如何让抛射物弧形转向

3
我有一门能以抛物线弧线发射子弹的大炮。现在当我开火时,子弹保持与从大炮中发射时相同的旋转状态。

animation

如何使子弹的旋转跟随其穿越空气的弧线?
我尝试了以下作为运行在子弹上的脚本:
展示1
public class PointingBehaviour:MonoBehaviour
{
    private Rigidbody rb;

    private void Awake()
    {
        rb = GetComponent<Rigidbody>();
    }

    public void Update()
    {
        transform.up = rb.velocity;
    }
}

这个方法工作得相当不错,但我看到对象存在的第一帧会有轻微的闪烁(我认为这是因为此时速度仍为0),并且对象一旦着陆就会失去控制地旋转。

animation

通过以下步骤,我解决了开始时的闪烁问题和落地后旋转的问题。

public class BulletController : MonoBehaviour
{
    private Rigidbody _rb;
    private bool _followArc;
    private bool _firstFrame;
    private void Start()
    {
        _rb = GetComponent<Rigidbody>();
        _firstFrame = true;
        _followArc = true;
    }

    public void LateUpdate()
    {
        if (_followArc && !_firstFrame)
            transform.up = _rb.velocity;
        _firstFrame = false;
    }

    public void OnCollisionEnter(Collision collision)
    {
        _followArc = false;
    }
}

但是,如果我在空中碰到了什么东西,它就会停止沿着弧线移动,只是自由地翻滚直到着陆。如何才能以“正确”的方式做到我想做的事情?


因为人们想要看到它,这里是生成子弹的代码。

public class TankController : MonoBehaviour
{

    private Transform _barrelPivot;
    private Transform _bulletSpawn;
    public GameObject Bullet;
    public float FirePower;
    public float RotationSpeed;
    public float TiltSpeed;

    private void Start()
    {
        _barrelPivot = GetComponentsInChildren<Transform>().First(x => x.CompareTag("BarrelPivotPoint"));
        _bulletSpawn = GetComponentsInChildren<Transform>().First(x => x.CompareTag("BulletSpawn"));
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            FireCannon();
        }
        //(SNIP) Handle turning left and right and pivoting up and down.
    }

    private void FireCannon()
    {
        var newBullet = SpawnBullet();
        var rb = newBullet.GetComponent<Rigidbody>();
        rb.AddForce(_bulletSpawn.up * FirePower, ForceMode.Impulse);
    }

    private GameObject SpawnBullet()
    {
        var newBullet = (GameObject) Instantiate(Bullet, _bulletSpawn.position, _bulletSpawn.rotation);
        newBullet.transform.localScale = Bullet.transform.localScale;
        return newBullet;
    }
}

我会检查速度,如果弹丸速度较慢,则将_followArc设置为false,如果速度较快,则将其改回。 - Adrian Krupa
@JoeBlow不要说“永远不要使用”。LateUpdate用于固定计算,例如物理。您无法将基于物理的运动与变化的步骤集成在一起。您只需要知道自己在做什么。 - Adrian Krupa
@JoeBlow 我只是生成了子弹并对其施加了冲量力。我已经在问题中更新了代码。此外,我有点同意你的LateUpdate语句,我不应该在这里使用它,但是有很多合法的理由可以使用它。例如,如果我在飞行中为子弹添加了更多的力(一个在Update中应用的飞行转向系统),并且我想要一个固定的追踪摄像机,它会平移但不会旋转(所以我不能将相机作为子对象绑定到子弹上),那么相机的逻辑应该放在LateUpdate中,不是吗? - Scott Chamberlain
所以我不同意“永远不要使用LateUpdate”,但我同意“除非更新的目标是更新相机的Translation,否则永远不要使用LateUpdate”。 - Scott Chamberlain
请停止评论垃圾信息,您本可以轻松编辑旧评论并合并它们,而不是每次都新建一个。如果您想聊天,该网站上有实际的聊天室可供使用。 - Scott Chamberlain
显示剩余5条评论
1个回答

2

我相信你的意思是 - 你的脚本exhibit1非常好用。

如果你仔细想一想,当你想要时只需要关闭那个行为即可。

在这种情况下,你认为“当它触地时该行为应该停止..我猜这就是你物理上的意思。

很容易关闭一个MonoBehaviour,正如你所知道的一样,只需要enabled = false;

所以,你有一些脚本,比如Bullet或者BulletBoss

在那里你将有一个私有变量PointingBehaviour pb,你只需要pb.enabled = false

(我不能告诉你“何时”做到这一点,这取决于你的游戏..所以可能是像“高度小于某个值时”或者“当我撞到东西时”之类的东西...可能与OnCollisionEnter有关。)

请注意 - 我相信你知道这一点 - 对于弹丸的指向行为,只需将其设置在切线上就足够了。

当你为这样的弹丸编写指向行为时,一个可爱而简单的事情是尝试将其轻轻地lerping到切线上。结果是令人惊叹的真实。接下来,也许添加一些随机的“摆动”效果,这非常像炸弹。令人惊讶的是,用户只能在几个帧中看到这样的事情。(下一步可能是真正的空气物理学!)

请注意,PointingBehaviour肯定应该成为它自己的脚本。你必须完全隔离行为。


关于提到的LateUpdate,永远不需要使用它。

Unity提供了一个“脚本执行顺序”系统(参见首选项菜单选项),如果确实想要在帧内排序。但唯一的原因可能是为了某种实验目的。

这有点像“使用全局变量” - 没有任何理由这样做。与任何代码一样,如果你必须按照给定的顺序执行某些操作,只需按顺序调用即可。


我只有在周末才有时间来处理它。如果我有机会尝试它并且没有其他人在那之前发布任何内容,我会接受它。 - Scott Chamberlain

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