游戏人工智能——聚集与避障

简介: 智能体只考虑哪些在检测盒内的障碍物。 1.初始的时候,要将游戏世界中所有的障碍物都迭代到内存中,并标记哪些在检测盒内的障碍物以作进一步分析,然后把所有已经标记的障碍物都转换到智能体的局部空间。 2.转换坐标后,那些x坐标为负值的物体将不被考虑,所以问题就变得简单多了,接下来必须要检测障碍物是否和检测盒重叠。使障碍物的包围半径扩大检测盒宽度的一半。然后测试该障碍物的y值是否小于这个值(即障碍物的包围半径加上检测盒宽度的一半)。此时,只剩下那些与检测盒相交的障碍物了。3.接下来我们找出离智能体最近的相交点。 再一次在局部空间中计算,第三步中扩大了障碍物的包围半径。用简单的线圆周相交测试

 实验二:聚集与避障

一、实验目的

掌握游戏中聚集与避障的人工智能算法,理解宽视野和有限视野的区别

二、实验仪器

Microsoft Visual Studio2019

三、实验原理及过程

//描述聚集与避障的算法原理

//描述程序实现时的思路包括对每个调用的API进行详细说明

智能体只考虑哪些在检测盒内的障碍物。

1.初始的时候,要将游戏世界中所有的障碍物都迭代到内存中,并标记哪些在检测盒内的障碍物以作进一步分析,然后把所有已经标记的障碍物都转换到智能体的局部空间。

2.转换坐标后,那些x坐标为负值的物体将不被考虑,所以问题就变得简单多了,接下来必须要检测障碍物是否和检测盒重叠。使障碍物的包围半径扩大检测盒宽度的一半。然后测试该障碍物的y值是否小于这个值(即障碍物的包围半径加上检测盒宽度的一半)。

此时,只剩下那些与检测盒相交的障碍物了。

3.接下来我们找出离智能体最近的相交点。

再一次在局部空间中计算,第三步中扩大了障碍物的包围半径。

用简单的线圆周相交测试方法可以得到被扩大的圈和x轴的相交点。

四、实验结果

image.gif编辑

image.gif编辑

image.gif编辑

image.gif编辑

五、实验心得(需包括有何不足如何改进)

//你认为目前的聚集与避障有什么不足之处,如何改进

程序的设计还有部分的不足,在避障方面还是有一部分小的瑕疵,在偶尔的时候没有进行到避障,但也是极少数的时候。

只有不断完善代码与算法进行合理与正确的计算。

六、主要代码

#include "main.h"

#include "time.h"

//---------------------------------------------------------------------------

/*

Book:           AI for Game Developers

Authors:        David M. Bourg & Glenn Seemann

Example:        Flocking, Chapter 4

*/

//---------------------------------------------------------------------------

#define          _TIMESTEP                                     0.0025

#define          _TOL                                               1e-10

#define          _FWDTIME                                     10

#define          _THRUSTFACTOR                                  1.0

#define     _CHASESETUP                                        true

#define          _SPAWN_AREA_R                                  100

#define          _MAX_NUM_UNITS                              20

#define          _UNIT_LENGTH                              4

#define          _OBSTACLE_RADIUS_FACTOR                    8

#define          _OBSTACLE_RADIUS                     _OBSTACLE_RADIUS_FACTOR * _UNIT_LENGTH

#define          _COLLISION_VISIBILITY_FACTOR 25

#define          _WIDEVIEW_RADIUS_FACTOR                          200

#define          _NARROWVIEW_RADIUS_FACTOR                    50

#define          _LIMITEDVIEW_RADIUS_FACTOR              30

#define          _SEPARATION_FACTOR                        5

#define          _BACK_VIEW_ANGLE_FACTOR                  1

#define          _FRONT_VIEW_ANGLE_FACTOR         1

#define          _NUM_OBSTACLES                               8

// Global Variables:

int                        FrameCounter = 0;

RigidBody2D        Units[_MAX_NUM_UNITS];

Vector                   Target;

