替换脚本PlayerCam_01.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
public class PlayerCam_02 : MonoBehaviour
{
public float sensX = 400;
public float sensY = 400;
public float minAngle = -90f;
public float maxAngle = 90f;
public Transform orientation;
public Transform camHolder;
private float xRotation;
private float yRotation;
private void Start()
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
private void Update()
{
float mouseX = Input.GetAxisRaw("Mouse X") * Time.deltaTime * sensX;
float mouseY = Input.GetAxisRaw("Mouse Y") * Time.deltaTime * sensY;
yRotation += mouseX;
xRotation -= mouseY;
xRotation = Mathf.Clamp(xRotation, minAngle, maxAngle);
camHolder.rotation = Quaternion.Euler(xRotation, yRotation, 0);
orientation.rotation = Quaternion.Euler(0, yRotation, 0);
}
public void DoFov(float endValue)
{
GetComponent<Camera>().DOFieldOfView(endValue, 0.25f);
}
public void DoTilt(float zTilt)
{
transform.DOLocalRotate(new Vector3(0, 0, zTilt), 0.25f);
}
}
替换脚本PlayerMovement_03.cs和Sliding.cs,并新增脚本WallRunning.cs


PlayerMovement_04.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement_04 : MonoBehaviour
{
private float moveSpeed;
public float walkSpeed = 7;
public float sprintSpeed = 10;
public float slideSpeed = 30;
public float wallrunSpeed = 8.5f;
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;
private 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 Transform orientation;
private float h;
private float v;
private Vector3 moveDirection;
private Rigidbody rb;
public MovementState state;
public enum MovementState
{
walking,
sprinting,
wallrunning,
crouching,
sliding,
air
}
public bool sliding;
public bool wallrunning;
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()
{
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 (wallrunning)
{
state = MovementState.wallrunning;
desiredMoveSpeed = wallrunSpeed;
}
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;
}
}
Sliding_01.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Sliding_01 : MonoBehaviour
{
public Transform orientation;
public Transform playerObj;
private Rigidbody rb;
private PlayerMovement_04 pm_04;
public float maxSlideTime = 0.75f;
public float slideForce = 200;
private float slideTimer;
public float slideYScale = 0.5f;
private float startYScale;
public KeyCode slideKey = KeyCode.F;
private float h;
private float v;
private void Start()
{
rb = GetComponent<Rigidbody>();
pm_04 = GetComponent<PlayerMovement_04>();
startYScale = playerObj.localScale.y;
}
private void Update()
{
h = Input.GetAxisRaw("Horizontal");
v = Input.GetAxisRaw("Vertical");
if (Input.GetKeyDown(slideKey) && (h != 0 || v != 0))
{
StartSlide();
}
if (Input.GetKeyUp(slideKey) && pm_04.sliding)
{
StopSlide();
}
}
private void FixedUpdate()
{
if (pm_04.sliding)
{
SlidingMovement();
}
}
private void StartSlide()
{
pm_04.sliding = true;
playerObj.localScale = new Vector3(playerObj.localScale.x, slideYScale, playerObj.localScale.z);
rb.AddForce(Vector3.down * 5f, ForceMode.Impulse);
slideTimer = maxSlideTime;
}
private void SlidingMovement()
{
Vector3 inputDirection = orientation.forward * v + orientation.right * h;
if (!pm_04.OnSlope() || rb.velocity.y > -0.1f)
{
rb.AddForce(inputDirection.normalized * slideForce, ForceMode.Force);
slideTimer -= Time.deltaTime;
}
else
{
rb.AddForce(pm_04.GetSlopeMoveDirection(inputDirection) * slideForce, ForceMode.Force);
}
if (slideTimer <= 0)
{
StopSlide();
}
}
private void StopSlide()
{
pm_04.sliding = false;
playerObj.localScale = new Vector3(playerObj.localScale.x, startYScale, playerObj.localScale.z);
}
}
WallRunning.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WallRunning : MonoBehaviour
{
public LayerMask whatIsWall;
public LayerMask whatIsGround;
public float wallRunForce = 200;
public float wallJumpUpForce = 7;
public float wallJumpSideForce = 12;
public float wallClimbSpeed = 3;
public float maxWallRunTime = 0.7f;
private float wallRunTimer;
public KeyCode upwardsRunKey = KeyCode.E;
public KeyCode downwardsRunKey = KeyCode.Q;
public KeyCode jumpKey = KeyCode.Space;
private bool upwardsRunning;
private bool downwardsRunning;
private float h;
private float v;
public float wallCheckDistance = 0.7f;
public float minJumpHeight = 1;
private RaycastHit leftWallHit;
private RaycastHit rightWallHit;
private bool wallLeft;
private bool wallRight;
private bool exitingWall;
public float exitWallTime = 0.2f;
private float exitWallTimer;
public bool useGravity = true;
public float gravityCounterForce = 3;
public Transform orientation;
public PlayerCam_02 cam_02;
private PlayerMovement_04 pm_04;
private Rigidbody rb;
private void Start()
{
rb = GetComponent<Rigidbody>();
pm_04 = GetComponent<PlayerMovement_04>();
}
private void Update()
{
CheckForWall();
StateMachine();
}
private void FixedUpdate()
{
if (pm_04.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 bool AboveGround()
{
return !Physics.Raycast(transform.position, Vector3.down, minJumpHeight, whatIsGround);
}
private void StateMachine()
{
h = Input.GetAxisRaw("Horizontal");
v = Input.GetAxisRaw("Vertical");
upwardsRunning = Input.GetKey(upwardsRunKey);
downwardsRunning = Input.GetKey(downwardsRunKey);
if ((wallLeft || wallRight) && v > 0 && AboveGround() && !exitingWall)
{
if (!pm_04.wallrunning)
{
StartWallRun();
}
if (wallRunTimer > 0)
{
wallRunTimer -= Time.deltaTime;
}
if (wallRunTimer <= 0 && pm_04.wallrunning)
{
exitingWall = true;
exitWallTimer = exitWallTime;
}
if (Input.GetKeyDown(jumpKey))
{
WallJump();
}
}
else if (exitingWall)
{
if (pm_04.wallrunning)
{
StopWallRun();
}
if (exitWallTimer > 0)
{
exitWallTimer -= Time.deltaTime;
}
if (exitWallTimer <= 0)
{
exitingWall = false;
}
}
else
{
if (pm_04.wallrunning)
{
StopWallRun();
}
}
}
private void StartWallRun()
{
pm_04.wallrunning = true;
wallRunTimer = maxWallRunTime;
rb.velocity = new Vector3(rb.velocity.x, 0f, rb.velocity.z);
cam_02.DoFov(90f);
if (wallLeft)
{
cam_02.DoTilt(-5f);
Debug.Log("摄像机向左倾斜5度");
}
if (wallRight)
{
cam_02.DoTilt(5f);
Debug.Log("摄像机向右倾斜5度");
}
}
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;
}
rb.AddForce(wallForward * wallRunForce, ForceMode.Force);
if (upwardsRunning)
{
rb.velocity = new Vector3(rb.velocity.x, wallClimbSpeed, rb.velocity.z);
}
if (downwardsRunning)
{
rb.velocity = new Vector3(rb.velocity.x, -wallClimbSpeed, rb.velocity.z);
}
if (!(wallLeft && h > 0) && !(wallRight && h < 0))
{
rb.AddForce(-wallNormal * 100, ForceMode.Force);
}
if (useGravity)
{
rb.AddForce(transform.up * gravityCounterForce, ForceMode.Force);
}
}
private void StopWallRun()
{
pm_04.wallrunning = false;
cam_02.DoFov(80f);
cam_02.DoTilt(0f);
}
private void WallJump()
{
exitingWall = true;
exitWallTimer = exitWallTime;
Vector3 wallNormal = wallRight ? rightWallHit.normal : leftWallHit.normal;
Vector3 forceToApply = transform.up * wallJumpUpForce + wallNormal * wallJumpSideForce;
rb.velocity = new Vector3(rb.velocity.x, 0f, rb.velocity.z);
rb.AddForce(forceToApply, ForceMode.Impulse);
}
}