Is there anyway to avoid this much if statements?

Hi,

I am trying to optimize my relative walking script and I need to make sure if this much if statements are necessary

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")

local ExtraFunctions = require(ReplicatedStorage.Modules.ExtraFunctions)
local MathAddons = require(ReplicatedStorage.Modules.MathAddons)

local LocalPlayer = Players.LocalPlayer
if not LocalPlayer then
	Players:GetPropertyChangedSignal("LocalPlayer"):Wait()
	LocalPlayer = Players.LocalPlayer
end

local PlayerScripts = ExtraFunctions:WaitForChildWhichIsA(LocalPlayer, "PlayerScripts") :: PlayerScripts
local PlayerModule = require(PlayerScripts:WaitForChild("PlayerModule")) :: any

local Controls = PlayerModule:GetControls()

local Humanoid: Humanoid?
local Character = LocalPlayer.Character or LocalPlayer.CharacterAdded:Wait()
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")

local PlayerAnimations = ReplicatedStorage.Animations.PlayerAnimations

local Character = LocalPlayer.Character or LocalPlayer.CharacterAdded:Wait()
local Humanoid = Character:WaitForChild("Humanoid")
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")
local Camera = workspace.CurrentCamera

-- Important Tables

local Directions = {
	[Vector3.new(0, 0, 0)] = "Not Moving";
	[Vector3.new(0, 0, -1)] = "Foward";
	[Vector3.new(0, 0, 1)] = "Backward";
	[Vector3.new(-1, 0, 0)] = "Left";
	[Vector3.new(1, 0, 0)] = "Right";
	[Vector3.new(-1, 0, -1)] = "FowardLeft";
	[Vector3.new(1, 0, -1)] = "FowardRight";
	[Vector3.new(-1, 0, 1)] = "BackwardLeft";
	[Vector3.new(1, 0, 1)] = "BackwardRight";
}

local animTable = {}

local animNames = { -- i havent made the animations yet
	-- walking stuff
	back = { 
		{id = "rbxassetid://12630387784", weight = 10}
	};
	front = { 
		{id = "rbxassetid://12630387784", weight = 10}
	};
	left = { 
		{id = "rbxassetid://12630387784", weight = 10}
	};
	right = { 
		{id = "rbxassetid://12630387784", weight = 10}
	};
	backLeft = { 
		{id = "rbxassetid://12630387784", weight = 10}
	};
	backRight = { 
		{id = "rbxassetid://12630387784", weight = 10}
	};
	frontLeft = { 
		{id = "rbxassetid://12630387784", weight = 10}
	};
	frontRight = { 
		{id = "rbxassetid://12630387784", weight = 10}
	};
	-- idle
	idle = 	{	
		{ id = "http://www.roblox.com/asset/?id=180435571", weight = 9 },
		{ id = "http://www.roblox.com/asset/?id=180435792", weight = 1 }
	},
	
}

-- Declarations
local currentAnim = ""
local currentAnimInstance = nil
local currentAnimTrack
-- Functions


