半吊子
日历
网志分类
· 所有网志 (82)
站内搜索
友情链接
· 歪酷博客
· 我的歪酷 非非共享界

订阅 RSS

0069827

歪酷博客

« 上一篇: 当一个妇科医生(4)——浅浅的剖析神秘的AI 下一篇: 日本队第二个进球不是手球(不懂的进来扫盲) »
天地间有我 @ 2004-08-08 22:07

       AI的问题似乎说不完,上一次我们分析RPG和SLG中的AI设计,其实重点还是RPG中的最简单的AI的设计。SLG中一些复杂的问题还是没有讨论的。昨天在Blog上发了文章之后,我玩了一个很早以前下载的小游戏“是男人就撑过20秒”。相信很多朋友都玩过这个小游戏。满屏幕的子弹,但我在游戏中发现一个问题:就是他的子弹有一点跟踪性。忽然我觉得这事一个很有意思的设计。索性就来分析分析“跟踪弹”。

       至于军事上是怎么形成跟踪弹的,我不太了解似乎好像的确有人跟我说过是GPS什么的,还有人跟我说过是热感什么的。这些方法我们肯定是用不上的了,但是有一些数学原理还是可以使用的。我们就先来复习一下三角函数:

      sin(Ө)=a/c       对边/斜边         在1,2项限为正,3,4项限为负
      cos(Ө)=b/c      邻边/斜边         在1,4项限为正,2,3项限为负
      tan(Ө)=a/b      对边/邻边         在1,3项限为正,2,4项限为负

之后的工作就是联立数据结构了:
       typedef struct elemtype
               {
               double  x,                /*记录子弹的横坐标*/
                           y,                /*记录子弹的纵坐标*/
                           speed;         /*记录子弹的速度*/
               kind     attribute;
               }elemtype;

      至于kind的类型,他对应的一张“子弹种类表”。当子弹击中我方之后,通过查表得到,这次击中伤血的多少,爆炸的效果,效果音等等,每种子弹的特有属性。
我们做如下的数据定义:
       elemtype        导弹,         /*假设只有一枚*/
                             导弹新状态;
       elemtype        飞机,         /*由此可见定义kind属性之后,此结构的通用性*/
                             飞机新状态;

并建立如下的坐标系:

      公元××××年××月××日,空军部队某部的导弹发射井在相对坐标的(x0,y0)出,这时,雷达探测到,在(x1,y1)的位置上出现了一架飞机,导弹发生井立刻发射了一枚地对空导弹,我们的故事从这里开始……

       此时在坐标平面上出现一个三角形。斜边就是导弹的飞行速度,通过物理运动的合成性原理,我们把运动分解到坐标轴上,我们默认,在两个记速点的中间的运动时匀速的——所谓下一个记速点,就是speed改变一次——再根据运动学公式得到:

导弹.x += 导弹.speed * cos(THETA) * 最小时间单位;
导弹.y += 导弹.speed * sin(THETA) * 最小时间单位;

THETA就是导弹向飞机发射过来的时候,导弹于飞机所在位置的夹角。

      而这个夹角时必须得到的。因为在计算这个夹角的时候,我们使用的函数是:
THETA=arctan(tan(THETA))

得到THETA的值方法很简单,知道得到三角形纵横两边的长度就好了。这是三角形的于x轴平行的边为:
double        DELTAx = 飞机.x - 导弹.x;

于y轴平行的边为:
double        DELTAy = 飞机.y - 导弹.y;

在数学上只要在用DELTAy/DELTAx就可以得到tan(THETA)了。但在编程时候,是绝对不行的。我们要考虑到分母为0的情况。也就是导弹于飞机处在同一铅垂上。

       if ( DELTAx == 0 )
               {
               if( 飞机.y >= 导弹.y )
                       {
                       DELTAx = 0.0000001;
                       }
               else
                       {
                       DELTAx = -0.0000001;
                       }
               }

      虽然说分子为0在数学上是通过的,但在我们程序中已经出现了飞机和导弹不可能出现在同一铅垂上的设置了,我们也让他们两个不能出现在同水平线上。

       if( DELTAy == 0 )
               {
               if( 飞机.x >= 导弹.x )
                       {
                       DELTAy = 0.0000001;
                       }
                   else
                       {
                       DELTAy = -0.0000001;
                       }
               }

     现在我们要做的就是开始确定导弹在这个记速段的飞行角度:

       double        tanTHETA=fabs(deltay/deltax);
       double  atanTHETA=atan(tanTHETA);
       if ((DELTAx>0) && (DELTAy>0))
               {
               THETA = atanTHETA;
               }
       if ((DELTAx<0) && (DELTAy>0))
                   {
               THETA = π-atanTHETA;
               }
       if ((DELTAx<0) && (DELTAy<0))                     
               {
               THETA = π+atanTHETA;
               }
       if ((DELTAx>0) && (DELTAy<0))
               {
               THETA = 2π-atanTHETA;
               }

      其中π=3.14159265358939723846…………至于要精确到什么地方这就是随便的事情了;)好了,方向已经确定了,那就开始追吧……

     下面的一个工作就是根据飞机飞行位置定时给出飞机最新的位置,以调整导弹的飞行方向。