Vector                   Obstacles[_NUM_OBSTACLES];

bool Initialize(void)

{

      int i;

      GetRandomNumber(0, _WINWIDTH, true);

                   

      for(i=0; i<_MAX_NUM_UNITS; i++)

      {    

             Units[i].fMass = 10;

             Units[i].fInertia = 10;

             Units[i].fInertiaInverse = 1/10;

             Units[i].vPosition.x = GetRandomNumber(_WINWIDTH/2-_SPAWN_AREA_R, _WINWIDTH/2+_SPAWN_AREA_R, false);

             Units[i].vPosition.y = GetRandomNumber(_WINHEIGHT/2-_SPAWN_AREA_R, _WINHEIGHT/2+_SPAWN_AREA_R, false);

             Units[i].fWidth = _UNIT_LENGTH/2;

             Units[i].fLength = _UNIT_LENGTH;

             Units[i].fHeight = _UNIT_LENGTH;

             Units[i].fOrientation = GetRandomNumber(0, 360, false);

             Units[i].CD.y = -0.12*Units[i].fLength;       Units[i].CD.x = 0.0f;                   // coordinates of the body center of drag

             Units[i].CT.y = -0.50*Units[i].fLength;       Units[i].CT.x = 0.0f;                    // coordinates of the propeller thrust vector

             Units[i].CPT.y = 0.5*Units[i].fLength;        Units[i].CPT.x = -0.5*Units[i].fWidth; // coordinates of the port bow thruster

             Units[i].CST.y = 0.5*Units[i].fLength;        Units[i].CST.x = 0.5*Units[i].fWidth;  // coordinates of the starboard bow thruster

             Units[i].ProjectedArea = (Units[i].fLength + Units[i].fWidth) * Units[i].fHeight;

             Units[i].Leader = false;

           

             if(i>_MAX_NUM_UNITS/2)

             {

                    Units[i].Interceptor = true;

                    Units[i].ThrustForce = _THRUSTFORCE*1.5f;

             } else {

                    Units[i].Interceptor = false;

                    Units[i].ThrustForce = _THRUSTFORCE;

             }          

      }

      for(i=0; i<_NUM_OBSTACLES; i++)

      {

             Obstacles[i].x = GetRandomNumber(_OBSTACLE_RADIUS*4, _WINWIDTH-_OBSTACLE_RADIUS*4, false);

             Obstacles[i].y = /*_WINHEIGHT/2;*/GetRandomNumber(_OBSTACLE_RADIUS*4, _WINHEIGHT-_OBSTACLE_RADIUS*4, false);

      }

      return true;

}

void DoUnitAI(int i)

