Better way to do 4 directional movement animations?

I’m currently developing my own movement system which uses 4 different animations depending on the movement direction relative to the camera (First Person). Here’s what i currently have in my Animate script:

local char = script.Parent
local humanoid : Humanoid = char:WaitForChild("Humanoid")
local animator : Animator = humanoid:WaitForChild("Animator")
local xFunc = require(game:GetService("ReplicatedFirst").xFunc)

local animations = {
	WalkFoward = animator:LoadAnimation(script.WalkFoward),
	WalkBackward = animator:LoadAnimation(script.WalkBackward),
	WalkLeft = animator:LoadAnimation(script.WalkLeft),
	WalkRight = animator:LoadAnimation(script.WalkRight),
	Idle = animator:LoadAnimation(script.Idle),
	Jump = animator:LoadAnimation(script.Jump)
}

animations.Idle:Play()

local function PlayOnce(animation, fadeTime)
	if not animation.IsPlaying then
		animation:Play(fadeTime)
	end
end

humanoid:GetPropertyChangedSignal("MoveDirection"):Connect(function()
	local dir = humanoid.MoveDirection
	if dir.Magnitude > 0 then
		animations.Idle:Stop()
	
		local ZDot = dir:Dot(char.HumanoidRootPart.CFrame.LookVector)
		ZDot = math.sign(xFunc.Round(ZDot, 3))
		
		local XDot = dir:Dot(char.HumanoidRootPart.CFrame.RightVector)
		XDot = math.sign(xFunc.Round(XDot, 3))
		
		print(ZDot, XDot)
		
		if ZDot == 0 then
			print("Side")
			
			animations.WalkFoward:AdjustWeight(0, 0.4)
			animations.WalkBackward:AdjustWeight(0, 0.4)
			
			PlayOnce(animations.WalkLeft, 0.4)
			PlayOnce(animations.WalkRight, 0.4)
			
			animations.WalkRight:AdjustWeight(XDot)
			animations.WalkLeft:AdjustWeight(-XDot)
		else
			animations.WalkLeft:AdjustWeight(0, 0.4)
			animations.WalkRight:AdjustWeight(0, 0.4)
			
			PlayOnce(animations.WalkFoward, 0.4)
			PlayOnce(animations.WalkBackward, 0.4)
			
			animations.WalkFoward:AdjustWeight(ZDot)
			animations.WalkBackward:AdjustWeight(-ZDot)
		end
	else
		animations.WalkFoward:AdjustWeight(0)
		animations.WalkBackward:AdjustWeight(0)
		animations.WalkLeft:AdjustWeight(0)
		animations.WalkRight:AdjustWeight(0)
		
		animations.Idle:Play()
	end
end)

here’s what it looks like in game (Normally you would be in first person but i set it to third for debugging);

It works fine until i start to rotate the camera while strafing to the left or right, which causes the animation to switch to a foward walking animation. Is there a better method or way of handling this?

2 Likes

I updated the script, but the same issue still persists

local char = script.Parent
local humanoid = char:WaitForChild("Humanoid")
local animator = humanoid:WaitForChild("Animator")
local camera = game.Workspace.CurrentCamera
local xFunc = require(game:GetService("ReplicatedFirst").xFunc)

local animations = {
    WalkForward = animator:LoadAnimation(script.WalkForward),
    WalkBackward = animator:LoadAnimation(script.WalkBackward),
    WalkLeft = animator:LoadAnimation(script.WalkLeft),
    WalkRight = animator:LoadAnimation(script.WalkRight),
    Idle = animator:LoadAnimation(script.Idle),
    Jump = animator:LoadAnimation(script.Jump)
}

animations.Idle:Play()

local function PlayOnce(animation, fadeTime)
    if not animation.IsPlaying then
        animation:Play(fadeTime)
    end
end

humanoid:GetPropertyChangedSignal("MoveDirection"):Connect(function()
    local dir = humanoid.MoveDirection
    if dir.Magnitude > 0 then
        animations.Idle:Stop()

        local cameraLookVector = camera.CFrame.LookVector
        local cameraRightVector = camera.CFrame.RightVector

        local ZDot = dir:Dot(cameraLookVector)
        ZDot = math.sign(xFunc.Round(ZDot, 3))

        local XDot = dir:Dot(cameraRightVector)
        XDot = math.sign(xFunc.Round(XDot, 3))

        print(ZDot, XDot)

        if ZDot == 0 then
            print("Side")

            animations.WalkForward:AdjustWeight(0, 0.4)
            animations.WalkBackward:AdjustWeight(0, 0.4)

            PlayOnce(animations.WalkLeft, 0.4)
            PlayOnce(animations.WalkRight, 0.4)

            animations.WalkRight:AdjustWeight(XDot)
            animations.WalkLeft:AdjustWeight(-XDot)
        else
            animations.WalkLeft:AdjustWeight(0, 0.4)
            animations.WalkRight:AdjustWeight(0, 0.4)

            PlayOnce(animations.WalkForward, 0.4)
            PlayOnce(animations.WalkBackward, 0.4)

            animations.WalkForward:AdjustWeight(ZDot)
            animations.WalkBackward:AdjustWeight(-ZDot)
        end
    else
        animations.WalkForward:AdjustWeight(0)
        animations.WalkBackward:AdjustWeight(0)
        animations.WalkLeft:AdjustWeight(0)
        animations.WalkRight:AdjustWeight(0)

        animations.Idle:Play()
    end
end)
1 Like

few tips:

  1. dont use “script.Parent” in local starter character scripts, better use
local char = game.Players.LocalPlayer.Character or game.Players.LocalPlayer.CharacterAdded:Wait()

but if script is server sided, then leave it stay
2. instead of

local humanoid : Humanoid = char:WaitForChild("Humanoid")

consider use:

local humanoid = char:FindFirstChildOfClass("Humanoid")

(char is reference to player character)

1 Like