下面给出伪代码:
       
       记时器归零;
       得到:飞机、导弹的初始状态;
       while (1)
               {
               计算THETA;
               导弹新状态.x = 导弹.x + 导弹.speed * cos(THETA) * 最小记时单位;
               导弹新状态.y = 导弹.y + 导弹.speed * sin(THETA) * 最小记时单位;
               得到:飞机新状态;
               if (撞击判断(导弹 , 导弹新状态 , 飞机 ,飞机新状态))
                       {
                       成功拦截;
                       break;
                       }
               if ((导弹撞上阻挡物) || (其他失败条件))
                       {
                       拦截失败;
                       break;
                       }
               if (飞机撞上阻挡物))
                       {
                       飞机自毁;
                       break;
                       }
               记时器++;
               导弹新状态.speed = 导弹速度计算(记时器 , 导弹.speed);
               导弹=导弹新状态;
               飞机=飞机新状态;
               }

     以上的伪代码给出了一个飞机和导弹的追击函数。以上的函数中,出现两个在前面没有解释的模块。撞击判断()和导弹速度计算()。

     其中导弹速度计算()是比较容易实现的函数,我们可以用时间做为变量,设计一个反函数或者是一个斜率为负截距为正的线性函数这样就可以更真实的出现“强弩之末势不能穿芦槁”的物理和军事原理。也可以作为一个拦截失败的条件。下面一个要考虑的就是撞击判断()函数。这是一个高中解析几何的问题:已知线段1(导弹.x , 导弹.y)(导弹新状态.x , 导弹新状态.y)和线段2(飞机.x , 飞机.y)(飞机新状态.x , 飞机新状态.y),只要两个线段有交点,那在这个记速段里面飞机和导弹就会碰撞。

     以上是分析在XOY平面内的,定坐标原点的跟踪导弹的算法。其实关于原点的取法还有很多种,其中还有一种比较容易实现的是飞机本身是原点。但每种原点的取法,在放到卷轴中的时候,存在一个相对运动的问题。这就是比较实际的问题了,我们这次只讨论碰撞,这个问题以后在谈。

最新评论

2004-08-09 00:29

怎么看都不懂,这玩艺文科免看吧?


2004-08-09 17:34 网址: http://dev365.ycool.com/

可能需要考虑一些附加的东西,按照当前飞机坐标进行运算有可能存在缺陷:
1)探测器需要时间。无论多普勒还是红外或其他,得到的目标地址是以前的位置,不是当前的。
2)即使不考虑探测的延迟,导弹飞行和机动也需要时间,按当前模型,导弹将在机尾掠过。(以前F19,F117游戏中的导弹就用这种数学模型,因此你就很容易躲过,比如,你预测导弹路径,然后做一个大回转,导弹就在你头顶呼啸而去)

因次建议保存前一次的目标飞行器位置,再根据最新位置推测下一时间的位置。如果知道目标飞行器参数,那么在一系列采样点的基础上可以预测对方飞行路径以实现精确打击,毕竟飞行器需要遵循物理原则,直角转弯是不可能的嘛。对游戏设计而言就容易许多,只要预测直线就够了。另外,很多时候要避免三角运算,CPU时间是非常宝贵的。

小小的建议. :)



红移

2004-08-09 18:12

喜欢想你这样勤于思考并open自己想法的人。坚持下去你一定会有个很好的将来。祝福一下。:)



威尔森

2004-08-09 23:05

你很好,象你学习


2004-10-18 16:17 网址: http://fivestone.ycool.com/

“20秒”里应该是子弹生成的一瞬间根据飞机位置确定直线轨迹的
当然也有“诱导弹”,实时变轨,不过在垂直方向上的加力分量应该有个最大值限制

而且真正的导弹cpu没有必要算什么arctan,只需要在历史轨迹上做时间微分就可以了


评论 / 个人网页 / 扔小纸条
* 昵称

已经注册过? 请登录

新用户请先注册 以便能显示头像及追踪评论回复

Email
网址
* 评论
表情
 


 

分类小组论坛
杂谈 , 娱乐、八卦 , 文学、艺术 , 体育 , 旅游、同城 , 象牙塔 , 情感 , 时尚、生活 , 星座 , 科技

请注意遵守中华人民共和国法律法规, 如威胁到本站生存, 将依法向有关部门报告, 同时本站的相关记录可能成为对您不利的证据.

相关法律法规
全国人大常委会关于维护互联网安全的决定
中华人民共和国计算机信息系统安全保护条例
中华人民共和国计算机信息网络国际联网管理暂行规定
计算机信息网络国际联网安全保护管理办法
计算机信息系统国际联网保密管理规定