wallRunning
unknown
csharp
9 months ago
7.5 kB
3
Indexable
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();
}
}
Editor is loading...
Leave a Comment