{

           

             int          j;

             int          N;

             Vector     Pave;

             Vector     Vave;

             Vector     Fs;

             Vector     Pfs;

             Vector     d, u, v, w;

             double    m;

             int          Nf;

             bool InView;

             bool DoFlock = WideView || LimitedView || NarrowView;

             int          RadiusFactor;

             // begin Flock AI

             Fs.x = Fs.y = Fs.z = 0;

             Pave.x = Pave.y = Pave.z = 0;

             Vave.x = Vave.y = Vave.z = 0;

             N = 0;

             Pfs.x = 0;

             Pfs.y = Units[i].fLength / 2.0f;

             Nf = 0;

           

             for(j=1; j<_MAX_NUM_UNITS; j++)

             {

                    if(i!=j)

                    {

                           InView = false;

                           d = Units[j].vPosition - Units[i].vPosition;

                           w = VRotate2D(-Units[i].fOrientation, d);

                         

                           if(((w.y > 0) && (fabs(w.x) < fabs(w.y)*_FRONT_VIEW_ANGLE_FACTOR)))

                                  if(d.Magnitude() <= (Units[i].fLength * _NARROWVIEW_RADIUS_FACTOR))

                                         Nf++;

                           if(WideView)

                           {

                                  InView = ((w.y > 0) || ((w.y < 0) && (fabs(w.x) > fabs(w.y)*_BACK_VIEW_ANGLE_FACTOR)));

                                  RadiusFactor = _WIDEVIEW_RADIUS_FACTOR;

                           }

                           if(LimitedView)

                           {

                                  InView = (w.y > 0);

                                  RadiusFactor = _LIMITEDVIEW_RADIUS_FACTOR;

                           }

                           if(NarrowView)

                           {

                                  InView = (((w.y > 0) && (fabs(w.x) < fabs(w.y)*_FRONT_VIEW_ANGLE_FACTOR)));

                                  RadiusFactor = _NARROWVIEW_RADIUS_FACTOR;

                           }

                         

                           if(InView && (Units[i].Interceptor == Units[j].Interceptor))                  

                           {

                                  if(d.Magnitude() <= (Units[i].fLength * RadiusFactor))

                                  {

                                         Pave += Units[j].vPosition;

                                         Vave += Units[j].vVelocity;

                                         N++;

                                  }

                           }

                           // Separation Rule:

                           if(InView)//(w.y > 0) || ((w.y < 0) && (fabs(w.x) > fabs(w.y)*_BACK_VIEW_ANGLE_FACTOR)))

                           {                                

                                  if(d.Magnitude() <= (Units[i].fLength * _SEPARATION_FACTOR))

                                  {

                                         if(w.x < 0) m = 1;

                                         if(w.x > 0) m = -1;                                    

                                       

                                         Fs.x += m*_STEERINGFORCE * (Units[i].fLength * _SEPARATION_FACTOR) / d.Magnitude();

                                  }

                           }

                         

                    }

             }

           

             // Cohesion Rule:

             if(DoFlock && (N > 0))

             {

                    Pave = Pave / N;

                    v = Units[i].vVelocity;

                    v.Normalize();

                    u = Pave - Units[i].vPosition;

                    u.Normalize();

                    w = VRotate2D(-Units[i].fOrientation, u);

                    if(w.x < 0) m = -1;

                    if(w.x > 0) m = 1;

                    if(fabs(v*u) < 1.0f)

                           Fs.x += m * _STEERINGFORCE * acos(v * u) / pi;

             }

             // Alignment Rule:

             if(DoFlock && (N > 0))

             {

                    Vave = Vave / N;

                    u = Vave;

                    u.Normalize();

                    v = Units[i].vVelocity;

                    v.Normalize();            

                    w = VRotate2D(-Units[i].fOrientation, u);

                    if(w.x < 0) m = -1;

                    if(w.x > 0) m = 1;

                    if(fabs(v*u) < 1)

                           Fs.x += m * _STEERINGFORCE * acos(v * u) / pi;

             }

             // Chase the target if the unit is a leader

             if(Chase)

             {

                    if(Nf == 0)

                           Units[i].Leader = true;

                    else

                           Units[i].Leader = false;

                    if((Units[i].Leader || !DoFlock))

                    {                        

                           if(!Units[i].Interceptor)

                           {

                                  // Chase                                          

                                  u = Units[0].vPosition;

                                  d = u - Units[i].vPosition;

                                  w = VRotate2D(-Units[i].fOrientation, d);

                                  if(w.x < 0) m = -1;

                                  if(w.x > 0) m = 1;

                                  Fs.x += m*_STEERINGFORCE;

                           } else {

                                  // Intercept          

                                  Vector     s1, s2, s12;

                                  double    tClose;  

                                  Vector     Vr12;

                                  Vr12 = Units[0].vVelocity-Units[i].vVelocity; // closing velocity

                                  s12 = Units[0].vPosition - Units[i].vPosition; // range to close

                                  tClose = s12.Magnitude() / Vr12.Magnitude(); // time to close

                                  s1 = Units[0].vPosition + (Units[0].vVelocity * tClose);

                                  Target = s1;

                                  s2 = s1 - Units[i].vPosition;  

                                  w = VRotate2D(-Units[i].fOrientation, s2);

                                  if(w.x < 0) m = -1;

                                  if(w.x > 0) m = 1;

                                  Fs.x += m*_STEERINGFORCE;

                           }

                    }

             }

           

             // Collision avoidance (with static obstacles)

             Vector     a, p, b;          

           

             for(j=0; j<_NUM_OBSTACLES; j++)

             {

                    u = Units[i].vVelocity;

                    u.Normalize();

                    v = u * _COLLISION_VISIBILITY_FACTOR * Units[i].fLength;

                   

                    a = Obstacles[j] - Units[i].vPosition;

                    p = (a * u) * u;

                    b = p - a;

                    if((b.Magnitude() < _OBSTACLE_RADIUS) && (p.Magnitude() < v.Magnitude()))

                    {

                           // impending collision...steer away

                           w = VRotate2D(-Units[i].fOrientation, a);

                           w.Normalize();

                           if(w.x < 0) m = 1;

                           if(w.x > 0) m = -1;

                           Fs.x += m * _STEERINGFORCE * (_COLLISION_VISIBILITY_FACTOR * Units[i].fLength)/a.Magnitude();

                    }

             }

           

           

             // apply accumulated steering force

             Units[i].Fa = Fs;

             Units[i].Pa = Pfs;

             // end Flock AI

}