function configureAnimationSet(name, fileList) -- forked from roblox animate
	if (animTable[name] ~= nil) then
		for _, connection in pairs(animTable[name].connections) do
			connection:disconnect()
		end
	end
	animTable[name] = {}
	animTable[name].count = 0
	animTable[name].totalWeight = 0	
	animTable[name].connections = {}

	-- check for config values
	local config = script:FindFirstChild(name)
	if (config ~= nil) then
		print("Loading anims " .. name)
		table.insert(animTable[name].connections, config.ChildAdded:connect(function(child) configureAnimationSet(name, fileList) end))
		table.insert(animTable[name].connections, config.ChildRemoved:connect(function(child) configureAnimationSet(name, fileList) end))
		local idx = 1
		for _, childPart in pairs(config:GetChildren()) do
			if (childPart:IsA("Animation")) then
				table.insert(animTable[name].connections, childPart.Changed:connect(function(property) configureAnimationSet(name, fileList) end))
				animTable[name][idx] = {}
				animTable[name][idx].anim = childPart
				local weightObject = childPart:FindFirstChild("Weight")
				if (weightObject == nil) then
					animTable[name][idx].weight = 1
				else
					animTable[name][idx].weight = weightObject.Value
				end
				animTable[name].count = animTable[name].count + 1
				animTable[name].totalWeight = animTable[name].totalWeight + animTable[name][idx].weight
							print(name .. " [" .. idx .. "] " .. animTable[name][idx].anim.AnimationId .. " (" .. animTable[name][idx].weight .. ")")
				idx = idx + 1
			end
		end
	end

	-- fallback to defaults
	if (animTable[name].count <= 0) then
		for idx, anim in pairs(fileList) do
			animTable[name][idx] = {}
			animTable[name][idx].anim = Instance.new("Animation")
			animTable[name][idx].anim.Name = name
			animTable[name][idx].anim.AnimationId = anim.id
			animTable[name][idx].weight = anim.weight
			animTable[name].count = animTable[name].count + 1
			animTable[name].totalWeight = animTable[name].totalWeight + anim.weight
		end
	end
end

for name, fileList in pairs(animNames) do 
	configureAnimationSet(name, fileList)
end	


local function ThumbstickCurve(X: number): number
	local K_CURVATURE = 2.0
	local K_DEADZONE = 0.15

	local function FCurve(X: number): number
		return (math.exp(K_CURVATURE * X) - 1) / (math.exp(K_CURVATURE) - 1)
	end

	local function FDeadzone(X: number): number
		return FCurve((X - K_DEADZONE) / (1 - K_DEADZONE))
	end

	return math.sign(X) * math.clamp(FDeadzone(math.abs(X)), 0, 1)
end

function playAnimation(animName, humanoid) 
	print(animTable)
	print(animTable[animName])
	local roll = math.random(1, animTable[animName].totalWeight) 
	local origRoll = roll
	local idx = 1
	while (roll > animTable[animName][idx].weight) do
		roll = roll - animTable[animName][idx].weight
		idx = idx + 1
	end
	
	local anim = animTable[animName][idx].anim

	-- switch animation		
	if (anim ~= currentAnimInstance) then

		if (currentAnimTrack ~= nil) then
			currentAnimTrack:Stop(0.0)
			currentAnimTrack:Destroy()
		end

		-- load it to the humanoid; get AnimationTrack
		currentAnimTrack = humanoid:LoadAnimation(anim)
		currentAnimTrack.Priority = Enum.AnimationPriority.Core

		-- play the animation
		currentAnimTrack:Play(0.0)
		currentAnim = animName
		currentAnimInstance = anim
	end
end

-----------------
local Pose = "Standing"

