Movement with the animation (HRP sticking to animation)

I’m trying to make a fighting game with moving animations without using VectorForces or other constraints. I’ve noticed that the animations can move every limb in the character except for the HumanoidRootPart. My goal is to make the HRP always stay with the character so that the character will always travel somehow.

I’ve tried experimenting with Motor6D and other weld constraints to make my expectations come true, but nothing worked. Then I tried thinking about using a reference dummy to play animations on and render it back to the player, but it was too complicated for me to apply it to Studio. Any suggestions?

I’d go with CFrame movement which is pretty much adjusting the HRP’s cframe each physics step based on whatever velocity or target position you want


here’s an example of one implementation I did with it:
Roblox Game Development - Example of CFrame Movement - YouTube

The Local Script used in StarterPlayerScripts
local Humanoid = script.Parent.Humanoid
local HumanoidRootPart = script.Parent.HumanoidRootPart

type AppliedVelocity = {velocity: CFrame | Vector3, endTime: number}
local appliedVelocities: AppliedVelocity = {} -- array of velocities to apply and the time to end them

-- add a velocity to the table to be handled
local function ApplyVelocity(velocity: CFrame, length: number)
	table.insert(
		appliedVelocities, {
			velocity = velocity,
			endTime = os.clock() + length,
		})
	print(string.format("{Time=[%.0f]}\tApplied [%s] for [%d] seconds", os.clock(), tostring(velocity), length))
end

-- setup the function to detect inputs to apply velocities
local function OnInputBegan(input, caughtByGui)
	if caughtByGui then return end

	if input.KeyCode == Enum.KeyCode.One then
		print(input.KeyCode)
		ApplyVelocity(Vector3.new(0, 0, 10), 2) -- 2 seconds of being pushed in the Z direction at 10 studs per second
	elseif input.KeyCode == Enum.KeyCode.Two then
		print(input.KeyCode)
		ApplyVelocity(Vector3.new(0, 10, 0), 1) -- 1 second of being pushed in the Y direction at 10 studs per second
	elseif input.KeyCode == Enum.KeyCode.Three then
		print(input.KeyCode)
		ApplyVelocity(Vector3.new(10, 0, 0), 3) -- 3 second of being pushed in the X direction at 10 studs per second
	elseif input.KeyCode == Enum.KeyCode.Four then
		print(input.KeyCode)
		ApplyVelocity(CFrame.new(0, 0, 10), 2) -- 2 second of being pushed in the Z direction at 10 studs per second in object space of the character. so it changes based on the direction the HRP faces
	elseif input.KeyCode == Enum.KeyCode.Five then
		print(input.KeyCode)
		ApplyVelocity(Vector3.new(0, 0, -50), .5) -- .5 seconds of being pushed in the Z direction at -50 studs per second
	end
end
game:GetService("UserInputService").InputBegan:Connect(OnInputBegan)

-- handle simulating the velocities each physics step
local function StepPhysics(dTime)
	local currentCFrame = HumanoidRootPart.CFrame
	local currentTime = os.clock()

	Humanoid.PlatformStand = ( #appliedVelocities > 0 ) -- set platform standing if we have velocities to apply. this will stop the user from doing things like preventing us from applying rotation
	HumanoidRootPart.Velocity = if ( #appliedVelocities > 0 ) then Vector3.new() else HumanoidRootPart.Velocity -- ignore roblox's velocities if we're applying velocity

	local index = 1
	while index <= #appliedVelocities do -- using while loop because length of table may change
		local appliedVelocity: AppliedVelocity = appliedVelocities[index]
		local velocity = appliedVelocity.velocity
		local endTime = appliedVelocity.endTime

		if endTime < currentTime then -- if appliedVelocity has expired, skip and remove
			table.remove(appliedVelocities, index)
		else -- else, apply the movement and increment the index
			if typeof(velocity) == "Vector3" then
				currentCFrame += ( Vector3.new():Lerp(velocity, dTime) ) -- pretty much (distance = velocity * time) e.g., if velocity is Vector3.new(0,0,4) and dTime is 0.5, this returns Vector3.new(0,0,2)
			else -- if cframe
				currentCFrame *= ( CFrame.new():Lerp(velocity, dTime) ) -- this does the same as Vector3, but it uses objectSpace instead of world space. you'll probably use this more doing knockback stuff
			end
			index += 1  
		end
	end

	-- apply all movements at the same time
	HumanoidRootPart.CFrame = currentCFrame
end
game:GetService("RunService").Heartbeat:Connect(StepPhysics)

This one pretty much just applies a velocity for N seconds on the character whenever the buttons 1,2,3 or 4 are pressed on the keyboard

It has the issues of:

  • not completely negating roblox’s velocities, so there’s going to be a constant downward velocity when applying velocities
    • this can be negated by applying an upward velocity
  • allowing characters to go through thin walls at high speeds
    • even roblox has this, so this is probably neglegible
  • default animations don’t play when platform standing
    • you’ll probably be playing custom animations, so the character won’t look like it’s not animated during this
2 Likes

Using CFrames is a good idea, but the animation that played in my video was moved from the Animation Editor with the lower torso. I want to make it so that the HRP would follow it. I’ll see what I can do with the code you sent.

Btw I think you meant StarterCharacterScripts :joy:

Hello! I’m sorry for bumping this, but have you figured out a way? I’m trying to make a vault animation, but the HRP moves outside the scope of the animation editor, so I can’t see the real time position of the character