How to make an AI that moves away from the player, but still looks at the player

When I try to lerp using the HumanoidRootPart’s CFrame, I get an error in the Output: “Unable to cast CoordinateFrame to float” Is there any workaround to this error, or does it not even matter?

That error probably means you put a cframe for alpha instead of a number

Try: humanoidRootPartCframe:lerp(LookAt, 0.5)

1 Like

Thanks! But it still isn’t as smooth as I would like it to be, as it doesn’t fix the fact that it doesn’t just rotate it, it moves it aswell. Any way to fix that? Here’s my updated code:

local LookAt = CFrame.lookAt(HumanoidRootPart.Position, Target.Position)
local Alpha = 0.5 -- idk what this should be, so im keeping it as 0.5 for now
local InterpolatedCFrame = HumanoidRootPart.CFrame:Lerp(LookAt, Alpha)
		
HumanoidRootPart.CFrame = InterpolatedCFrame
1 Like

If you want it to be smoother make alpha closer to 0.

As for the AI moving, cframe.lookat can tilt up or down to look at its target.

Here’s a workaround I made, someone might have a better solution:

local LookAt = CFrame.lookAlong(HumanoidRootPart.Position, (Target.Position - HumanoidRootPart.Position) * Vector3.new(1, 0, 1))

CFrame.lookAlong(at, direction) is equivalent to CFrame.lookAt(at, at + direction)

1 Like

Thanks for the code! But do you know why my AI’s movement gets butchered? For some reason, my AI walks fine without turning towards the player, but when I try to turn in towards the player, the movement looks more like teleportation/lag than actual character movement. I’ll attempt to send a video later, as currently Roblox is having issues loading it.

Sorry I went to bed after that, but you could try lerping instead I guess.

I think that’s because instead of the NPC walking in the normal orientation it’s supposed to we changed it. You could try also doing this client-sided if it looks a bit weird on the server. It may be smoother on the client.

Yeah, I’m currently trying to lerp it, yet it still is a little bit buggy for some reason, in the fact that it’s turning could be improved. This code is in a LocalScript, which means it runs on the client side I’m pretty sure. Here’s the current code I’m using, and a video of what I’m talking about too. (Sorry for the poor video quality, had to use Roblox’s recorder, but I think you would get the point)

local function RunAway()
	if Target ~= nil then
		local PositionDifference = Target.Position - HumanoidRootPart.Position 
		local NormalizedDirection = PositionDifference.Unit
		local LookAt = CFrame.lookAt(HumanoidRootPart.Position, Target.Position)
		local Alpha = 0.5
		local InterpolatedCFrame = HumanoidRootPart.CFrame:Lerp(LookAt, Alpha)
		
		Humanoid:MoveTo(HumanoidRootPart.Position + NormalizedDirection * -1 * RunDistance)
		
		HumanoidRootPart.CFrame = InterpolatedCFrame
	else
		return nil
	end
end

robloxapp-20240428-0858052.wmv (3.2 MB)

You could try to rotate the humanoidrootpart joint to the player.

I’m just curious, how would that work exactly? It might help me construct some code for it. (Unless you can give a quick example) Thank you! :slight_smile:

The RootJoint has these 2 properties called C0 and C1 they are CFrames and you can just use CFrame.lookat()
image
Example Video:


Dont mind the background i made this video in one of my projects :/.

When lerping you can use a for loop to make the transition smoother:

for i = 0, 1, .1 do -- third value is the transition, making it lower will make it smoother
workspace.Part.CFrame = CFrame:Lerp(CFrame.new(part.CFrame, part2.CFrame), i)-- putting two values in a cframe will make the first value look at the second value
end

You could also lerp in a heartbeat.Renderstepped event to make it even smoother.

Thanks to both of you! Just for the lerping, if I’m using a Runservice.Renderstepped function, does that mean I have to use the for i loop in that too? If not, what would i be instead when lerping?

Yep, just the exact same thing just within an event connected to a function, and once it’s done you can disconnect the event just for optimization purposes.

I got an error in the output for some reason. “invalid argument #1 to ‘new’ (Vector3 expected, got CFrame)” What does that mean, and what is the solution to it?

Oh by using the code I gave you? I think its because it wants a vector3 instead of a cframe. My mistake:

for i = 0, 1, .1 do
	task.wait()
	workspace.Part.CFrame = workspace.Part.CFrame:Lerp(CFrame.lookAt(workspace.Part.Position, workspace.Part2.Position), i)
end

the other version would’ve worked just was deprecated and I didn’t expect it to work but use the above code not this one, this is just the mistake that I made earlier that I fixed now:

for i = 0, 1, .1 do -- third value is the transition, making it lower will make it smoother
workspace.Part.CFrame = workspace.Part.CFrame:Lerp(CFrame.new(part.Position part2.Position), i)-- putting two values in a cframe will make the first value look at the second value
end
1 Like

Actually scratch this idea, what you could try to use is pathfindingservice. Once you learn it, in the for loop of waypoints you can do the CFrame.lookat() stuff. (dont worry if you don’t understand what waypoints are, once you use pathfindingservice and learn about it you will know). Also I recommend learning it because if theere’s an obstacle iin the way between the destination and the rig, the rig will be able to avoid it.

for i, waypoint in waypoints do
char.HumanoidRootPart.CFrame = CFrame.LookAt(script.Parent.HumanoidRootPart.Position, workspace.Part2.Position)
righuman:MoveTo(waypoint.Position)
righuman.MoveToFinished:Wait()
end

Thanks for the idea! I think I’ll just use the one above though, because it kinda works more with my script lol. I’ll definitely learn Pathfinding, as it sounds useful :slight_smile:

Alright that’s fine. Good luck hope it works.

Thank you! The code actually worked! I just had to tweak a few things to adjust with my game. Can you paste this code so I can mark it as a solution? Thanks to everyone else who helped me as well :smile: I always appreciate it!

local function RunAway()
	if Target ~= nil then
		Humanoid.AutoRotate = false
		
		local PositionDifference = (Target.Position - HumanoidRootPart.Position) 
		local NormalizedDirection = PositionDifference.Unit
		
		Humanoid:MoveTo(HumanoidRootPart.Position + NormalizedDirection * -1 * RunDistance)
		
		for i = 0, 1, 0.01 do
			task.wait()
			HumanoidRootPart.CFrame = HumanoidRootPart.CFrame:Lerp(CFrame.lookAt(HumanoidRootPart.Position, Target.Position), i)
		end
	else
		return nil
	end
end