void UpdateSimulation(void)

{

      double    dt = _TIMESTEP;

      int          i;

     

      // initialize the back buffer

      if(FrameCounter >= _RENDER_FRAME_COUNT)

      {

             ClearBackBuffer();

             DrawObstacles();

      }

     

      // Update player controlled unit:  

      Units[0].SetThrusters(false, false, 1);

      Units[0].SetThrusters(false, false, 1);

      if (IsKeyDown(VK_RIGHT))

             Units[0].SetThrusters(true, false, 0.5);

      if (IsKeyDown(VK_LEFT))

             Units[0].SetThrusters(false, true, 0.5);

      Units[0].UpdateBodyEuler(dt);

      if(FrameCounter >= _RENDER_FRAME_COUNT)

             DrawCraft(Units[0], RGB(0, 255, 0));

      if(Units[0].vPosition.x > _WINWIDTH) Units[0].vPosition.x = 0;

      if(Units[0].vPosition.x < 0) Units[0].vPosition.x = _WINWIDTH;

      if(Units[0].vPosition.y > _WINHEIGHT) Units[0].vPosition.y = 0;

      if(Units[0].vPosition.y < 0) Units[0].vPosition.y = _WINHEIGHT;

     

      // update computer controlled units:    

      for(i=1; i<_MAX_NUM_UNITS; i++)

      {          

             DoUnitAI(i);

           

             Units[i].UpdateBodyEuler(dt);

             if(FrameCounter >= _RENDER_FRAME_COUNT)

             {

                    if(Units[i].Leader)

                           DrawCraft(Units[i], RGB(255,0,0));

                    else {

                           if(Units[i].Interceptor)

                                  DrawCraft(Units[i], RGB(255,0,255));      

                           else

                                  DrawCraft(Units[i], RGB(0,0,255));

                    }

             }

             if(Units[i].vPosition.x > _WINWIDTH) Units[i].vPosition.x = 0;

             if(Units[i].vPosition.x < 0) Units[i].vPosition.x = _WINWIDTH;

             if(Units[i].vPosition.y > _WINHEIGHT) Units[i].vPosition.y = 0;

             if(Units[i].vPosition.y < 0) Units[i].vPosition.y = _WINHEIGHT;          

      } // end i-loop

      if(FrameCounter >= _RENDER_FRAME_COUNT) {

             CopyBackBufferToWindow();

             FrameCounter = 0;

      }  else

             FrameCounter++;

}

void DrawCraft(RigidBody2D      craft, COLORREF clr)

