这涉及到拦截导弹的自动跟踪。最近看到一个有趣的自动跟踪算法,Python的简单模拟版,分享给大家。
在我们设计2D射击游戏时,经常会用到自动跟踪算法。这个听起来很高大上的东西,其实并不是军事科学的专利。如果用数学方法求解,就需要解微分方程。
没有一些数学基础,这个很难算出来。但是我们有了电脑就不一样了。借助计算机极快的运算速度,利用微分的思想和一点简单的三角学知识就可以实现。
好了,话不多说,我们来看看它的算法原理,看图:
因为后面要用pygame来演示,他的坐标系是Y轴下的,所以这里我们也用Y轴下的坐标系。
算法的大致思路是根据上图将时间t分成足够小的片段(例如1/1000,时间片越小越精确),并为每个片段构造三角形,从而计算出下一个时间片内导弹的方向(即a)和距离(即vt=|AC|)。这时目标在第二个时间片内移动了,刚计算出来。
假设导弹和目标的初始坐标分别为(x1,y1)和(x,y),构造一个直角三角形ABE。这个三角形是用来求 A的正弦和余弦值的,因为vt是我们自己设定的,所以我们需要计算A点到C点的X和Y坐标分别移动了多少。移动值是AD和CD的长度,这两个可以分别用cosa和sina乘以vt。
Sina和cosa、正弦对比斜率、余弦相邻对比斜率和斜边可利用两点距离公式计算,即:
因此
AC的长度是导弹的速度乘以时间|AC|=vt,然后就可以计算出AD和CD的长度,所以这个时间片过去后,导弹应该出现在新的位置C,它的坐标是旧点A的X加上AD,Y减去CD。
所以,C点的新坐标是:
只要你一直重复这个操作,嗯,为了更形象,把第一个时间片和第二个时间片放在一起看一下:
第一个是时间片构造的三角形是ABE。一个时间片后,目标从B点到D点,此时导弹在C点,于是构造了一个新的三角形CDF,可以重复刚才的计算过程。
图中的角度b是导弹需要旋转的角度。实际上,只需要在每个时间片上校正导弹的方向。具体怎么改变导弹的方向,不是我们需要研究的问题。
好了,因为最近在用Python的pygame库做小游戏,我们就用pygame来演示一下这个效果,效果如下:
简单的代码如下:
importpygame,sysfrommathimport * py game . init()screen=py game . display . set _ mode((800,700),0,32)missile=py game . image . load(' element/red _ pointer . png ')。convert_alpha()x1,y1=100,初始发射位置600#导弹速度=800#导弹速度时间=1/1000#每个时间片的长度Clock=py game . time . Clock()old _ angle=0 while true:foreventingpygame . event . get()。如果事件。type==pygame。退出:sys。退出()时钟。tick (300) x,y=pygame。老鼠。get _ pos () #获取鼠标的位置,鼠标与目标的距离=sqrt (pow (x1-x,2) pow (y1-)。2) #两点距离公式section=velocity*time#每个时间片要移动的距离Sina=(Y1-y)/Distance Cosa=(x-x1)/Distance angle=atan2(y-Y1,x-x1) #两点线段的圆弧值x1,y1=(x1 section * Cosa,Y1-section * Sina)d _ angle=degrees(angle)#弧度到角度屏。blit(缺失,(x1-缺失。get _ width(),Y1-导弹。GET _ HIGH()/2))DIS _ ANGLE=D _ ANGLE-OLD _ ANGLE # DIS _ ANGLE是需要换到下一个位置的角度。old_angle=d_angle#更新初始角度pygame.display.update()。
如果只把导弹看成一个质点,那么上面的算法就足够了。我没有旋转导弹,因为一个粒子是不需要旋转的,当然如果你加载一个小的导弹图片的时候不旋转似乎也不是问题。
但是在pygame中做旋转并不容易(可能是我无知)。好吧,我们先把图片换成矩形,再加上旋转功能,看看效果如何。
missiled=pygame . transform . rotate(missile,-(d _ angle))screen . blit(missiled,(x1-missile.get_width()、y1-missile.get_height()/2))
因为图片的坐标点是其左上角的点,如果我们想把图片的坐标固定在箭头的尖端,那么我们可以把图片的实际打印位置X减少图片的长度,宽度Y减少一半。
但实际操作效果并不好:
一般是同一个方向,但是图片箭头的尖点并不总是跟着鼠标。为什么?经过我的研究(因为这个问题没有解决所以没有发表),
我发现是这张图的旋转机制。让我们看看旋转后的图片是什么样的:
旋转后的图像变成蓝色范围,根据旋转角度的不同,图像的大小也不同。我们来看看90的旋转:
我们发现旋转后的图像不仅放大了区域,还改变了导弹头部的位置。那么应该如何解决这个问题呢?其思路是,每次旋转图片后,找到旋转图片的头部位置(图中绿色箭头点),然后将绿色图片的打印位置分别移动两个头的距离,使旋转后的导弹头部与我们参与操作的实际导弹头部位置对齐。运动之后,应该是这样的:
这样两个导弹头的指向就一致了。接下来,我们分析寻找旋转的导弹头的算法。根据旋转角度的不同,不同象限的旋转角度的参数是不同的,所以我们可以分为这四种情况。
1.2象限:
象限3和4,它的旋转只有正负0-180,所以象限3和4是负角。
当图片显示时,我们移动它。
screen.blit(missiled,(x1-width (x1-C[0]),y1-height/2 (y1-C[1]))
(x1-宽度,y1-高度/2)这里实际上是上图中的(x1,y1)。
所以最后我们加上相关的算法代码,效果很完美。
大功告成,最后附上所有算法代码:
importpygame,sysfrommathimport * pygame . init()font 1=pygame . font . sys font(' microsoftyaheim microsoftyaheiui '23)textc=font1.render('*,True,(250,0,0))screen=pygame . display . set _ mode((800,700),0,32)missile=pygame . image . load(' element/rect 1 . png ')。convert _ alpha()height=Missile . get _ height()width=Missile . get _ width()py game . mouse . set _ visible(0)x1,y1=100,初始发射位置600#导弹速度=800#导弹速度时间=1/1000#每个时间片的长度Clock=py game . time . Clock()A=()B=()C=()While True:foreventingpygame . event . get()。如果事件。type==pygame。退出:sys。退出()时钟。tick (300) x,y=pygame。老鼠。get _ pos () #获取鼠标的位置,鼠标与目标的距离=sqrt (pow (x1-x,2) pow (y1-)。2) #两点距离公式section=velocity*time#每个时间片要移动的距离Sina=(y1-y)/distance cosa=(x-x1)/distance angle=atan2(y-y1,x-x1) #两点间线段的弧度值方了=度(角度)#弧度转角度x1。y1=(x1 section*cosa,y1-section * Sina)missiled=py game . transform . rotate(missile,-(方了))if0=-方了=90:A=(width*cosa x1-width,y1-height/2)B=(A[0] height*sina,A[1]height * COSA)if90-方了=180:A=(x1-width,y1-height/2 height *(-COSA))B=(x1-width height * Sina,y1-height/2)if-90=-
最后
这是用Python实现的简单的自动跟踪算法,真正的导弹拦截跟踪算法要复杂得多。
审计彭静
标签:X导弹算法