Hello devs,
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
(some parts that are not related were cut)
Lastly, here’s the hierachy of the Bot Instance:

Any help is appreciated!!!
8 Likes
i don’t really know but it may be related to a precise angle that causes itself to be flung that badly
2 Likes
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
2 Likes
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)
2 Likes
I’m actually trying to make the tween faster if the distance of traveling is longer, not based on the distance to the player.
1 Like
Try doing something like this for moveKillbot
:
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
2 Likes
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
)
2 Likes
and remove the math.abs()
while you’re at it 
2 Likes
local TI = TweenInfo.new(
math.max(0.5, (sphere.Position - newPos).Magnitude / 50)
Enum.EasingStyle.Quad,
Enum.EasingDirection.InOut
)
2 Likes
It was just a joke
thank you though!
2 Likes