查看: 2131|回复: 0
打印 上一主题 下一主题

[其他] 实现火炮自动弹道计算

[复制链接]
may    

8830

主题

81

听众

7万

积分

首席设计师

Rank: 8Rank: 8

纳金币
52336
精华
343

最佳新人 热心会员 灌水之王 活跃会员 突出贡献 荣誉管理 论坛元老

跳转到指定楼层
楼主
发表于 2016-4-24 23:58:26 |只看该作者 |倒序浏览
        玩过战舰世界的玩家都能体会到,战舰世界那种玩家视角旋转与炮塔旋转相互独立的控制方法十分的适合战舰这类拥有巨大数量舰炮的单位。具体的控制是由玩家控制视野,用视野的中心来定位炮击位置,而炮塔则会自动转向玩家瞄准的方向,炮管也会自动的升到计算好的炮击仰角。接下来就将介绍在Unity中实现这种控制方法的过程。一、视野控制
        控制视野的移动十分简单,在摄像机上附加一个能够根据输入进行旋转的脚本即可。除此之外,为了后面进行炮击位置测定,也要在这个摄像机的脚本上添加一个射线碰撞检测,由屏幕中央向游戏中射线,在检测到地面时,返回碰撞点的坐标,提供给炮塔。

二、炮塔控制

        比起视野控制,炮塔控制就显得复杂得多。由于炮塔的射击角度并不是由玩家决定,而是由电脑计算得出,所以这里还需要一个瞄准目标的解决方案。这里分为两个部分来解决,水平旋转和垂直旋转。

        1.水平旋转
        水平旋转主要由炮塔本体进行关于y轴的旋转,最终的方向是面向炮击点。这里使用了一个简单的计算方法,使用一个一直面向炮击点的辅助物体来确定正确的localEulerAngles,再获取这个值应用给炮塔。这样炮塔就可以确定向哪个方向开炮了。
      
        2.垂直旋转
        垂直旋转是最复杂的一步,这里忽略炮弹在飞行中的空气阻力来简化计算过程。
        由于炮弹在空中做斜抛运动,我们可以使用抛物线方程来建立炮弹在射击面上的运动图像。
        
        file:///C:/Users/CYM/AppData/Roaming/Tencent/QQ/Temp/BAC0C8EC97154787BC6BD3CE9BBE56FF.pngfile:///C:/Users/CYM/AppData/Roaming/Tencent/QQ/Temp/BAC0C8EC97154787BC6BD3CE9BBE56FF.pngfile:///C:/Users/CYM/AppData/Roaming/Tencent/QQ/Temp/BAC0C8EC97154787BC6BD3CE9BBE56FF.png
        将t用x表示,并带入y的表达式,消去变量t。再经过简单的代数变化,能够化为下面的等式:
        
        利用求根公式,可以得到如下公式:
        
        
        可以再进行一步化简,得到最终公式:
        
        
        在代码中可以轻松实现这个公式的计算,由于炮弹发射时我们已经知道初速度v0,重力加速度g,炮弹落点在该坐标系中的x,y坐标,计算θ角只需要带入值即可。

        计算部分代码如下:
  1. float delta = Mathf.Pow(velocity, 4) - gravityAcceleration * (gravityAcceleration * x * x - 2 * y * velocity * velocity);
  2.         if (delta < 0)
  3.         {
  4.             Debug.Log("无法命中!");
  5.             return;
  6.         }
  7.         float theta1 = Mathf.Atan(((velocity * velocity) + Mathf.Sqrt(delta)) / (gravityAcceleration * x));
  8.         float theta2 = Mathf.Atan(((velocity * velocity) - Mathf.Sqrt(delta)) / (gravityAcceleration * x));
  9.         float angle = Mathf.Min(theta1, theta2);
复制代码

        如果Δ大于0,那么会有一大一小两个有效角度,可以根据需求选择较大的角或者较小的角来实现较高的弹道和较低的弹道。

        如果Δ等于0,这个唯一的解是45°,也就是理论上的极限射程。
        如果Δ小于0,说明目标地点已经处于炮击射程之外,无论以多大的射击仰角都无法击中目标。
        值得一提的是,Unity中提供的Mathf.Atan()函数返回的是弧度值,我们还要经过弧度到角度转换才能将其应用到炮管的仰角上。
        
        注意:如果将计算出的角度直接应用到炮塔上,会发现角度并不正确,当目标明显需要仰起炮管才能命中时会看到炮管向下旋转,并不能正确命中目标。经过观察和测试,发现了[color=rgb(85, 85, 85) !important]问题
所在。Unity中x轴的旋转,在x轴正方向上看向坐标系原点这个视野中是顺时针的,换句话说,当x轴旋转为30°时,炮管将向下旋转30°,旋转330°才是向上旋转30°。所以在处理旋转角度时,还要进行一个倒数的处理,才能让炮管转向正确的方向。由此也引导我发现了另外一个问题——抛物线所在坐标系的方向也不是我们猜想的y轴与世界坐标系y轴正方向相同,而是相反。我们带入坐标后真正计算的抛物线图像是会直接穿过地面,经过端距离再回到地面上的,与我们想要的弹道恰恰关于地平面对称。这也说明我们带入公式计算的y值,应该是一个与实际情况相反的值才能符合抛物线图像。

        故在使用上述方法时,需要带入的几个值,x为炮弹起始位置到落点位置的平面距离(即在计算距离前消除水平高度差),y为炮弹落点相对炮弹起始点的海拔差的相反数,velocity为炮弹初速度,gravityAccelerate为重力加速度。这样才能真正获得准确的炮弹射出仰角。


        计算出仰角再将其应用到炮管上即可。


三、过渡动画
        如果炮塔设定旋转速度不快,无法跟随镜头进行目标瞄准。可以为炮塔添加一个自动旋转函数,在FixedUpdate()中调用,并使用变量,将目标的旋转角度记录下来,使用插值函数来实现炮塔的平滑旋转和瞄准,获得更好的效果。



分享到: QQ好友和群QQ好友和群 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
转播转播0 分享淘帖0 收藏收藏0 支持支持0 反对反对0
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

手机版|纳金网 ( 闽ICP备2021016425号-2/3

GMT+8, 2025-2-7 17:47 , Processed in 0.069315 second(s), 28 queries .

Powered by Discuz!-创意设计 X2.5

© 2008-2019 Narkii Inc.

回顶部