替换脚本PlayerMovement_04.cs
using System. Collections ;
using System. Collections. Generic ;
using UnityEngine ; public class PlayerMovement_05 : MonoBehaviour
{ private float moveSpeed; public float walkSpeed = 7 ; public float sprintSpeed = 10 ; public float slideSpeed = 30 ; public float wallrunSpeed = 8.5f ; public float climbSpeed = 3 ; private float desiredMoveSpeed; private float lastDesiredMoveSpeed; public float speedIncreaseMultiplier = 1.5f ; public float slopeIncreaseMultiplier = 2.5f ; public float groundDrag = 5 ; public float playerHeight = 2 ; public LayerMask whatIsGround; public bool grounded; public float jumpForce = 6 ; public float jumpCooldown = 0.25f ; public float airMultiplier = 0.4f ; private bool readyToJump = true ; public float crouchSpeed = 3.5f ; public float crouchYScale = 0.5f ; private float startYScale; public float maxSlopAngle = 40 ; private RaycastHit slopeHit; private bool exitingSlope = true ; public KeyCode jumpKey = KeyCode. Space; public KeyCode sprintKey = KeyCode. LeftShift; public KeyCode crouchKey = KeyCode. LeftControl; public Climbing climbingScript; public Transform orientation; private float h; private float v; private Vector3 moveDirection; private Rigidbody rb; public MovementState state; public enum MovementState { walking, sprinting, wallrunning, climbing, crouching, sliding, air } public bool sliding; public bool wallrunning; public bool climbing; private void Start ( ) { rb = GetComponent < Rigidbody> ( ) ; rb. freezeRotation = true ; startYScale = transform. localScale. y; } private void Update ( ) { grounded = Physics. Raycast ( transform. position, Vector3. down, playerHeight * 0.5f + 0.2f , whatIsGround) ; MyInput ( ) ; SpeedControl ( ) ; StateHandler ( ) ; if ( grounded) rb. drag = groundDrag; else rb. drag = 0 ; } private void FixedUpdate ( ) { MovePlayer ( ) ; } private void MyInput ( ) { h = Input. GetAxisRaw ( "Horizontal" ) ; v = Input. GetAxisRaw ( "Vertical" ) ; if ( Input. GetKey ( jumpKey) && readyToJump && grounded) { readyToJump = false ; Jump ( ) ; Invoke ( nameof ( ResetJump) , jumpCooldown) ; } if ( Input. GetKeyDown ( crouchKey) ) { transform. localScale = new Vector3 ( transform. localScale. x, crouchYScale, transform. localScale. z) ; rb. AddForce ( Vector3. down * 5f , ForceMode. Impulse) ; } if ( Input. GetKeyUp ( crouchKey) ) { transform. localScale = new Vector3 ( transform. localScale. x, startYScale, transform. localScale. z) ; } } private void MovePlayer ( ) { if ( climbingScript. exitingWall) return ; moveDirection = orientation. forward * v + orientation. right * h; if ( OnSlope ( ) && ! exitingSlope) { rb. AddForce ( GetSlopeMoveDirection ( moveDirection) * moveSpeed * 20f , ForceMode. Force) ; if ( rb. velocity. y > 0 ) { rb. AddForce ( Vector3. down * 80f , ForceMode. Force) ; } } else if ( grounded) { rb. AddForce ( moveDirection. normalized * moveSpeed * 10f , ForceMode. Force) ; } else if ( ! grounded) { rb. AddForce ( moveDirection. normalized * moveSpeed * 10f * airMultiplier, ForceMode. Force) ; } if ( ! wallrunning) rb. useGravity = ! OnSlope ( ) ; } private void SpeedControl ( ) { if ( OnSlope ( ) && ! exitingSlope) { if ( rb. velocity. magnitude > moveSpeed) { rb. velocity = rb. velocity. normalized * moveSpeed; } } else { Vector3 flatVel = new Vector3 ( rb. velocity. x, 0f , rb. velocity. z) ; if ( flatVel. magnitude > moveSpeed) { Vector3 limitedVel = flatVel. normalized * moveSpeed; rb. velocity = new Vector3 ( limitedVel. x, rb. velocity. y, limitedVel. z) ; } } } private void Jump ( ) { exitingSlope = true ; rb. velocity = Vector3. zero; rb. AddForce ( transform. up * jumpForce, ForceMode. Impulse) ; } private void ResetJump ( ) { readyToJump = true ; exitingSlope = false ; } private void StateHandler ( ) { if ( climbing) { state = MovementState. climbing; desiredMoveSpeed = climbSpeed; } else if ( wallrunning) { state = MovementState. wallrunning; desiredMoveSpeed = wallrunSpeed; } else if ( sliding) { state = MovementState. sliding; if ( OnSlope ( ) && rb. velocity. y < 0.1f ) { desiredMoveSpeed = slideSpeed; } else { desiredMoveSpeed = sprintSpeed; } } else if ( Input. GetKey ( crouchKey) ) { state = MovementState. crouching; desiredMoveSpeed = crouchSpeed; } else if ( grounded && Input. GetKey ( sprintKey) ) { state = MovementState. sprinting; desiredMoveSpeed = sprintSpeed; } else if ( grounded) { state = MovementState. walking; desiredMoveSpeed = walkSpeed; } else { state = MovementState. air; } if ( Mathf. Abs ( desiredMoveSpeed - lastDesiredMoveSpeed) > 4f && moveSpeed != 0 ) { StopAllCoroutines ( ) ; StartCoroutine ( SmoothlyLerpMoveSpeed ( ) ) ; } else { moveSpeed = desiredMoveSpeed; } lastDesiredMoveSpeed = desiredMoveSpeed; } public bool OnSlope ( ) { if ( Physics. Raycast ( transform. position, Vector3. down, out slopeHit, playerHeight * 0.5f + 0.3f ) ) { float angle = Vector3. Angle ( Vector3. up, slopeHit. normal) ; return angle < maxSlopAngle && angle != 0 ; } return false ; } public Vector3 GetSlopeMoveDirection ( Vector3 direction) { return Vector3. ProjectOnPlane ( direction, slopeHit. normal) . normalized; } private IEnumerator SmoothlyLerpMoveSpeed ( ) { float time = 0 ; float difference = Mathf. Abs ( desiredMoveSpeed - moveSpeed) ; float startValue = moveSpeed; while ( time < difference) { moveSpeed = Mathf. Lerp ( startValue, desiredMoveSpeed, time / difference) ; if ( OnSlope ( ) ) { float slopeAngle = Vector3. Angle ( Vector3. up, slopeHit. normal) ; float slopeAngleIncrease = 1 + ( slopeAngle / 90f ) ; time += Time. deltaTime * speedIncreaseMultiplier * slopeIncreaseMultiplier * slopeAngleIncrease; } else { time += Time. deltaTime * speedIncreaseMultiplier; } yield return null ; } moveSpeed = desiredMoveSpeed; }
}
新增脚本Climbing.cs
using System. Collections ;
using System. Collections. Generic ;
using UnityEngine ; public class Climbing : MonoBehaviour
{ public Transform orientation; public Rigidbody rb; public PlayerMovement_05 pm_05; public LayerMask whatIsWall; public float climbSpeed = 10 ; public float maxClimbTime = 0.75f ; private float climbTimer; private bool climbing; public float climbJumpUpForce = 14 ; public float climbJumpBackForce = 12 ; public KeyCode jumpKey = KeyCode. Space; public int climbJumps = 1 ; private int climbJumpsLeft; public float detectionLength = 0.7f ; public float sphereCastRadius = 0.25f ; public float maxWallLookAngle = 30 ; private float wallLookAngle; private RaycastHit frontWallHit; private bool wallFront; private Transform lastWall; private Vector3 lastWallNormal; public float minWallNormalAngleChange = 5 ; public bool exitingWall; public float exitWallTime = 0.2f ; private float exitWallTimer; private void Update ( ) { WallCheck ( ) ; StateMachine ( ) ; if ( climbing && ! exitingWall) { ClimbingMovement ( ) ; } } private void StateMachine ( ) { if ( wallFront && Input. GetKey ( KeyCode. W) && wallLookAngle < maxWallLookAngle && ! exitingWall) { if ( ! climbing && climbTimer > 0 ) { Debug. Log ( "开始攀爬" ) ; StartClimbing ( ) ; } if ( climbTimer > 0 ) { climbTimer -= Time. deltaTime; } if ( climbTimer < 0 ) { Debug. Log ( "攀爬时间用完,停止攀爬!" ) ; StopClimbing ( ) ; } } else if ( exitingWall) { if ( climbing) { StopClimbing ( ) ; } if ( exitWallTimer > 0 ) exitWallTimer -= Time. deltaTime; if ( exitWallTimer < 0 ) exitingWall = false ; } else { if ( climbing) { StopClimbing ( ) ; } } if ( wallFront && Input. GetKeyDown ( jumpKey) && climbJumpsLeft > 0 ) { Debug. Log ( "进行攀爬跳跃" ) ; ClimbJump ( ) ; } } private void WallCheck ( ) { wallFront = Physics. SphereCast ( transform. position, sphereCastRadius, orientation. forward, out frontWallHit, detectionLength, whatIsWall) ; wallLookAngle = Vector3. Angle ( orientation. forward, - frontWallHit. normal) ; bool newWall = frontWallHit. transform != lastWall || Mathf. Abs ( Vector3. Angle ( lastWallNormal, frontWallHit. normal) ) > minWallNormalAngleChange; if ( ( wallFront && newWall) || pm_05. grounded) { climbTimer = maxClimbTime; climbJumpsLeft = climbJumps; } } private void StartClimbing ( ) { climbing = true ; pm_05. climbing = true ; lastWall = frontWallHit. transform; lastWallNormal = frontWallHit. normal; } private void ClimbingMovement ( ) { rb. velocity = new Vector3 ( rb. velocity. x, climbSpeed, rb. velocity. z) ; } private void StopClimbing ( ) { climbing = false ; pm_05. climbing = false ; } private void ClimbJump ( ) { exitingWall = true ; exitWallTimer = exitWallTime; Vector3 forceToApply = transform. up * climbJumpUpForce + frontWallHit. normal * climbJumpBackForce; rb. velocity = new Vector3 ( rb. velocity. x, 0f , rb. velocity. z) ; rb. AddForce ( forceToApply, ForceMode. Impulse) ; climbJumpsLeft-- ; }
}