Moving humanoid to certain tiles, in a certain path, and detecting it

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? Keep it simple and clear!
    I have several tiles in the Workspace, and each of them have a different name so they can be detected individually. Each time a player clicks on a tile that is theirs and meets requirements (for now none) they are able to spawn in a unit to select and move around. I’ve made a ray that detected the tiles in order, from the start tile of where the unit is standing to the end tile where the player wants the unit to go. However, I don’t know how I can make the game move that unit to that desired tile without running into while loop problems. I don’t know how I would make the unit move to the desired tile and not waste resources constantly checking if the humanoid MoveDirection is at 0, for example, in a big loop, which also crashes and becomes infinite when the player selects again. My idea was to make a for loop for the length of the table of tiles intercepted by the ray, but it would have to skip over several times reaching the end prematurely before the unit hits the end tile. Any ideas?

Edit: So, I want a player to be able to click on the desired tile for the unit to go to, the unit performs the movement, going from tile to tile in the zigzag kind of pattern hex to hex movement performs. Is there any way to perform all this without having a highly resource-intensive while loop checking if the humanoid of the unit stopped moving, and then performing the movement again until it reaches the end tile? Is there a better method? Anything at all?

  1. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    My own mostly, but I’ve stumbled at a wall.
1 Like

Can you post a picture of your environment? It sounds like you have a path finding problem but I have no idea what you’re referring to when you reference “tiles” or “units”, and I’m further confused by our ‘while loop’ issues. It would also help if you further explain how the user is selecting the last tile, are they just clicking on the desired goal tile, or are they selecting several tiles? I ask this as you mention using a ray to determine the path?

Regardless, as I currently understand your problem: if you’re attempting to pathfind on a grid, use the A* algorithm to determine the waypoints of the path, iterate through these and move the humanoid accordingly using the :MoveTo() method of the Humanoid.

Here’s what exists for now regarding environment:
https://gyazo.com/0884534017ba400d70446c02c443ef14

My pathing method is casting a ray from start hex to the end hex (with all in between added to a ignore list that’s also used for the pathing itself), then connected by iterating through it and doing the :MoveTo method. However, again, I have to check when it’s done so there is still a very resource-intensive while loop, as I have to also change a value inside the unit that tells the server its position. It’s a way of not relying on the player to give that kind of information.

The player selects the unit and right clicks on the desired hex. They do not have to select multiple tiles. I didn’t use A* because I didn’t see that it was necessary with this method as the ray hit a path that is pretty accurate to the desired path (and there will still be checks for which is closer depending on certain tiles) so it was unnecessary, to me at least, to use those extra resources checking around for the ‘correct’ path when it’s pretty much already given.

Does the terrain always remain flat? If so, I don’t understand why you have to cast a ray between the start and end point unless you want to detect if an enemy/opposing unit is in its path? Otherwise you could just do :MoveTo() and then wait until it’s within x distance of its goal position

If it doesn’t, or if there could be obstacles, then a pathfinding solution is necessary

It’ll remain flat, but the ray is for also knowing the intersecting hex. I don’t want to move the unit and have it ignore that is still a hex grid. I want it to act like it’s on a hex grid, again, having that kind of zigzagging pattern hex grids do.

Edit: And yes, the ray could also be for that as well. That was one of the plans.

I’m assuming the ray function you have provides you with a list of Vec3 or a list of Hexagons to travel to?

If so, just iterate between each one, use :MoveTo() and use .MoveToFinished before stepping to the next iteration. If you’re concerned with ‘running constant checks’ as you previously mentioned, I would just use linear interpolation to move the ‘unit’ from A => n => B e.g.

local LERP_STEP = 0.01
for _, point in next, IterablePath do
	local start = Unit.PrimaryPart.CFrame
	for i = 0, 1, LERP_STEP do
		Unit:SetPrimaryPartCFrame(
			start:lerp(CFrame.new(point), i)
		)
	end
end
1 Like

Oh I wasn’t aware there was a .MoveToFinished event. That helps a lot. And yea, it does provide Vec3 positions of each hex intercepted. I was hoping not to use lerp, though.

I have had issues with this previously though, and instead chose to just recursively check for < x magnitude between the NPC and the goal. It’s not that computationally expensive, although I suppose that depends on how many ‘units’ you’re intending to have

That’s actually exactly what I intended on doing, but I still ran in to problems. Such as the checks in case a player selects a new path while it’s in process, and going infinite for some reason and crashing.

It would be nice if you were able to provide your pathfinding code, so we can further debug your problem.

I’m going to try something different before I do, because I have a little more info to work off of. Otherwise, I would.

Ah I see, I didn’t realise this was your issue. Just check if the final goal has been changed, and if you need to break the current cycle e.g.

local REG_DISTANCE = 3 -- distance between char-point that you're willing to accept that the obj has reached that point
local states = {
	running  = false;
	reset    = false;
	lastGoal = nil;
	startPos = nil;
}

local function findPath(unit, goal)
	if goal == states.lastGoal then
		return
	end
	spawn(function ()
		if states.running then
			states.reset = true
			repeat wait() until not states.reset
		end
		
		local path = YourPathFunction(goal)
		if path then
			states.startPos = unit.PrimaryPart.CFrame.p
			states.lastGoal = goal
			
			local lastPoint = states.startPos
			while i <= #path and wait() and not states.reset do
				local point = path[i]
				if lastPoint ~= point then
					unit.Humanoid:MoveTo(point)
				end
				if (unit.PrimaryPart.Position - point).magnitude < REG_DISTANCE then
					i = i + 1
				end
			end
		end
	end)
end
1 Like

I didn’t even think of using spawn(). Thank you!

No worries, hope this provides you with the final solution - if not, feel free to post here / DM me.

1 Like