Unity 5:如何自然减速刚体而不是突然停止

3
我正在使用这个:

void Update(){
    if(leftJoystick){
        rb.AddRelativeForce(0, 0, 400f, ForceMode.Impulse);
    }
}

要让我的角色在空中前进(使用喷气背包)。当我松开操纵杆时,我的角色会立即停下。我的想法是让角色在摇杆释放后继续向前移动,并逐渐放慢速度直至停止。看起来很傻,好像我的角色撞到了墙上一样。我应该使用什么力量/速度/变换,以便在我松开操纵杆后物理学可以使我的角色减速?
我的刚体设置如下:
质量:100 阻力:0 角阻力:0.05 使用重力 不是运动学的 插值:插值 碰撞检测:离散 冻结位置:无 冻结旋转:所有
角色还具有一个胶囊形碰撞器,不是触发器,也没有物理材料。
编辑:这是完整的代码,您可以查看是否存在代码冲突。
using UnityEngine;
using System.Collections;
using UnityStandardAssets.CrossPlatformInput;

public class JetpackController : MonoBehaviour{

    Rigidbody rb;

    // controller axes
    [SerializeField]
    public string speedAxis = "Vertical";
    public string rotateAxis = "HorizontalRotate";

    [SerializeField]
    public float forwardSpeed;
    public float upSpeed;
    public float rotateSpeed;
    public float rotationIgnoreZone;
    public float MAX_HEIGHT;

    float speedInput;
    float rotateInput;
    public bool leftJoystick;
    public bool rightJoystick;

    ParticleSystem jetpackFire1;

    Vector3 originalGravity;

    // access Joystick script in Standard assets to detect when right joystick is held down
    Joystick joystick_left;
    Joystick joystick_right;

    void Start () {
        if (GetComponent<Rigidbody> ()) {
            rb = GetComponent<Rigidbody> ();
        } else {
            Debug.LogError ("Player needs to have a rigidbody.");
        }

        // get Joysticks
        if (GameObject.Find ("MobileJoystick_left").GetComponent<Joystick> ()) {
             joystick_left = GameObject.Find ("MobileJoystick_left").GetComponent<Joystick> ();
         } else {
             Debug.LogError ("Either gameobject with name 'MobileJoystick_right' does not exist in the scene or it does not have script called Joystick.cs attached to it.");
        }
        if (GameObject.Find ("MobileJoystick_right").GetComponent<Joystick> ()) {
            joystick_right = GameObject.Find ("MobileJoystick_right").GetComponent<Joystick> ();
        } else {
            Debug.LogError ("Either gameobject with name 'MobileJoystick_right' does not exist in the scene or it does not have script called Joystick.cs attached to it.");
        }

        jetpackFire1 = GameObject.Find("JetpackFire1").GetComponent<ParticleSystem> ();
        jetpackFire1.playbackSpeed = 5.0f;

        originalGravity = Physics.gravity;
    }

    void FixedUpdate () {

        GetInput ();

        // move forward and backward according to left joysticks input
        if(leftJoystick){
            // left joystick held down
            rb.AddRelativeForce(0, 0, forwardSpeed*speedInput, ForceMode.Impulse);
        }

        // if right joystick is used
        if (rightJoystick) {
            jetpackFire1.Play ();

        if (transform.position.y < MAX_HEIGHT) {
            // allow going up
            //rb.AddRelativeForce (0, upSpeed, 0, ForceMode.Impulse);
            rb.AddForce(transform.forward * forwardSpeed);
        } else if (transform.position.y >= MAX_HEIGHT) {
            // prevent player to go any further up and also falling
            Physics.gravity = Vector3.zero; // no gravity to prevent player from falling
            rb.velocity = Vector3.zero;
        }
            // rotate
            // always keep rotating (player can go past look at joystick dir)
            if (rotateInput >= rotationIgnoreZone || rotateInput <= -rotationIgnoreZone) {
                transform.Rotate(Vector3.up * rotateInput, Time.deltaTime * rotateSpeed);
            }
    } else {
            jetpackFire1.Stop ();
            // if right joystick is released
            Physics.gravity = originalGravity; // normal gravity -> player can fall
        }

    } 

public void GetInput(){
    speedInput = CrossPlatformInputManager.GetAxis (speedAxis);
    rotateInput = CrossPlatformInputManager.GetAxis (rotateAxis);
    // access Joystick.cs script to grab wether right joystick is pressed or not
    leftJoystick = joystick_left.leftJoystickPressed;
    rightJoystick = joystick_right.rightJoystickPressed;
}

}


1
我唯一能想到你可能停止刚体的地方是当 transform.position.y >= MAX_HEIGHT 时。你能检查一下是否进入了那个 if 语句吗? - Serlite
我在那个if语句中添加了Debug.Log("Can you see me?")来检查它何时触发。正如预期的那样,它只有在玩家的y位置超过15(MAX_HEIGHT = 15f)时才会触发。如果我在超过y位置15之前释放摇杆,问题仍然存在。 - Jonathan
2
当它们超过最大高度时,您会停止速度。也许当它们接近最大高度时,您应该Lerp Y方向速度,并允许水平速度正常运行。 Lerp将模拟包的“缺氧”状态,并防止它们达到最大高度时出现相同的“撞墙”感觉。 - Chuck Savage
3个回答

2

暂时无法评论

就像J.Small所说的那样,您可以将速度乘以大约0.95的数字来缓慢减慢刚体的速度。如果您将乘法放在Update方法中,建议您将~0.95数字与Time.deltaTime相乘,这样速度降低将与经过的时间成比例。

void Update(){
    if(leftJoystick){
        rb.AddRelativeForce(0, 0, 400f, ForceMode.Impulse);
    }

    if(noJoystick){
        rb.velocity = rb.velocity * 0.95f * Time.deltaTime;
        //Or: rb.velocity.x
    }
}

如果您想以更可配置的方式减慢刚体的速度,也可以施加少量的力而不是乘以速度(如果您将它放入每帧调用一次的Update中,则数量应该基于Time.deltaTime),但上述方法更容易。


2
答案已经过时了,但是在0.95后面缺少一个f,因为它是一个浮点数。 - William Wolseley-Charles

2

我不是专业的编码人员,所以我不确定这个方法是否适用于每个人,但我尝试使用类似的方式来解决一个类似的问题。

    void FixedUpdate()
    {
        playerRigidbody.AddRelativeForce(Vector2.up * forwardInput * playerSpeed * Time.fixedDeltaTime);

        if (forwardInput <= 0)
        {
            playerRigidbody.velocity = playerRigidbody.velocity / 1.005f; // <-- This will gradually slow down the player when they're idle.
        }
    } 

0

你可以使用简单的线性减速。

void Update(){
    if(leftJoystick){
        rb.AddRelativeForce(0, 0, 400f, ForceMode.Impulse);
    }
    
    if(noJoystick){
        rb.velocity = rb.velocity * 0.9f;
    }
}

请注意,更新函数在帧更新时被调用,因此我建议将其放在FixedUpdate()函数中,这样慢速率就不会依赖于帧率。

尝试过了,但不幸的是它并没有起作用。似乎在我释放操纵杆后,速度立即变为0,因此没有什么可以乘以的了。 - Jonathan
1
Time.deltaTime丢失了;-) - H. Hess
同样的事情,速度直接降为0。 - Gozmetaiemax
如果您只是像@H.Hess所说的那样包含Time.deltaTime,那么可以将其留在update()中,因为Time.deltaTime是上一帧和当前帧之间的时间,这使得游戏帧独立,并且无论fps如何都会以相同的速度运行。 - Noah

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接