我正在Unity中制作游戏,您可以在其中移动WASD和跳跃的空间。这是我的代码:

using UnityEngine;

public class PlayerMovement : MonoBehaviour {

    public Rigidbody rb;
    public bool canJump;

    void FixedUpdate () {
        if (Input.GetKey("w"))
        {
            rb.AddForce(0, 0, 750 * Time.deltaTime, ForceMode.Acceleration);
        }

        if (Input.GetKey("a"))
        {
            rb.AddForce(-750 * Time.deltaTime, 0, 0, ForceMode.Acceleration);
        }

        if (Input.GetKey("s"))
        {
            rb.AddForce(0, 0, -750 * Time.deltaTime, ForceMode.Acceleration);
        }

        if (Input.GetKey("d"))
        {
            rb.AddForce(750 * Time.deltaTime, 0, 0, ForceMode.Acceleration);
        }

        if (canJump)
        {
            if (Input.GetKeyDown("space"))
            {
                rb.AddForce(0, 10, 0, ForceMode.VelocityChange);
                Debug.Log("jump");
                canJump = false;
            }
        }

        Vector3 v = rb.velocity;
        v.y = 0;
        v = Vector3.ClampMagnitude(v, 6);
        v.y = rb.velocity.y;
        rb.velocity = v;
    }

    void OnCollisionEnter(Collision other)
    {
        if (other.gameObject.name == "Ground")
        {
            canJump = true;
        }
    }

    void OnCollisionExit(Collision other)
    {
        if (other.gameObject.name == "Ground")
        {
            canJump = false;
        }
    }
}


但是,当我跳时,它有时会跳得很高,有时甚至根本不会跳。我测试了按住空格键是否有任何作用,没有。我已经尝试过使用ForceMode.Impulse和ForceMode.VelocityChange,但是跳转仍然不一致。

我还注意到,只有在地板上的Y值约为0.23时,播放器才会跳到空中。像这样,它也可以是〜0.16,并且根本不会跳得很高。

这是〜0.16
c# - 取决于Y值,Unity中的跳跃不一致-LMLPHP
这是〜0.23
c# - 取决于Y值,Unity中的跳跃不一致-LMLPHP

最低的跳跃使它达到约0.7的Y值,但最高的跳跃使它达到4.83左右。

如果有人有任何想法,我将不胜感激。

最佳答案

我通常要做的是检查我是向上还是向下。我只接受地面检查,如果我向下走。

void OnCollisionEnter(Collision other)
{
    if (other.gameObject.name == "Ground" && rb.velocity.y < 0)
    {
        canJump = true;
    }
}


但是,您使用getKeyDOWN,所以它与保留空间等无关。

因此,我接下来要推荐的是:在跳跃之前将Velocity.y设置为0。

if (Input.GetKeyDown("space"))
{
    Vector3 vel = rb.velocity;
    vel.y = 0;
    rb.velocity = vel;
    rb.AddForce(0, 10, 0, ForceMode.VelocityChange);
    // ...
}


编辑:等等,我的第一个念头是“他使用getKey并保留了空间”,我的第二个念头是:“他错过了Time.deltaTime”。但是现在我看到了:

您在FixedUpdate中使用了Input.Get...

让我解释:

在调用所有Update之前,将评估所有输入。
As you can see in the execution Order在更新之前立即处理Input事件。

现在,根据您的帧速率,与(几乎)常量FixedUpdate相比,Update是经常被调用还是很少被调用。

因此,FixedUpdate可以在Update调用之间多次调用。这意味着输入事件只运行了一次。

因此,我必须假设Input.GetKeyDown(Key.SPACE)在多个FixedUpdates中都是正确的!

轻松解决:

bool jump_pressed = false;

void Update()
{
    if(Input.GetKeyDown("space"))
    {
        jump_pressed = true;
    }
    if(Input.GetKeyUp("space"))
    {
        jump_pressed = false;
    }
}

void FixedUpdate()
{
    if(jump_pressed)
    {
        jump_pressed = false;
        rb.AddForce(0, 10, 0, ForceMode.VelocityChange);
        // etc...
    }
}


因此,您只需处理Update中的所有Input逻辑,然后在固定Update中执行其余的逻辑。

当然,在FixedUpdate中需要将jump_pressed设置为false,因为否则它将保持为多个FixedUpdates。

edit2:我再次看了你的代码。无论做什么,无论是在FixedUpdate还是Update中,都不要在Time.deltaTime中使用AddForce

AddForce将操纵速度。在每个PhysicsUpdate中使用速度来移动变换。但是PhysicsUpdate / FixedUpdate尝试以(几乎)固定的速率运行,而Time.deltaTime为您提供了最后一个(更新)帧的经过时间。

如果您自己移动转换(position += ...)-请使用Time.deltaTime。但是在使用AddForce时不要使用它。

08-26 19:08