{

      Vector     vList[5];

      double    wd, lg;

      int          i;

      Vector     v1;

      wd = craft.fWidth;

      lg = craft.fLength;

      vList[0].y = lg/2;    vList[0].x = wd/2;

      vList[1].y = -lg/2;   vList[1].x = wd/2;

      vList[2].y = -lg/2;   vList[2].x = -wd/2;

      vList[3].y = lg/2;    vList[3].x = -wd/2;

      vList[4].y = lg/2*1.5; vList[4].x = 0;

      for(i=0; i<5; i++)

      {

             v1 = VRotate2D(craft.fOrientation, vList[i]);

             vList[i] = v1 + craft.vPosition;                  

      }

      DrawLine(vList[0].x, vList[0].y, vList[1].x, vList[1].y, 2, clr);

      DrawLine(vList[1].x, vList[1].y, vList[2].x, vList[2].y, 2, clr);

      DrawLine(vList[2].x, vList[2].y, vList[3].x, vList[3].y, 2, clr);

      DrawLine(vList[3].x, vList[3].y, vList[4].x, vList[4].y, 2, clr);

      DrawLine(vList[4].x, vList[4].y, vList[0].x, vList[0].y, 2, clr);

      if(ShowVectors)

      {

             Vector     v, u;

             double    f = 0.025;

             // Show velocity vectors in green

             DrawLine(craft.vPosition.x, craft.vPosition.y, craft.vPosition.x+craft.vVelocity.x, craft.vPosition.y+craft.vVelocity.y, 3, RGB(0,255,0));

           

             // Show force vectors in black

             // thrust vector

             v.x = 0;

             v.y = craft.ThrustForce*f;

             v = VRotate2D(craft.fOrientation, v);

             u.x = craft.CT.x;

             u.y = craft.CT.y;

             u = VRotate2D(craft.fOrientation, u);

             DrawLine(craft.vPosition.x+u.x, craft.vPosition.y+u.y, craft.vPosition.x + u.x + v.x, craft.vPosition.y + u.y + v.y, 1, RGB(0,0,0));

             // port steering force

             v.x = craft.PThrust.x*f;

             v.y = craft.PThrust.y*f;

             v = VRotate2D(craft.fOrientation, v);

             u.x = craft.CPT.x;

             u.y = craft.CPT.y;

             u = VRotate2D(craft.fOrientation, u);

             DrawLine(craft.vPosition.x+u.x, craft.vPosition.y+u.y, craft.vPosition.x + u.x + v.x, craft.vPosition.y + u.y + v.y, 1, RGB(0,0,0));

             // stbd steering force

             v.x = craft.SThrust.x*f;

             v.y = craft.SThrust.y*f;

             v = VRotate2D(craft.fOrientation, v);

             u.x = craft.CST.x;

             u.y = craft.CST.y;

             u = VRotate2D(craft.fOrientation, u);

             DrawLine(craft.vPosition.x+u.x, craft.vPosition.y+u.y, craft.vPosition.x + u.x + v.x, craft.vPosition.y + u.y + v.y, 1, RGB(0,0,0));

             // applied force

             v.x = craft.Fa.x*f;

             v.y = craft.Fa.y*f;

             v = VRotate2D(craft.fOrientation, v);

             u.x = craft.Pa.x;

             u.y = craft.Pa.y;

             u = VRotate2D(craft.fOrientation, u);

             DrawLine(craft.vPosition.x+u.x, craft.vPosition.y+u.y, craft.vPosition.x + u.x + v.x, craft.vPosition.y + u.y + v.y, 1, RGB(0,0,0));

      }

}

void DrawObstacles(void)

{

      int          i;

      RECT     r;

      int          radius = _OBSTACLE_RADIUS/2;

      for(i=0; i<_NUM_OBSTACLES; i++)

      {

             SetRect(&r, Obstacles[i].x - radius, Obstacles[i].y - radius, Obstacles[i].x + radius, Obstacles[i].y + radius);

             DrawEllipse(&r, 2, RGB(255,0,0));

      }

}

