我正在制作一个 Unity 游戏,如果对这个玩家控制器进行编码,但是当它跳跃时,它会消除我的速度

问题描述 投票:0回答:1

当我跳跃时,玩家会失去之前的速度并产生撞到无形墙壁的感觉。

我尝试过改变阻力、坡度控制以及跳跃的方式,但没有成功。我也尝试过使用 chatgpt 但它没有做任何有帮助的事情。如果有任何更有效的方法可以让玩家按照我的方式进行操作,我也将不胜感激。

using UnityEngine;
using System.Collections;

public class PlayerMovement : MonoBehaviour
{
    [Header("Movement Settings")]
    public float walkSpeed = 5f;
    public float sprintSpeed = 10f;
    public float crouchSpeed = 2f;
    public Transform orientation;
    public float groundDrag = 5f;
    public float airDrag = 0f;
    public float moveSmoothing = 0.1f;
    public float maxSpeed = 10f;

    [Header("Ground Check")]
    public float groundCheckRadius = 0.5f;
    public LayerMask groundLayer;
    private bool grounded;
    private bool wasGrounded;

    [Header("Slope Handling")]
    public float maxSlopeAngle = 45f;
    private bool exitingSlope;
    private bool onSlope;
    private RaycastHit slopeHit;
    private Vector3 slopeNormal;
    private float slopeRayLength = 2f;  // Longer ray length for better accuracy
    private float groundRayOffset = 0.5f;  // Height offset for ray origin
    private int groundRayCount = 3;  // Number of ground check rays

    [Header("Player Jumping")]
    public float jumpForce = 10f;
    public float jumpCooldown = 1f;
    public float airMultiplier = 0.25f;
    private Vector3 storedVelocity;

    [Header("Crouching")]
    public float crouchYScale = 0.5f;
    private float startYScale;

    [Header("Keybinds")]
    public KeyCode jumpKey = KeyCode.Space;
    public KeyCode sprintKey = KeyCode.LeftShift;
    public KeyCode crouchKey = KeyCode.LeftControl;

    private Rigidbody rb;
    private float moveSpeed;
    private float horizontalInput;
    private float verticalInput;
    private bool readyToJump = true;

    private Vector3 moveDirection;

    public MovementState state;
    public enum MovementState
    {
        walking,
        sprinting,
        crouching,
        air
    }

    private void Start()
    {
        rb = GetComponent<Rigidbody>();
        rb.freezeRotation = true;
        rb.constraints = RigidbodyConstraints.FreezeRotationX |
                         RigidbodyConstraints.FreezeRotationY |
                         RigidbodyConstraints.FreezeRotationZ;

        startYScale = transform.localScale.y;
        rb.drag = groundDrag;
    }

    private bool IsGrounded()
    {
        // Ground check using multiple raycasts to ensure accuracy
        bool isGrounded = false;
        float rayLength = slopeRayLength;
        Vector3 rayOrigin = transform.position + Vector3.up * groundRayOffset;

        for (int i = -1; i <= 1; i++)
        {
            Vector3 offset = Vector3.right * i * groundCheckRadius;
            Vector3 rayPosition = rayOrigin + offset;

            if (Physics.Raycast(rayPosition, Vector3.down, out RaycastHit hit, rayLength, groundLayer))
            {
                isGrounded = true;
                slopeNormal = hit.normal;
                float angle = Vector3.Angle(Vector3.up, slopeNormal);
                onSlope = angle > 0 && angle <= maxSlopeAngle;  // Within allowed slope range
            }
        }

        return isGrounded;
    }

    private void Update()
    {
        wasGrounded = grounded;
        grounded = IsGrounded();


        MyInput();
        StateHandler();

        if (grounded && !wasGrounded)
        {
            OnLanding();
        }

        if (Input.GetKey(crouchKey))
        {
            moveSpeed = crouchSpeed;
        }
        else if (Input.GetKey(sprintKey))
        {
            moveSpeed = sprintSpeed;
        }
        else
        {
            moveSpeed = walkSpeed;
        }
    }

    private void MyInput()
    {
        horizontalInput = Input.GetAxisRaw("Horizontal");
        verticalInput = Input.GetAxisRaw("Vertical");

        if (Input.GetKeyDown(jumpKey) && readyToJump && grounded)
        {
            readyToJump = false;
            Jump();
            StartCoroutine(JumpCooldown());
        }

        if (Input.GetKey(crouchKey))
        {
            transform.localScale = new Vector3(transform.localScale.x, crouchYScale, transform.localScale.z);
        }

        if (Input.GetKeyUp(crouchKey))
        {
            transform.localScale = new Vector3(transform.localScale.x, startYScale, transform.localScale.z);
        }
    }

    private void FixedUpdate()
    {
        MovePlayer();
        CapSpeed();
    }

        private void StateHandler()
    {
        // Mode - Crouching
        if (Input.GetKey(crouchKey))
        {
            state = MovementState.crouching;
            moveSpeed = crouchSpeed;
        }

        // Mode - Sprinting
        else if(grounded && Input.GetKey(sprintKey))
        {
            state = MovementState.sprinting;
            moveSpeed = sprintSpeed;
        }

        // Mode - Walking
        else if (grounded)
        {
            state = MovementState.walking;
            moveSpeed = walkSpeed;
        }

        // Mode - Air
        else
        {
            state = MovementState.air;
        }
    }

