Skip to content

Instantly share code, notes, and snippets.

@RH2
Created March 30, 2025 07:29
Show Gist options
  • Save RH2/09170bb50f77d75a710d54dd8fa849f7 to your computer and use it in GitHub Desktop.
Save RH2/09170bb50f77d75a710d54dd8fa849f7 to your computer and use it in GitHub Desktop.
Absolutely going to break all boundaries lol (UNITY)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class CharacterMovement10 : MonoBehaviour
{
public Camera playerCamera;
public float mouseSensitivity = 2f;
private float verticalLookRotation;
private CharacterController controller;
private Vector3 velocity;
private bool isGrounded;
private MovementState currentState;
private Dictionary<MovementState, List<Transition>> stateTransitions;
// Additional properties for transition conditions
public int maxJumpCount = 2;
private int currentJumpCount = 0;
public float maxStamina = 100f;
public float staminaRunCost = 10f;
private float currentStamina;
private float stateTimer = 0f;
[System.Serializable]
public class MovementSettings
{
public float speed;
public float duration;
public float fov;
public float gravityMultiplier;
public AnimationCurve cameraShake;
}
public MovementSettings walkSettings = new MovementSettings { speed = 3f, fov = 70f, gravityMultiplier = 1f };
public MovementSettings runSettings = new MovementSettings { speed = 6f, fov = 80f, gravityMultiplier = 1f };
public MovementSettings crouchSettings = new MovementSettings { speed = 1.5f, fov = 65f, gravityMultiplier = 1.2f };
public MovementSettings slideSettings = new MovementSettings { speed = 8f, duration = 1f, fov = 85f, gravityMultiplier = 0.5f };
public MovementSettings wallRunSettings = new MovementSettings { speed = 7f, duration = 2f, fov = 90f, gravityMultiplier = 0f };
public MovementSettings jumpSettings = new MovementSettings { speed = 4f, duration = 0.5f, fov = 75f, gravityMultiplier = 0.8f };
public MovementSettings fallSettings = new MovementSettings { fov = 70f, gravityMultiplier = 1.5f };
public MovementSettings climbSettings = new MovementSettings { speed = 2.5f, fov = 70f, gravityMultiplier = 0f };
public MovementSettings landSettings = new MovementSettings { duration = 0.3f, fov = 70f, gravityMultiplier = 1f };
private enum MovementState { Idle, Walk, Run, Crouch, Slide, WallRun, Jump, DoubleJump, Climb, Fall, Land }
private class Transition
{
public MovementState toState;
public System.Func<bool> condition;
}
void Start()
{
controller = GetComponent<CharacterController>();
Cursor.lockState = CursorLockMode.Locked;
currentStamina = maxStamina;
InitializeStateTransitions();
currentState = MovementState.Idle;
}
void Update()
{
HandleMouseLook();
HandleMovement();
UpdateStateTimer();
UpdateStamina();
CheckStateTransitions();
}
void HandleMouseLook()
{
float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity;
float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity;
transform.Rotate(Vector3.up * mouseX);
verticalLookRotation -= mouseY;
verticalLookRotation = Mathf.Clamp(verticalLookRotation, -90f, 90f);
playerCamera.transform.localEulerAngles = new Vector3(verticalLookRotation, 0, 0);
}
void HandleMovement()
{
isGrounded = controller.isGrounded;
Vector3 move = transform.right * Input.GetAxis("Horizontal") + transform.forward * Input.GetAxis("Vertical");
MovementSettings settings = GetCurrentMovementSettings();
controller.Move(move * settings.speed * Time.deltaTime);
velocity.y += Physics.gravity.y * settings.gravityMultiplier * Time.deltaTime;
if (isGrounded && velocity.y < 0) velocity.y = -2f;
controller.Move(velocity * Time.deltaTime);
}
void UpdateStateTimer()
{
MovementSettings settings = GetCurrentMovementSettings();
if (settings.duration > 0)
{
stateTimer += Time.deltaTime;
if (stateTimer >= settings.duration)
{
switch (currentState)
{
case MovementState.Slide:
TransitionToState(MovementState.Crouch);
break;
case MovementState.Land:
TransitionToState(MovementState.Idle);
break;
case MovementState.WallRun:
TransitionToState(MovementState.Fall);
break;
default:
break;
}
}
}
}
void UpdateStamina()
{
// Decrease stamina while running
if (currentState == MovementState.Run)
{
currentStamina -= staminaRunCost * Time.deltaTime;
}
// Regenerate stamina when not running
else if (currentState != MovementState.Run && currentStamina < maxStamina)
{
currentStamina += (maxStamina / 15f) * Time.deltaTime; // Regenerate full stamina in about 15 seconds
}
currentStamina = Mathf.Clamp(currentStamina, 0f, maxStamina);
}
void CheckStateTransitions()
{
if (stateTransitions.ContainsKey(currentState))
{
foreach (var transition in stateTransitions[currentState])
{
if (transition.condition())
{
TransitionToState(transition.toState);
break;
}
}
}
}
// Transition condition functions
bool CanIdle()
{
// Check if there's enough headspace to stand
return !Physics.Raycast(transform.position, Vector3.up, 2f) && isGrounded;
}
bool CanWalk()
{
return isGrounded && Input.GetAxis("Vertical") != 0 && CanIdle();
}
bool CanRun()
{
return isGrounded && Input.GetKey(KeyCode.LeftShift) && currentStamina > 0 &&
Input.GetAxis("Vertical") > 0 && CanIdle();
}
bool CanCrouch()
{
return isGrounded && Input.GetKey(KeyCode.C);
}
bool CanSlide()
{
return isGrounded && currentState == MovementState.Run && Input.GetKeyDown(KeyCode.C);
}
bool CanJump()
{
return isGrounded && Input.GetKeyDown(KeyCode.Space) && currentJumpCount < maxJumpCount;
}
bool CanDoubleJump()
{
return !isGrounded && Input.GetKeyDown(KeyCode.Space) && currentJumpCount < maxJumpCount;
}
bool CanWallRun()
{
return !isGrounded && DetectWall() && Input.GetAxis("Vertical") > 0;
}
bool CanClimb()
{
return DetectWallFront() && Input.GetKey(KeyCode.W);
}
bool CanFall()
{
return !isGrounded && velocity.y < 0;
}
bool CanLand()
{
return currentState == MovementState.Fall && isGrounded;
}
bool ShouldStopCrouching()
{
return !Input.GetKey(KeyCode.C) && CanIdle();
}
bool ShouldStopWallRun()
{
return !DetectWall() || Input.GetAxis("Vertical") <= 0;
}
bool DetectWall()
{
return Physics.Raycast(transform.position, transform.right, 1f) || Physics.Raycast(transform.position, -transform.right, 1f);
}
bool DetectWallFront()
{
return Physics.Raycast(transform.position, transform.forward, 1f);
}
void TransitionToState(MovementState newState)
{
// Exit actions
switch (currentState)
{
case MovementState.Land:
currentJumpCount = 0; // Reset jump counter when landing
break;
}
// Enter actions
switch (newState)
{
case MovementState.Jump:
case MovementState.DoubleJump:
currentJumpCount++;
velocity.y = Mathf.Sqrt(jumpSettings.speed * -2f * Physics.gravity.y);
break;
case MovementState.Land:
case MovementState.Slide:
case MovementState.WallRun:
stateTimer = 0f; // Reset timer for timed states
break;
}
currentState = newState;
}
void InitializeStateTransitions()
{
stateTransitions = new Dictionary<MovementState, List<Transition>>();
// Idle state transitions
stateTransitions[MovementState.Idle] = new List<Transition>
{
new Transition { toState = MovementState.Walk, condition = CanWalk },
new Transition { toState = MovementState.Crouch, condition = CanCrouch },
new Transition { toState = MovementState.Jump, condition = CanJump },
new Transition { toState = MovementState.Fall, condition = CanFall }
};
// Walk state transitions
stateTransitions[MovementState.Walk] = new List<Transition>
{
new Transition { toState = MovementState.Idle, condition = () => Input.GetAxis("Vertical") == 0 && Input.GetAxis("Horizontal") == 0 },
new Transition { toState = MovementState.Run, condition = CanRun },
new Transition { toState = MovementState.Crouch, condition = CanCrouch },
new Transition { toState = MovementState.Jump, condition = CanJump },
new Transition { toState = MovementState.Fall, condition = CanFall }
};
// Run state transitions
stateTransitions[MovementState.Run] = new List<Transition>
{
new Transition { toState = MovementState.Walk, condition = () => !Input.GetKey(KeyCode.LeftShift) || currentStamina <= 0 },
new Transition { toState = MovementState.Slide, condition = CanSlide },
new Transition { toState = MovementState.Jump, condition = CanJump },
new Transition { toState = MovementState.Fall, condition = CanFall },
new Transition { toState = MovementState.WallRun, condition = CanWallRun }
};
// Crouch state transitions
stateTransitions[MovementState.Crouch] = new List<Transition>
{
new Transition { toState = MovementState.Idle, condition = ShouldStopCrouching },
new Transition { toState = MovementState.Jump, condition = CanJump },
new Transition { toState = MovementState.Fall, condition = CanFall }
};
// Slide state transitions
stateTransitions[MovementState.Slide] = new List<Transition>
{
new Transition { toState = MovementState.Crouch, condition = () => stateTimer >= slideSettings.duration },
new Transition { toState = MovementState.Jump, condition = CanJump },
new Transition { toState = MovementState.Fall, condition = CanFall }
};
// WallRun state transitions
stateTransitions[MovementState.WallRun] = new List<Transition>
{
new Transition { toState = MovementState.DoubleJump, condition = CanDoubleJump },
new Transition { toState = MovementState.Fall, condition = ShouldStopWallRun },
new Transition { toState = MovementState.Fall, condition = () => stateTimer >= wallRunSettings.duration }
};
// Jump state transitions
stateTransitions[MovementState.Jump] = new List<Transition>
{
new Transition { toState = MovementState.DoubleJump, condition = CanDoubleJump },
new Transition { toState = MovementState.Fall, condition = () => velocity.y < 0 },
new Transition { toState = MovementState.WallRun, condition = CanWallRun },
new Transition { toState = MovementState.Climb, condition = CanClimb }
};
// DoubleJump state transitions
stateTransitions[MovementState.DoubleJump] = new List<Transition>
{
new Transition { toState = MovementState.Fall, condition = () => velocity.y < 0 },
new Transition { toState = MovementState.WallRun, condition = CanWallRun },
new Transition { toState = MovementState.Climb, condition = CanClimb }
};
// Climb state transitions
stateTransitions[MovementState.Climb] = new List<Transition>
{
new Transition { toState = MovementState.Jump, condition = CanJump },
new Transition { toState = MovementState.Fall, condition = () => !CanClimb() }
};
// Fall state transitions
stateTransitions[MovementState.Fall] = new List<Transition>
{
new Transition { toState = MovementState.Land, condition = CanLand },
new Transition { toState = MovementState.WallRun, condition = CanWallRun },
new Transition { toState = MovementState.Climb, condition = CanClimb },
new Transition { toState = MovementState.DoubleJump, condition = CanDoubleJump }
};
// Land state transitions
stateTransitions[MovementState.Land] = new List<Transition>
{
new Transition { toState = MovementState.Idle, condition = () => stateTimer >= landSettings.duration }
};
}
MovementSettings GetCurrentMovementSettings()
{
switch (currentState)
{
case MovementState.Walk: return walkSettings;
case MovementState.Run: return runSettings;
case MovementState.Crouch: return crouchSettings;
case MovementState.Slide: return slideSettings;
case MovementState.WallRun: return wallRunSettings;
case MovementState.Jump:
case MovementState.DoubleJump: return jumpSettings;
case MovementState.Fall: return fallSettings;
case MovementState.Climb: return climbSettings;
case MovementState.Land: return landSettings;
default: return walkSettings;
}
}
void OnGUI()
{
GUI.Label(new Rect(10, 10, 300, 20), "Current State: " + currentState);
GUI.Label(new Rect(10, 30, 300, 20), "Stamina: " + Mathf.Round(currentStamina) + " / " + maxStamina);
GUI.Label(new Rect(10, 50, 300, 20), "Jump Count: " + currentJumpCount + " / " + maxJumpCount);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment