替换脚本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-- ;
}
}