Today when I’m trying to write a Killbot AI (if you don’t know what is Killbot it is just a classic NPC or robot, details here), I found out the bot could sometimes, for unknown reason, reach an extremely high velocity, here’s a video for reference:
(skip to 0:10 if you like)
Here’s the movement AI script:
function fire(target)
local dir = target - sphere.Position
dir = computeDirection(dir)
local missile = Rocket:clone()
local spawnPos = sphere.Position
local pos = spawnPos + (dir * 5)
--missile.Position = pos
missile.CFrame = CFrame.new(pos, pos + dir)
missile.RocketScript.Disabled = false
missile.Parent = game.Workspace
missile:SetNetworkOwner(nil)
end
function computeDirection(vec)
local lenSquared = vec.magnitude * vec.magnitude
local invSqrt = 1 / math.sqrt(lenSquared)
return Vector3.new(vec.x * invSqrt, vec.y * invSqrt, vec.z * invSqrt)
end
function scanForHumans()
local humansFound = {}
local players = game.Players:children()
if (#players < 1) then return end
myTarget = players[math.random(1, #players)].Character
end
function moveKillbot()
warn("move")
local x = math.random(-30,30)
local y = math.random(-8,8)
local z = math.random(-30,30)
local newPos = Vector3.new(sphere.Position.X+x,sphere.Position.Y+y,sphere.Position.Z+z)
local TI = TweenInfo.new(
math.abs((sphere.Position-newPos).Magnitude)/10,
Enum.EasingStyle.Quad,
Enum.EasingDirection.InOut
)
local result = workspace:Raycast(sphere.Position, newPos - sphere.Position)
if result and (result.Instance and math.abs((sphere.Position-newPos).Magnitude) > result.Distance) then
task.wait(1)
moveKillbot()
return
end
local tween = TS:Create(sphere,TI,{Position = newPos})
tween:Play()
tween.Completed:Connect(function() tween:Destroy() end)
end
task.spawn(function()
while task.wait() do
if myTarget ~= nil then
sphere.CFrame = CFrame.lookAt(sphere.Position, myTarget.PrimaryPart.Position)
print(sphere.CFrame)
end
end
end)
while true do -- loop forever
scanForHumans()
if myTarget then
fire(myTarget.PrimaryPart.Position)
wait(math.random(2,3))
moveKillbot()
end
task.wait(0.03)
end
Well I believe the problem most likely might stem from the computeDirection function, specifically this part, here:
local lenSquared = vec.magnitude * vec.magnitude
local invSqrt = 1 / math.sqrt(lenSquared)
This can cause high values IF the vector vec has a very very small magnitude (basically, as close to zero as possible) That would lead to a large velocity when applying the direction.
I think you should add a check to ensure the vector’s magnitude isn’t too small before going any further
I’m pretty sure the issue is actually that you are making the tween faster based on the distance to the player.
Because you also randomly select position values every frame within the range (-30, 30). (another issue i see)
Imagine that the player is really close, and then the bot instantly tries to move 30 studs away because you have made the tween faster based on the distance to the player.
Usually the way this is done is with a cooldown. The killbot will select a direction to move, and then wait to select a new direction, and directions should be normalized vectors. (so your movement tweens are consistent)
local Random = Random.new(math.random(2147483647))
local MovementDirection = Random:NextUnitVector()
local ChangeDirectionCooldown = 0
local Epoch = tick()
function moveKillbot()
warn("move")
if tick() - Epoch > ChangeDirectionCooldown then
MovementDirection = Random:NextUnitVector()
ChangeDirectionCooldown = math.random(3)
Epoch = tick()
end
local newPos = sphere.Position + MovementDirection
local toNewPos = newPos - sphere.Position
if workspace:Raycast(sphere.Position, toNewPos) then -- The ray will only go as far as the toNewPos vector's magnitude
MovementDirection = Random:NextUnitVector()
return
end
local TI = TweenInfo.new(
0.1,
Enum.EasingStyle.Linear
)
local tween = TS:Create(sphere, TI, {Position = newPos})
tween:Play()
tween.Completed:Wait()
end
This makes it so the bot is always moving with a consistent velocity
Also, I should mention that the tween should not complete faster based on the distance. The tween wil already look faster because it takes the same amount of time to travel more distance. But when you are using direction vectors instead, this is negligible
Right now, in your moveKillbot function, you’re calculating the tween duration based on the distance to the new position divided by 10, which makes the bot move at a constant speed. To make the bot move faster for longer distances, you can tweak that calculation.
Instead of dividing by 10, you could scale the duration based on the distance, like this: math.abs((sphere.Position - newPos).Magnitude) / 50. This will make the bot move faster as the distance increases. You can adjust the 50 value to control the speed, and add a math.max(0.5, ...) to make sure the bot doesn’t move too fast for shorter distances. This will keep the bot moving at a reasonable speed even for small distances.
Also, in your scanForHumans function, you’re picking a random player to target. That’s fine, but if you want a more precise targeting system, we could tweak it further, though that’s not part of your movement issue.
Try changing your tween’s duration calculation to something like this:
local TI = TweenInfo.new(
math.max(0.5, math.abs((sphere.Position - newPos).Magnitude) / 50), -- Duration now increases with distance
Enum.EasingStyle.Quad,
Enum.EasingDirection.InOut
)