【Unity】预计算刚体运动轨迹

 

像以前玩过的TNT、弹弹岛、百战天虫这样的游戏,都会有一个弹道路线提示,而通过施加力或速度,可以控制刚体移动,刚好前段时间在商店看到一个插件(脚本),可以通过刚体信息、速度、受力等信息,计算出刚提的运动轨迹,与刚体实际运动轨迹完全相符(计算方式可能与Unity物理引擎计算方式类似或相同),可以实现预计算弹道轨迹等功能。

免费插件链接:Calculate Trajectory  Calculate Trajectory | Physics | Unity Asset Store

下面解析模拟物理计算代码,做了一些修改(其中有两处公式不明白,欢迎大佬告知):

public static class RigidbodyExtension
    {
        //returns返回值:运动轨迹点位位置及该点的速度
        //stepCount:运动轨迹点位数量,数量越多,得到的轨迹越远,计算量也就越多
        //calculateCountPerStep:每相邻点位之间,模拟的次数,次数越多,相邻点位距离越远(轨迹也会随之变远),但精度会降低
        //addedSpeed:要增加的速度
        //addedForce:要施加的力
        public static Vector3[][] CalculateMovement(this Rigidbody that, int stepCount, int calculateCountPerStep, Vector3 addedSpeed, Vector3 addedForce)
        {
            //计算刚体现有速度
            Vector3 vel = !that.isKinematic ? that.velocity : Vector3.zero;
            //计算刚体重力
            Vector3 gra = (that.useGravity && !that.isKinematic) ? Physics.gravity : Vector3.zero;
            //根据所需数据计算轨迹
            return CalculateMovement(that.transform.position, vel, gra, stepCount, calculateCountPerStep, addedSpeed, addedForce, that.mass, that.drag);
        }

        //returns返回值:运动轨迹点位的位置与速度
        //position:刚体起始位置
        //velocity:刚体原有速度
        //gravity:刚体重力
        //stepCount:点位数量
        //calculateCountPerStep:模拟精度
        //addedSpeedparam:增加速度
        //addedForceparam:增加受力
        //mass:刚体质量
        //drag:所受阻力
        public static Vector3[][] CalculateMovement(Vector3 position, Vector3 velocity, Vector3 gravity, int stepCount, int calculateCountPerStep, Vector3 addedSpeed, Vector3 addedForce, float mass, float drag)
        {
            Vector3[][] movePath = new Vector3[stepCount][];
            //将受力转化为速度(动量公式 F*t = M*V)
            Vector3 addedVel = addedForce / mass * Time.fixedDeltaTime;
            //速度和
            Vector3 vel = velocity + addedSpeed + addedVel;
            //点位的位置和该位置下的速度
            Vector3[] calc = new Vector3[] { position, vel };
            //依次计算所有点位
            for (var i = 0; i < stepCount; ++i)
            {
                //使用上一点位的位置和速度信息,计算下一点位
                calc = CalculateNewPos(calc[0], calc[1], gravity, drag, calculateCountPerStep);
                //记录点位位置速度信息
                movePath[i] = new Vector3[2] { calc[0], calc[1] };
            }
            //返回值
            return movePath;
        }

        static Vector3[] CalculateNewPos(Vector3 pos, Vector3 vel, Vector3 gra, float drag, int count)
        {
            //数据转化
            //物理刷新时间间隔
            var dt = Time.fixedDeltaTime;
            //所受重力转化为速度
            var graVel = gra * dt;
            //抵消掉阻力之后的受力系数(drag * dt:所受阻力)(不懂这个计算方式)
            var dragDt = 1 - drag * dt;
            //确保系数不为负
            dragDt = dragDt < 0 ? 0 : dragDt;
            //模拟速度位置
            for (int i = 0; i < count; i++)
            {
                //新速度 = (原速度 + 重力产生的速度) * 系数
                vel = (vel + graVel) * dragDt;
                //新位置 = 原位置 + 速度产生的位移 + 重力产生的位移(不懂0.5的作用)
                pos = pos + vel * dt + 0.5f * graVel * dt;
            }
            return new Vector3[] { pos, vel };
        }
    }

根据Rigidbody对Rigidbody2D也做了扩展,计算方式与上面代码相差不大,就不重复粘贴了,Rigidbody2D多了一个bodyType属性:
Rigidbody2D.bodyType:

Dynamic 动态
对重力和施加力做出反应,包括其他Rigidbody2D接触产生的力
动态Rigidbody2D将与所有其他Rigidbody2D产生碰撞

Kinematic运动学
对重力和施加力无反应,包括其他Rigidbody2D接触产生的力(也无反应)
可以通过设置Rigidbody2D.velocity或Rigidbody2D.angularVelocity或显式重新定位来移动
运动Rigidbody2D只会与动态Rigidbody2D碰撞
如果Rigidbody2D.useFullKinematicContacts设置为true,在这种情况下它将与所有Rigidbody2D碰撞

Static静态
对重力或施加力无反应,包括与任何其他Rigidbody2D的接触(也无反应)
永远不会移动
静态Rigidbody2D只会与动态Rigidbody2D碰撞
如果Rigidbody2D.useFullKinematicContacts设置为true,在这种情况下它将与所有Rigidbody2D碰撞

  • 2
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

萧然CS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值