    private void MovePlayer()
    {
        moveDirection = (orientation.forward * verticalInput + orientation.right * horizontalInput).normalized;

        if (onSlope && !exitingSlope)  // No parentheses because 'onSlope' is a boolean, not a method
        {
           rb.AddForce(GetSlopeMoveDirection() * moveSpeed * 20f, ForceMode.Force);

            if (rb.velocity.y > 0)
                rb.AddForce(Vector3.down * 80f, ForceMode.Force);
        }
        else if (grounded)
        {
            Vector3 targetPosition = transform.position + moveDirection * moveSpeed * Time.fixedDeltaTime;
            rb.MovePosition(Vector3.Lerp(transform.position, targetPosition, moveSmoothing));
        }
        else
        {
            rb.AddForce(moveDirection * moveSpeed * airMultiplier, ForceMode.Force);  // Airborne movement
        }
    }


    private void CapSpeed()
    {
        float currentSpeed = rb.velocity.magnitude;

        if (currentSpeed > maxSpeed)
        {
            rb.velocity = rb.velocity.normalized * maxSpeed;  // Limit speed to avoid excessive acceleration
        }
    }

    private void Jump() {
        // Keep horizontal velocity, reset only vertical component to 0 before jump
        Vector3 horizontalVelocity = new Vector3(rb.velocity.x, rb.velocity.z); // Remove Y component
    
        // Set the new velocity with preserved horizontal components
        rb.velocity = new Vector3(horizontalVelocity.x, 0, horizontalVelocity.y);

        // Apply jump force
        rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
        Debug.Log("jump");
    }

    private IEnumerator JumpCooldown()
    {
        yield return new WaitForSeconds(jumpCooldown);
        readyToJump = true;
    }

private IEnumerator SmoothDragChange(float newDrag, float duration)
{
    float startDrag = rb.drag;
    float time = 0f;

    while (time < duration)
    {
        rb.drag = Mathf.Lerp(startDrag, newDrag, time / duration);
        time += Time.fixedDeltaTime;
        yield return new WaitForSeconds(Time.fixedDeltaTime);
    }

    rb.drag = newDrag;
} 

    private void OnLanding()
    {
        storedVelocity = rb.velocity;
        Invoke("RestoreVelocity", 0.1f);

        rb.drag = groundDrag;  // Restore drag upon landing
        Invoke(nameof(ResetGroundDrag), 0.1f);  // Slight delay to smooth landing
    }

    private void RestoreVelocity()
    {
        rb.velocity = storedVelocity;
    }  


    private void ResetGroundDrag()
    {
        rb.drag = groundDrag;
    }

    private void OnDrawGizmos()
    {
        Gizmos.color = Color.red;
        Vector3 rayOrigin = transform.position + Vector3.up * groundRayOffset;
        float rayLength = slopeRayLength;

        for (int i = -1; i <= 1; i++)
        {
            Vector3 offset = Vector3.right * i * groundCheckRadius;
            Gizmos.DrawRay(rayOrigin + offset, Vector3.down * rayLength);
        }
    }
    private Vector3 GetSlopeMoveDirection()
    {
        return Vector3.ProjectOnPlane(moveDirection, slopeHit.normal).normalized;
    }
}

c# unity-game-engine
1个回答
0
投票

有很多代码需要理解,所以我不能 100% 确定为什么会出现问题。但我怀疑这是因为你根据状态不同地移动刚体。当接地时,您可以直接操纵位置,当在空中时,您可以增加力量:

else if (grounded)
{
    Vector3 targetPosition = transform.position + moveDirection * moveSpeed * Time.fixedDeltaTime;
    rb.MovePosition(Vector3.Lerp(transform.position, targetPosition, moveSmoothing));
}
else
{
    rb.AddForce(moveDirection * moveSpeed * airMultiplier, ForceMode.Force);  // Airborne movement
}

因此,当您开始跳跃时,您会失去初始速度,因为 AddForce 必须加速您的玩家,而且它可能会缓慢加速。最好保持一致,并在处理一种移动时以一种方式移动你的球员。使用力进行向上/向下移动是可以的,但对于水平移动,要么切换到力,要么仅使用位置操纵。您可以通过将空气中的水平运动更改为操纵来测试它,如下所示:

else if (grounded)
{
    Vector3 targetPosition = transform.position + moveDirection * moveSpeed * Time.fixedDeltaTime;
    rb.MovePosition(Vector3.Lerp(transform.position, targetPosition, moveSmoothing));
}
else
{
    Vector3 targetPosition = transform.position + moveDirection * moveSpeed * Time.fixedDeltaTime;
    rb.MovePosition(Vector3.Lerp(transform.position, targetPosition, moveSmoothing)); //AirMovement
}

您可以使用最后一个 else 块来根据您的需要进行调整。如果你不需要调整,你可以将其合并为一段代码,因为这是相同的操作。

你的上/下运动不应该受此影响,因为无论如何你都单独添加跳跃力

© www.soinside.com 2019 - 2024. All rights reserved.