local function onRun(Speed)
	local MoveVector = Controls:GetMoveVector()
	
	MoveVector = Vector3.new(
		math.round(ThumbstickCurve(MoveVector.X)),
		math.round(ThumbstickCurve(MoveVector.Y)),
		math.round(ThumbstickCurve(MoveVector.Z))
	)
	
	local NewSpeed = math.round(Speed)
	local ChangedAnimation = false

	if Directions[MoveVector] == "Foward" then
		if Pose ~= "WalkingFoward" then
			Pose = "WalkingFoward"
			print(Directions[MoveVector])
			playAnimation("foward",Humanoid)
		end
	end
	
	if Directions[MoveVector] == "Backward" then
		if Pose ~= "WalkingBackward" then
			Pose = "WalkingBackward"
			print(Directions[MoveVector])
			playAnimation("back",Humanoid)
		end
	end
	
	if Directions[MoveVector] == "Right" then
		if Pose ~= "WalkingRight" then
			Pose = "WalkingRight"
			print(Directions[MoveVector])
			playAnimation("right",Humanoid)
		end
	end
	
	if Directions[MoveVector] == "Left" then
		if Pose ~= "WalkingLeft" then
			Pose = "WalkingLeft"
			print(Directions[MoveVector])
			playAnimation("left",Humanoid)
		end
	end
	
	if Directions[MoveVector] == "FowardLeft" then
		if Pose ~= "WalkingFrontLeft" then
			Pose = "WalkingFrontLeft"
			print(Directions[MoveVector])
			playAnimation("frontleft",Humanoid)
		end 
	end
	
	if Directions[MoveVector] == "FowardRight" then
		if Pose ~= "WalkingFrontRight" then
			Pose = "WalkingFrontRight"
			print(Directions[MoveVector])
			playAnimation("frontright",Humanoid)
		end 
	end
	
	if Directions[MoveVector] == "BackwardLeft" then
		if Pose ~= "WalkingBackwardLeft" then
			Pose = "WalkingBackwardLeft"
			print(Directions[MoveVector])
			playAnimation("backleft",Humanoid)
		end 
	end
	
	if Directions[MoveVector] == "BackwardRight" then
		if Pose ~= "WalkingBackwardRight" then
			Pose = "WalkingBackwardRight"
			print(Directions[MoveVector])
			playAnimation("backright",Humanoid)
		end 
	end
end

-- Connections
Humanoid.Running:Connect(onRun)

I can’t really help you with the if statements problem right now, but check your spelling for ‘forward’. Just wanted to point that out as that spelling mistake might cause errors later.

You can avoid If-Statements by connecting If’s with logical operators like and/or/not

In the part with the Directions you can avoid some If-Statements by changing

	if Directions[MoveVector] == "Foward" then
		if Pose ~= "WalkingFoward" then
			Pose = "WalkingFoward"
			print(Directions[MoveVector])
			playAnimation("foward",Humanoid)
		end
	end

to this

	if Directions[MoveVector] == "Foward" and Pose ~= "WalkingFoward" then
		Pose = "WalkingFoward"
		print(Directions[MoveVector])
		playAnimation("foward",Humanoid)
	end

also, while you maybe can’t avoid If-Statements with it, you can avoid nesting (many If’s in each other) by returning with the opposite of the If-Statement.

From:

	if (animTable[name] ~= nil) then -- If this isn't nil its true 
		for _, connection in pairs(animTable[name].connections) do
			connection:disconnect()
		end
	end
   -- rest of code continues here

To:

if (animTable[name] == nil) then return end -- If animTable[name] has no value (nil) it will return else it will continue
-- Same thing: if not animTable[name] then return end
for _, connection in pairs(animTable[name].connections) do
	connection:disconnect()
end
--rest of the code continues here

So if animTable[name] == nil the function will end right there because it returns from it.
I’m not sure if you can use that for your example because in that function you also check for a config value, basically if there can’t be a config value if animTable[name] == nil then you can use it. This also makes the code more secure because there can’t be unexpected nils or errors.

1 Like

You could always use a loop.

First, make a table like so and put all your directions in it.

local possibleDirectionTable = {"BackwardRight", "BackwardLeft", "FowardRight"} 

and so on.

Next, loop through this table.

for _, possibleDirection in pairs(possibleDirectionTable) do
if Directions[MoveVector] == possibleDirection and Pose ~= "Walking"..possibleDirection then
Pose = "Walking"..possibleDirection
playAnimation(possibleDirection, Humanoid)
break
end
end

Remember to change the names of the animations in your animation table accordingly.
No idea why it doesn’t format properly.

1 Like

Thi may be a little offtopic, but you should try not to Nester your code, Here is a video of what i meant by that.
Why You Shouldn’t Nest Your Code - YouTube

1 Like

Well for starters this:

if (weightObject == nil) then
	animTable[name][idx].weight = 1
else
	animTable[name][idx].weight = weightObject.Value
end

Could be simplified to:

animTable[name][idx].weight = if weightObject then weightObject.Value else 1

What about this?

if not animTable[name] then return end

This would be the most organized.