wallRunning
using System.Collections; using System.Collections.Generic; using UnityEngine; public class WallRunningAdvanced : MonoBehaviour { [Header("Wallrunning")] public LayerMask whatIsWall; public LayerMask whatIsGround; public float wallRunForce; public float wallJumpUpForce; public float wallJumpSideForce; public float wallClimbSpeed; public float maxWallRunTime; public float maxWallJumps; private float wallRunTimer; private float currentWallJumps; private HashSet<GameObject> restrictedWalls = new HashSet<GameObject>(); // Track restricted walls private Queue<GameObject> lastWalls = new Queue<GameObject>(); // Keep track of last 2 walls public int maxRestrictedWalls = 2; // Limit to 2 walls [Header("Input")] public KeyCode jumpKey = KeyCode.Space; public KeyCode upwardsRunKey = KeyCode.LeftShift; public KeyCode downwardsRunKey = KeyCode.LeftControl; private bool upwardsRunning; private bool downwardsRunning; private float horizontalInput; private float verticalInput; [Header("Detection")] public float wallCheckDistance; public float minJumpHeight; private RaycastHit leftWallhit; private RaycastHit rightWallhit; private bool wallLeft; private bool wallRight; [Header("Exiting")] private bool exitingWall; public float exitWallTime; private float exitWallTimer; [Header("Gravity")] public bool useGravity; public float gravityCounterForce; [Header("References")] public Transform orientation; public PlayerCam cam; private PlayerMovementAdvanced pm; private Rigidbody rb; private GameObject currentWall; // Store reference to the current wall private void Start() { rb = GetComponent<Rigidbody>(); pm = GetComponent<PlayerMovementAdvanced>(); } private void Update() { CheckForWall(); StateMachine(); WallJumpCounter(); } private void FixedUpdate() { if (pm.wallrunning) WallRunningMovement(); } private void CheckForWall() { wallRight = Physics.Raycast(transform.position, orientation.right, out rightWallhit, wallCheckDistance, whatIsWall); wallLeft = Physics.Raycast(transform.position, -orientation.right, out leftWallhit, wallCheckDistance, whatIsWall); } private void WallJumpCounter() { if (pm.grounded) { currentWallJumps = maxWallJumps; ResetWallRunRestrictions(); // Reset walls when grounded } } private bool AboveGround() { return !Physics.Raycast(transform.position, Vector3.down, minJumpHeight, whatIsGround); } private void StateMachine() { // Getting Inputs horizontalInput = Input.GetAxisRaw("Horizontal"); verticalInput = Input.GetAxisRaw("Vertical"); upwardsRunning = Input.GetKey(upwardsRunKey); downwardsRunning = Input.GetKey(downwardsRunKey); // Determine current wall GameObject detectedWall = null; if (wallLeft) detectedWall = leftWallhit.collider.gameObject; if (wallRight) detectedWall = rightWallhit.collider.gameObject; // Prevent wallrun if wall is in restricted list if (detectedWall != null && restrictedWalls.Contains(detectedWall)) return; // State 1 - Wallrunning if ((wallLeft || wallRight) && verticalInput > 0 && AboveGround() && !exitingWall) { if (!pm.wallrunning) StartWallRun(detectedWall); // Wallrun timer if (wallRunTimer > 0) wallRunTimer -= Time.deltaTime; if (wallRunTimer <= 0 && pm.wallrunning) { exitingWall = true; exitWallTimer = exitWallTime; } // Wall jump if (Input.GetKeyDown(jumpKey) && currentWallJumps > 0) { WallJump(detectedWall); } } // State 2 - Exiting else if (exitingWall) { if (pm.wallrunning) StopWallRun(); if (exitWallTimer > 0) exitWallTimer -= Time.deltaTime; if (exitWallTimer <= 0) exitingWall = false; } // State 3 - None else { if (pm.wallrunning) StopWallRun(); } } private void StartWallRun(GameObject wall) { pm.wallrunning = true; wallRunTimer = maxWallRunTime; rb.linearVelocity = new Vector3(rb.linearVelocity.x, 0f, rb.linearVelocity.z); currentWall = wall; // Store the current wall // Apply camera effects cam.DoFov(90f); if (wallLeft) cam.DoTilt(-5f); if (wallRight) cam.DoTilt(5f); } private void WallRunningMovement() { rb.useGravity = useGravity; Vector3 wallNormal = wallRight ? rightWallhit.normal : leftWallhit.normal; Vector3 wallForward = Vector3.Cross(wallNormal, transform.up); if ((orientation.forward - wallForward).magnitude > (orientation.forward - -wallForward).magnitude) wallForward = -wallForward; // Forward force rb.AddForce(wallForward * wallRunForce, ForceMode.Force); // Upwards/downwards force if (upwardsRunning) rb.linearVelocity = new Vector3(rb.linearVelocity.x, wallClimbSpeed, rb.linearVelocity.z); if (downwardsRunning) rb.linearVelocity = new Vector3(rb.linearVelocity.x, -wallClimbSpeed, rb.linearVelocity.z); // Push to wall force if (!(wallLeft && horizontalInput > 0) && !(wallRight && horizontalInput < 0)) rb.AddForce(-wallNormal * 100, ForceMode.Force); // Weaken gravity if (useGravity) rb.AddForce(transform.up * gravityCounterForce, ForceMode.Force); } private void StopWallRun() { pm.wallrunning = false; // Add wall to restriction list if it exists if (currentWall != null) { restrictedWalls.Add(currentWall); lastWalls.Enqueue(currentWall); // Remove the oldest wall if we exceed the limit if (lastWalls.Count > maxRestrictedWalls) { GameObject oldestWall = lastWalls.Dequeue(); restrictedWalls.Remove(oldestWall); } } // Reset camera effects cam.DoFov(80f); cam.DoTilt(0f); } private void WallJump(GameObject wall) { exitingWall = true; exitWallTimer = exitWallTime; Vector3 wallNormal = wallRight ? rightWallhit.normal : leftWallhit.normal; Vector3 forceToApply = transform.up * wallJumpUpForce + wallNormal * wallJumpSideForce; // Reset Y velocity and apply force rb.linearVelocity = new Vector3(rb.linearVelocity.x, 0f, rb.linearVelocity.z); rb.AddForce(forceToApply, ForceMode.Impulse); currentWallJumps -= 1; } private void ResetWallRunRestrictions() { restrictedWalls.Clear(); lastWalls.Clear(); } }
Leave a Comment