/*

void DoAttractCraft2(void)

{

      // Apply Leonard-Jones potential force to Craft2

      // todo: make sure rigidbody calcloads function handles it

      Vector     r = Craft2.vPosition - Craft1.vPosition;

      Vector  u = r;

      u.Normalize();

      double    k1 = 0.5e2; // repel

      double    k2 = 1.0e2; // attract

      Craft2.Fa = VRotate2D( -Craft2.fOrientation, ((k1*pow(Craft2.fLength*5/r.Magnitude(), 4) - k2*pow(Craft2.fLength*3/r.Magnitude(), 2)) ) * u);

      Craft2.Pa.x = 0;

      Craft2.Pa.y = Craft2.fLength / 2;

      Target = Craft1.vPosition;

     

}

*/

int GetRandomNumber(int min, int max, bool seed)

{

      int   number;

      if(seed)

             srand( (unsigned)time( NULL ) );

           

   number = (((abs(rand())%(max-min+1))+min));  

 

   if(number>max)

             number = max;

   if(number<min)

          number = min;

           

      return number;

}


相关文章
|
29天前
|
机器学习/深度学习 人工智能 自然语言处理
软件测试中的人工智能:改变游戏规则的革新
在这篇技术性文章中,我们将深入探讨人工智能(AI)如何彻底改变了软件测试领域。从自动化测试到智能缺陷检测,AI不仅提高了测试的效率和准确性,还为软件开发团队提供了前所未有的洞察力。通过具体案例,本文揭示了AI在软件测试中应用的现状、挑战及未来趋势,强调了技术创新在提升软件质量与开发效率中的关键作用。
|
1月前
|
机器学习/深度学习 人工智能 自然语言处理
软件测试中的人工智能:改变游戏规则的技术革命
【10月更文挑战第10天】 本文深入探讨了人工智能在软件测试中的应用,揭示了它如何提高测试效率、减少人为错误,并预示了未来软件测试行业的发展趋势。通过案例分析和原理讲解,文章展现了AI技术在自动化测试、缺陷检测和性能评估等方面的巨大潜力。
|
3月前
|
机器学习/深度学习 人工智能 自然语言处理
【机器学习】python之人工智能应用篇--游戏生成技术
游戏生成技术,特别是生成式人工智能(Generative Artificial Intelligence, 简称Generative AI),正逐步革新游戏开发的多个层面,从内容创作到体验设计。这些技术主要利用机器学习、深度学习以及程序化内容生成(Procedural Content Generation, PCG)来自动创造游戏内的各种元素,显著提高了开发效率、丰富了游戏内容并增强了玩家体验。以下是生成式AI在游戏开发中的几个关键应用场景概述
66 2
|
6月前
|
机器学习/深度学习 人工智能 自然语言处理
【AI 生成式】生成式人工智能如何在虚拟现实和游戏中使用?
【5月更文挑战第4天】【AI 生成式】生成式人工智能如何在虚拟现实和游戏中使用?
|
人工智能 搜索推荐 vr&ar
AIGC:引领人工智能和游戏产业融合的里程碑
AIGC:引领人工智能和游戏产业融合的里程碑
209 0
|
人工智能 自然语言处理
人工智能大模型这场游戏才刚刚开始吗?还是在走下坡路?
自人工智能研究实验室OpenAI推出chatGPT发布以来,人们对自然语言大模型的关注度倍增,国内各大厂以及各路大佬都纷纷入局,计划开发自己的人工智能大模型,或以chatGPT为基础开发自己人工智能产品。
146 1
|
机器学习/深度学习 人工智能 自然语言处理
英雄联盟、Dota 2等电竞游戏蓬勃发展,人工智能起大作用
英雄联盟、Dota 2等电竞游戏蓬勃发展,人工智能起大作用
159 0
|
机器学习/深度学习 人工智能 自然语言处理
AIGC未来畅想:探讨人工智能与游戏创作的发展融合
AIGC未来畅想:探讨人工智能与游戏创作的发展融合
247 0
|
机器学习/深度学习 人工智能 算法
人工智能为游戏带来提升
人工智能为游戏带来提升
114 0
人工智能为游戏带来提升
|
机器学习/深度学习 人工智能 算法
人工智能在游戏中的应用与未来展望
人工智能在游戏中的应用与未来展望
844 0