Realistic NPC movement

I’m making a game and I want the npcs to simulate how actual players move for a cutscene, so like jittery, and quick.

Heres a good example i found of it.

How could i do something like this?

also heres the game if you guys need it ( ✦ ) Nightmare - Roblox

5 Likes

What’s the song that plays in the clip?

1 Like

Do it yourself and record the CFrames of your character

7 Likes

its just pathways set up i believe or random directions picked

3 Likes

My plan was to record the cframes of my character and I did but I just don’t know how I could make it look like the players actually walking

I’m stuck with this

readyEvent.OnServerEvent:Connect(function ()

	for i, cframe in  cframeData.JimData do
		jimNPC.PrimaryPart.CFrame = cframe
		task.wait(0.1)
	end
end)

the cframeData is the table of cframe data btw

ALSO

i tried using hum:MoveTo but it just didn’t look great.

What do i do from here?

EDIT:

While thinking about my last script, I realized this is likely a more efficient and accurate way to collect the movement data:

-- recording phase
local movedata = {};
local player = game.Players:WaitForChild('devmaxcat')

while not player.Character do wait() end
local last = nil;
local conn = player.Character:WaitForChild("Humanoid"):GetPropertyChangedSignal('MoveDirection'):Connect(function(moveDirection)
	last = last or tick()
	local t = tick() - last
	table.insert(movedata, {
		direction = player.Character.Humanoid.MoveDirection,
		duration = t
	})
	last = tick()
end)

task.wait(3) -- record for 3 seconds

-- playback phase
conn:Disconnect()
table.insert(movedata, {
	direction = Vector3.new(0,0,0),
	duration = 0
})

for i in pairs(movedata) do
	game.Workspace.Rig.Humanoid:Move(movedata[i].direction) 
	task.wait(movedata[i].duration)
end

I did some experimentation and this setup produced fairly decent results. I imagine it can be improved, since a task.wait is involved in the playback. If you need predetermined movement, you’ll need to get out the movedata array into something static and re-usuable.

Previous Code
-- recording phase
local movedata = {};
local player = game.Players:WaitForChild('devmaxcat')
local t = 0
local conn = game:GetService('RunService').Heartbeat:Connect(function(dt)
	t += dt -- measures the duration of the movement
	if not player.Character then return end
	local moveDirection = player.Character.Humanoid.MoveDirection
	if moveDirection ~= movedata[math.max(#movedata - 1, 1)] then
		table.insert(movedata, {
			direction = moveDirection,
			duration = t
		})
		t = 0 -- we recorded the movement, so lets start recording the next movements duration
	end
end)

task.wait(3) -- record for 3 seconds

-- playback phase
conn:Disconnect()

for i in pairs(movedata) do
	game.Workspace.Rig.Humanoid:Move(movedata[i].direction) 
	task.wait(movedata[i].duration)
end
3 Likes

I made a small experiment recording the CFrame every single frame.

The movement is pretty accurate, however… since I’m saving the CFrame every frame, the recording table is made out of 700 CFrames only for 5 seconds of “animation”, which cannot not be good.

But either way you can see how would it look this way.

1 Like