Hello, all.
I’ve been taking a shot at making an RTS style game in Roblox. My most recent roadblock has been managing the movement of units across pathfinding nodes.
I’ve attached a video that attempts to demonstrate the current issues I have. The two biggest things that bother me are:
-
At times the tank will just stop moving on the server side, while on the client side the tank keeps moving. Sometimes the tank will correct itself after a few seconds, but most of the time the tank remains still while the locally-rendered tank goes off into nowhere; and
-
There appears to be an error that occurs while indexing the list of waypoints. This is most likely caused by giving the unit a new “Move” command before it has reached its original goal. This was what I was originally trying to fix before the aforementioned issue appeared, and I decided to take this up with the forum to make sure my attempt at an RTS isn’t doomed.
I am confident that both these issues are being caused by a fault in my pathfinding code: specifically the way I handle waypoints. Here is all the code that deals with waypoints:
local GoTo = Function.new("GoTo", function(location, target, usePathfinder)
-- print("GoTo") --DEBUG
--Stop the unit's current movement (if any)
--unitFolder:WaitForChild("Halt"):Invoke()
--Get the unit's position, as well as the objects used to move and turn the unit
local DISTANCE_THRESHOLD = Model.Value:GetExtentsSize().Y / 2 + 0.2
local unitPosition = Model.Value.PrimaryPart.Position
local velocityObject = Model.Value.BodyKit.UnitPart.BodyVelocity
local gyroObject = Model.Value.BodyKit.UnitPart.BodyGyro
if usePathfinder == true then
pathSuccess, waypoints = Pathfinder:CreatePath(unitPosition, location)
-- print(pathSuccess, waypoints) --DEBUG
-- print(#waypoints) --DEBUG
NodeDebugger:ClearAllNodes() --DEBUG
if pathSuccess == true and #waypoints > 0 then
for waypoint = 1, #waypoints do
NodeDebugger:AddNode(waypoints[waypoint]) --DEBUG
end
waypointIndex = 1 --We're skipping the first waypoint, as it's where the unit already is.
--Move to first waypoint
local distance = math.huge
local previousDistance = math.huge
while waypointIndex <= #waypoints and waypoints[waypointIndex] do
NodeDebugger:HighlightNode(waypoints[waypointIndex]) --DEBUG
velocityObject.Velocity = (waypoints[waypointIndex] - Model.Value.PrimaryPart.Position).Unit * Speed.Value
gyroObject.CFrame = CFrame.new(Model.Value.PrimaryPart.Position, waypoints[waypointIndex])
repeat
--print(waypoints[waypointIndex], " ", Model.Value.PrimaryPart.Position) --DEBUG
distance = (waypoints[waypointIndex] - Model.Value.PrimaryPart.Position).magnitude
--print(distance - previousDistance) --DEBUG
--if (distance - previousDistance) > 1 then
--print("Recalibrating") --DEBUG
velocityObject.Velocity = (waypoints[waypointIndex] - Model.Value.PrimaryPart.Position).Unit * Speed.Value
gyroObject.CFrame = CFrame.new(Model.Value.PrimaryPart.Position, waypoints[waypointIndex])
--end
previousDistance = distance
wait()
until distance <= DISTANCE_THRESHOLD
unitFolder:WaitForChild("WaypointReached"):Fire()
waypointIndex = waypointIndex + 1
end
--Stop the unit
--velocityObject.Velocity = Vector3.new()
unitFolder.Halt:Invoke()
else
--Here we will send a message to the commander, informing him / her of our failure to find a path.
end
--Stop the unit
--velocityObject.Velocity = Vector3.new()
else
--This is an easy case: we just move the unit in a straight line to the location / target.
velocityObject.Velocity = (location - Model.Value.PrimaryPart.Position).Unit * Speed.Value
gyroObject.CFrame = CFrame.new(Model.Value.PrimaryPart.Position, location)
end
end, unitFolder)
--Halt
local Halt = Function.new("Halt", function()
--Clear the pathfinding data
waypoints = {}
waypointIndex = 0
--Stop the unit
--print("Stopping unit") --DEBUG
local velocityObject = Model.Value.BodyKit.UnitPart.BodyVelocity
velocityObject.Velocity = Vector3.new()
end, unitFolder)
Finally, allow me to make some things very clear:
-
I am using a custom Pathfinding module in ServerStorage. All the pathfinding in-game is handled by the server;
-
You may have some questions as to why I use a “Function” class instead of just creating a normal function. Don’t worry about that. It’s not going to change, and it’s not relevant to the issue at hand;
-
There is a part of the pathfinding function that handles a case where the caller just wants to move in a straight line towards the goal. That section is incomplete. What’s being used in this video is the “usePathfinder == true” scenario.
-
Yes, I am aware that the tank shoots itself into the sky when it bumps into a wall. I am also aware that the tank drives upside-down at one point in the video. Believe it or not, these have no effect on the unit’s pathfinding. The code only examines the unit’s distance from the node on the X and Z axes, so however high the hover tank flies or how strange it is oriented has no real effect on waypoints (and I’m going to take care of it);
-
I don’t want feedback on the lack of textures. I don’t want feedback on the tanks’ design. I don’t want feedback on the UI. I just want assistance on the issues I’ve already mentioned. If you have no thoughts on what could be going on, I politely ask that you move on. I’m not trying to be rude: I just don’t like cluttered threads.
Any help with this issue would be greatly appreciated.