# PROJECT CONTEXT & ARCHITECTURE - Engine: Unity 6.3 - Genre: 3D Third-Person Action Game (TPS) - Input: Unity New Input System (using InputReader script) - Pattern: Hierarchical State Machine (HSM) / State Pattern - Coding Rules: Strictly English for all variables, methods, classes, and comments. Use CharacterController for movement. Handle rotation using Quaternion.Slerp. # 1. INPUT READER (InputReader.cs) Inherits: MonoBehaviour Properties: - Vector2 MoveInput (from WASD/Left Stick) - bool IsSprintHeld (from Left Shift - continuous hold) Events (Actions): - event Action OnJumpEvent (Space bar pressed) - event Action OnDodgeEvent (Right Mouse Button - RMB pressed) - event Action OnCrouchEvent (C key pressed) # 2. ANIMATOR SETUP REQUIREMENTS Parameters: - "Speed" (Float): Grounded movement (0.0 = Idle, 0.5 = Walk, 1.0 = Run). - "IsCrouching" (Bool): Toggle crouch mode. - "CrouchSpeed" (Float): Crouch movement (0.0 = Idle, 0.5 = Sneak, 1.0 = Walk). - Triggers: "Dash", "Jump", "Fall", "AirDash", "Thrust", "Dodge". # 3. STATE MACHINE CORE (PlayerStateMachine.cs) Inherits: MonoBehaviour RequireComponents: CharacterController, InputReader, Animator Variables: - float WalkSpeed = 3f, RunSpeed = 6f, DashForce = 10f, SneakSpeed = 1.5f - float JumpForce = 5f, Gravity = -9.81f, ThrustDownwardForce = -20f - float VelocityY (tracks vertical speed) - PlayerBaseState currentState Methods: - SwitchState(PlayerBaseState newState): calls currentState.Exit(), updates state, calls currentState.Enter(). - Update(): calls currentState.Tick(Time.deltaTime). - FixedUpdate(): calls currentState.PhysicsTick(Time.fixedDeltaTime). # 4. BASE STATE (PlayerBaseState.cs) Abstract class. Constructor takes (PlayerStateMachine stateMachine). Abstract Methods: Enter(), Tick(float deltaTime), PhysicsTick(float fixedDeltaTime), Exit(). # 5. DETAILED STATE LOGICS ## PlayerIdleState - Enter: Subscribe to OnJumpEvent, OnDodgeEvent, OnCrouchEvent. - Tick: SmoothDamp "Speed" to 0.0. If MoveInput != Vector2.zero -> SwitchState(PlayerMoveState). - Exit: Unsubscribe events. ## PlayerMoveState - Enter: Subscribe to events (Jump, Dodge, Crouch). - Tick: - If MoveInput == Vector2.zero -> SwitchState(PlayerIdleState). - If IsSprintHeld == true -> SwitchState(PlayerDashState). - Move using CharacterController (MoveInput * WalkSpeed). - Slerp rotation towards MoveInput direction. - SmoothDamp "Speed" to 0.5. - Exit: Unsubscribe events. ## PlayerDashState - Variables: timer = 0.25s, dashDirection (Vector3). - Enter: Set dashDirection to MoveInput (or transform.forward if 0). Snap rotation to dashDirection. SetTrigger("Dash"). - Tick: - Move at DashForce along dashDirection (no gravity applied). - timer -= deltaTime. - If timer <= 0: - If IsSprintHeld AND MoveInput != 0 -> SwitchState(PlayerRunState). - If MoveInput != 0 -> SwitchState(PlayerMoveState). - Else -> SwitchState(PlayerIdleState). ## PlayerRunState - Enter: Subscribe to events (Jump, Dodge, Crouch). - Tick: - If MoveInput == 0 -> SwitchState(PlayerIdleState). - If IsSprintHeld == false -> SwitchState(PlayerMoveState). - Move using CharacterController (MoveInput * RunSpeed). Slerp rotation. - SmoothDamp "Speed" to 1.0. - Exit: Unsubscribe events. ## PlayerJumpState - Enter: SetTrigger("Jump"). VelocityY = JumpForce. - Tick: - Apply Gravity (VelocityY += Gravity * deltaTime). - Apply horizontal Air Control (MoveInput * WalkSpeed). - Move using CharacterController (Horizontal + Vertical). - If VelocityY <= 0 -> SwitchState(PlayerFallState). ## PlayerFallState - Enter: SetTrigger("Fall"). Subscribe to OnDodgeEvent (maps to Thrust here). - Tick: - Apply Gravity. Apply horizontal Air Control. Move via Controller. - If IsSprintHeld -> SwitchState(PlayerAirDashState). - If isGrounded -> Set VelocityY = -2f. SwitchState(Idle or Move based on input). - Thrust Event Trigger: SwitchState(PlayerThrustState). - Exit: Unsubscribe OnDodgeEvent. ## PlayerAirDashState - Variables: timer = 0.2s, dashDir. - Enter: SetTrigger("AirDash"). VelocityY = 0f. Set dashDir based on MoveInput. - Tick: - Move horizontally at DashForce (VelocityY stays 0). - timer -= deltaTime. If timer <= 0 -> SwitchState(PlayerFallState). ## PlayerThrustState - Enter: SetTrigger("Thrust"). VelocityY = ThrustDownwardForce. - Tick: - VelocityY += (Gravity * 2) * deltaTime. Move purely downwards (no horizontal). - If isGrounded -> Set VelocityY = -2f. SwitchState(PlayerIdleState). ## PlayerCrouchState - Enter: SetBool("IsCrouching", true). Subscribe to OnCrouchEvent (Toggle), OnDodgeEvent. - Tick: - If MoveInput == 0: "CrouchSpeed" = 0.0. - If MoveInput != 0 AND IsSprintHeld: Move at SneakSpeed. "CrouchSpeed" = 0.5. - If MoveInput != 0 AND !IsSprintHeld: Move at WalkSpeed. "CrouchSpeed" = 1.0. - Apply Movement and Slerp rotation. - Toggle Event Trigger (C key): SwitchState(Idle or Move). - Dodge Event Trigger (LMB): SwitchState(PlayerDodgeState). - Exit: SetBool("IsCrouching", false). Unsubscribe events. ## PlayerDodgeState - Variables: timer = 0.4s, dodgeDir. - Enter: SetTrigger("Dodge"). Set dodgeDir based on MoveInput (Left/Right/Back/Forward). Snap rotation. - Tick: - Move at (DashForce * 0.8) along dodgeDir. - timer -= deltaTime. - If timer <= 0 -> SwitchState(Idle or Move based on MoveInput).