Priority-based StateMachine for Humanoids or any other types of Instances [Priority3]

updated this post to keep it up with the updates

Priority3


This module is made to eliminate issues like: running while crouching or dashing while being stunned by using priority based states.

you can use this module to easily add states with priorities to objects and have full control over them

Listen!


Changing states in client scripts will not update them on the server

Download


Roblox marketplace

Github

Adding States


Method1

This method is just a quick way of adding States to every Statemachine created by the Module

Method2

Use this method if you want to add specific states to some of the classes

-----------// Server Script//-----------

-- Module
local Priority3 = require(...) -- require the module

-- State Configs
local stateConfig1 = Priority3.CreateStateConfig({
	Name = "Walking",
	Priority = 1,
	Priorities = {
		WalkSpeed = 16,
		JumpPower = 50,
	}
})

-- Variables
local character = ... -- get character
local humanoid = character:WaitForChild("Humanoid") -- Get humanoid
local class = Priority3.GetClass(humanoid) -- Get/Create Statemachine for Humanoid

-- Adding States
class:AddState(stateConfig1)
Method3

The difference between this method and the second method is that you have more control over the properties changing

-----------// Server Script//-----------

-- Module
local Priority3 = require(...) -- require the module

-- State Configs
local stateConfig1 = Priority3.CreateStateConfig({
	Name = "Walking",
	Priority = 1,
})

-- Variables
local character = ... -- get character
local humanoid = character:WaitForChild("Humanoid") -- Get humanoid
local class = Priority3.GetClass(humanoid) -- Get/Create Statemachine for Humanoid

-- Adding States
class:AddState(stateConfig1)

class:ListenToChange(stateConfig1.Name):Connect(function(enabled, active)
   if active then
      -- You can use TweenService for this if you want!
      humanoid.WalkSpeed = 16
      humanoid.JumpPower = 50
   end
end)

Example Script


-----------// Toggle Sprint (server) //-----------

local remote = ...

remote.OnServerEvent:Connect(function(player, enable)
   local humanoid = player.Character:WaitForChild("Humanoid")
   local class = Priority3.GetClass(humanoid)

   class:SetEnabled("Running", enable)
end)
-----------// Toggle Sprint (client) //-----------

local remote = ...

local character = ...
local humanoid = character:WaitForChild("Humanoid")
local class = Priority3.GetClass(humanoid)

local function ToggleSprint()
   local enable = not class.States.Running.Enabled

   -- To make sprinting intuitive for Players with bad internet
   -- we will first toggle sprint on the Client and
   -- then we will use RemoteEvent to do it on the Server
   class:SetEnabled("Running", enable)

   remote:FireServer(enable)
end

-- Use the ToggleSprint() function however you want.

- Bonus!
-----------// Stamina Check for Sprinting (server) //-----------

class:AddCheck("Running", "StaminaCheck", function()
	if humanoid:GetAttribute("Stamina") > 0 then
		return true -- allow the module to activate the state
	end
end)

-----------// Sprinting Animation (client) //-----------

-- Module
local Priority3 = require(...) -- require the module

-- Variables
local character = ... -- get character
local humanoid = character:WaitForChild("Humanoid") -- get humanoid
local class = Priority3.GetClass(humanoid) -- get/create statemachine for humanoid

-- Functions (updating animation)
local function UpdateSprintAnimation(enabled, active)
   if active then
      -- play sprint animation here
   else
      -- stop sprint animation here
   end
end

class:ListenToChange("Running"):Connect(UpdateSprintAnimation)

API Document


Moved to Github

Its my first time using Github so lmk if I’m using it wrong :slightly_smiling_face:

Other Versions


Priority4:

PriProp:

24 Likes

Looks awesome, will definitely use on my projects!

2 Likes

New update:

Improved performance


Removed method:

priority.ListenToChange(function): Connection

Removed property:

priority.Functions: table

Added event:

class:ListenToChange(priorityName: string):Connect(enabled: boolean, active: boolean): RBXScriptConnection

Added Property:

priority.Signal: BindableEvent/Signal

2 Likes

New update:

Added method:

class:CanActivate(priorityName: string): boolean

  • returns true if a state can have the highest priority among other enable states
1 Like

could you show us an mp4 of this in action? thanks

1 Like

Sure here you go

and here’s the script used in this video

local Players = game:GetService("Players")
local Priority3 = require(game.ReplicatedStorage.Priority3)

Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(function(char)
		local hum: Humanoid = char:WaitForChild("Humanoid")
		local class = Priority3.GetClass(hum)
		
		-- enable walking by default
		class:SetEnabled("Walking", true)
		
		while true do
			-- toggle running
			class:SetEnabled("Running", not class.Priorities.Running.Enabled)
			
			task.wait(3)
			
			if math.random(0, 100) >= 50 then
				-- random stun
				class:SetEnabled("Stunned", true)
				task.delay(1, class.SetEnabled, class, "Stunned", false)
			end
		end
	end)
end)

2 Likes

You could try generalizing this to work for any instance, like for example the camera’s FOV

that is a good idea but I’m not sure how the HumanoidProperties module should work when adding support to multiple types of instances

Edit: this module does actually work on all types of Instances so if you want to use it on something other than Humanoids, you can.

This would DEFINITELY make my game’s state machine (for players only) much cleaner. I’m going to look into this soon; thanks for making it!

1 Like

New update:

Improved performance again


Added Properties:

  • priority.PrevEnabled: boolean (read-only)
    changes to priority.Enabled after class:ListenToChange is fired
  • priority.PrevActive: boolean (read-only)
    changes to priority.Active after class:ListenToChange is fired

Bug fixes:

  • Fixed class:ListenToChange getting fired more than 4 times in a row thanks to the new properties

Quality of life (QOL) changes:

  • Added a new priority named “Default” (its enabled by default for all humanoids)

New update:


Added Properties:

  • priority.Checks: table
    contains functions that give permission for activating the priority

Bug fixes:

  • Fixed not being able to create priority class for objects other than humanoids

Added Methods:

  • class:AddCheck(priority_name: string, checkId: string|any, checkFunction: function)
    no idea how to explain this one so take a look at this example script:
    (it runs checks after every frame btw)
  • class:RemoveCheck(priority_name: string, checkId: string|any)
    removes check function

Quality of life (QOL) changes:

  • class:SetEnabled(priority_name: string, enabled: boolean) now returns the active property of the priority
  • class:AddCheck() runs every frame now

New update:


New Class:

  • Stateconfig: { Name: string, Priority: number, Properties: {} }

Added Functions:

  • module.CreateStateConfig(info: {} | nil): Stateconfig

Added Methods:

  • class:AddState(config: Stateconfig): void
  • class:RemoveState(state_name: string): void

Small update:


Bug fix: Reverted a small change from the last update to fix the Typechecking/ IntelliSense for states