我正在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
这是〜0.23
最低的跳跃使它达到约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时不要使用它。