|
发表于 2007-8-23 14:40:00
|
显示全部楼层
Re: 新手请教怪物AI的设定问题
如果你要讨论具体的编码方式...好吧,虽然我对底层技术知道得不多,但我这里可以提供一段以前玩AI-CODE时写的坦克机器人的部分代码.那个机器人的AI都写在这段C代码里了,有兴趣可以看看.
#include "api\c\SimpleRobot.h"
#include "api\c\MathUtils.h"
#include "stdlib.h"
#include "stdio.h"
#include "math.h"
//全局变量
struct Bot * Enemy;
int needFight;
int aimMode;
int moveMode;
int fireFlag;
int bulletHit;
int hitByBullet;
int needDefense;
double velocity;
double firePower;//开火能量
double MbulletVelocity;//子弹速度
double possiblePower;//可能对敌造成伤害的子弹能量
double PFenergy;
double Ex;
double Ey;
double Edistance;
double Eheading;//敌机当前朝向
double Evelocity;
double EfirePower;
double Ebearing;//当前敌机方位
double aimHeading;//炮管所指方位
double eq[90];//直瞄误差量化数组,量化单位为10度角,从eq[0]~eq[8]表示0~90度的范围
double EPFvelocity;
double EPFacceleration;
double EacceleratingTime;
double EPFenergy;
double danger;//定义靠近敌人的危险程度
struct Mshoot
{
struct Mshoot *pre;
int am;//当前瞄准模式
double FP;//子弹能量
double BV;//子弹速度
double fx;//开火位置
double fy;
double eb;//开火时的敌机方位(相对开火位置)
double h0;//瞄准模式0的开火方向
double x0;
double y0;//对应模式0的子弹坐标
double ld0;//对应模式0的子弹与敌机最小距离
double h1;
double x1;
double y1;
double ld1;
double h2;
double x2;
double y2;
double ld2;
struct Mshoot *next;
};
struct Mshoot *head;
struct Mshoot *end;//已发射的某发子弹的数据及相关结构
double ar0,ar1,ar2;
//函数声明
void doRadar(void);
void doMove(void);
void changeDirection(void);
void doGun(void);
double aim_0();
double aim_1();
double aim_2();
void getAimMode();
//事件处理函数///////////////////////
////////////////////////////////////////////////
/**
* 当开始一场新的比赛时触发
*/
void onMatchBegin(struct MatchBeginAction* action){}
/**
* 当整场比赛结束时触发
*/
void onMatchFinish(struct MatchFinishAction* action){}
/**
* 当开始一轮新的比赛时触发
*/
void onRoundBegin(struct RoundBeginAction* action)
{
int i;
Enemy=getFirstOpponent();
EPFvelocity=0;
EPFenergy=100;
velocity=8;
fireFlag=0;
bulletHit=0;
hitByBullet=0;
ar0=ar1=ar2=0;
danger=0;
if(Enemy==NULL)
needFight=0;
else
needFight=1;
needDefense=0;
head=NULL;
end=NULL;
aimMode=2;
moveMode=1;
for(i=0;i<90;i++)
{
eq=0;
}
}
/**
* 当一轮比赛结束时触发。
*/
void onRoundFinish(struct RoundFinishAction* action){}
/**
* 当有队友向自己发送消息时触发
*/
void onMessageReceived(struct MessageReceivedAction* action){}
/**
* 当撞到其它机器人时触发
*/
void onHitRobot(struct HitRobotAction* action){}
/**
* 当撞到墙时触发
*/
void onHitWall(struct HitWallAction* action)
{
changeDirection();
}
/**
* 当任意一个机器人开火时触发
*/
void onFire(struct FireAction* action){}
/**
* 当有机器人死亡时触发
*/
void onRobotDeath(struct RobotDeathAction* action){}
/**
* 当自己的子弹击中敌人时触发
*/
void onBulletHit(struct BulletHitAction* action)
{
bulletHit=1;
}
/**
* 当被别人的子弹击中时触发
*/
void onHitedByBullet(struct HitedByBulletAction* action)
{
hitByBullet=1;
moveMode=-moveMode;
}
//执行函数////////////////////////////////////////
//////////////////////////////////////////////////
/**
* 每个单位时间都会触发
*/
void onTick(struct TickAction* action)
{
if(needFight)
{
doRadar();
doMove();
doGun();
}
else
move(0);
getAimMode();
if(!isAlive(Enemy))
{
Enemy=getFirstOpponent();
if(Enemy==NULL)
needFight=0;
else
needFight=1;
}
}
void doRadar()
{
double angle;
//将后面计算所需的部分敌方数据计算出来存入全局变量
Ex=Enemy->x;
Ey=Enemy->y;
Evelocity=Enemy->velocity;
Eheading = Enemy->heading;
Ebearing = heading( getX(),getY(),Ex, Ey);
Edistance = distance(getX(),getY(),Ex,Ey);//计算敌我距离
EPFacceleration = Evelocity-EPFvelocity;//估算敌加速度
//计算敌加速度维持时间
if(EPFacceleration == 0)
EacceleratingTime = 0;//当敌加速度为0时认为加速度维持时间也为0
else
{
if(EPFacceleration*Evelocity<=0)
EacceleratingTime = (0-Evelocity)/EPFacceleration;//减速维持时间
else
{
if(Evelocity>0)
{
EacceleratingTime = 8-Evelocity;//正向加速维持时间
EPFacceleration = 1;//将正向加速度修正为1
}
else
{
EacceleratingTime = Evelocity+8;//负向加速维持时间
EPFacceleration =-1;//将负向加速度修正为-1
}
}
}
danger=danger*(1-getEnergy()/300);
if(hitByBullet)
danger=danger+(PFenergy-getEnergy());
if(danger>0.05)
needDefense=1;
else
needDefense=0;
if(bulletHit&&(!hitByBullet))
{
if(possiblePower>3)
EPFenergy=EPFenergy+(PFenergy-getEnergy())/4*6;
else
EPFenergy=EPFenergy-possiblePower*6;
}
if((!bulletHit)&&hitByBullet)
{
EPFenergy=EPFenergy+(PFenergy-getEnergy())/6*4;
}
if(bulletHit&&hitByBullet)
{
EPFenergy=EPFenergy+((possiblePower*(8/3)-(getEnergy()-PFenergy)*(2/3))-6*possiblePower);
}
EfirePower = EPFenergy-Enemy->energy;
PFenergy=getEnergy();
EPFvelocity = Evelocity;
EPFenergy = Enemy->energy;
bulletHit=0;
hitByBullet=0;
}
void doMove()
{
//始终侧对着敌人
double angle;
long keepDistance;
if(moveMode==1)
{
if( EfirePower>=0.1 ) changeDirection();
}//如果moveMode为1,则探测到敌机开火就改变运动方向
keepDistance=80;
if((Edistance>keepDistance+40)&&!needDefense)
{
if( velocity >= 0 )
angle = Ebearing+PI/2-PI/4;
else
angle = Ebearing+PI/2+PI/4;
}//以PI/4靠近敌机
if((Edistance<keepDistance)&&!needDefense)
{
if( velocity >= 0 )
angle = Ebearing+PI/2+PI/4;
else
angle = Ebearing+PI/2-PI/4;
}//以PI/4远离敌机
if((Edistance>=keepDistance)&&(Edistance<=keepDistance+40)||needDefense)
{
angle = Ebearing+PI/2;
}//否则与敌机方位成90度角
move(velocity);
turnTo(angle);
}
void changeDirection()
{
velocity=-velocity;
}
void doGun()
{
double angle;
firePower=(1000/Edistance-1)/(300/Edistance);
if(firePower*6>Enemy->energy)
firePower=(Enemy->energy)/5;//当敌机能量不多时以恰好能击毁敌机的能量开火
if(firePower<0.1)
{
firePower = 0.1;
}
else
{
if(firePower>3)
firePower = 3;
}//使开火能量处于规定范围内
MbulletVelocity=20-3*firePower;//得到子弹速度
if(aimMode==0)//根据aimMode的值选择瞄准模式
aimHeading=aim_0();
if(aimMode==1)
aimHeading=aim_1();
if(aimMode==2)
aimHeading=aim_2();
if(getFirePrepareTime()==0)
{
fireFlag=1;
fire(aimHeading,firePower);
}
else
{
fireFlag=0;
fire(aimHeading,0);
}
}
double aim_0()//瞄准模式0:直线预测瞄准。以迭代法计算
{
double x,y;//接触点坐标
double S;//从开炮到弹敌接触前敌机行使距离估测值
double D;
double impactTime;
double AH;
D=Edistance;
do
{
impactTime = D/MbulletVelocity;//根据前次估算距离计算弹敌接触时间
if(EacceleratingTime>=impactTime)
{
S = Evelocity*impactTime+EPFacceleration*impactTime*impactTime/2;
x = Ex+cos(Eheading)*S;
y = Ey+sin(Eheading)*S;
}
else
{
S = Evelocity*EacceleratingTime+
EPFacceleration*EacceleratingTime*EacceleratingTime/2+
(Evelocity+EPFacceleration*EacceleratingTime)*(impactTime-EacceleratingTime);
x = Ex+cos(Eheading)*S;
y = Ey+sin(Eheading)*S;
}
D = distance(getX(),getY(),x,y);//重新估算弹敌接触时的敌我距离
}
while(fabs(D-MbulletVelocity*impactTime)>=1);//循环条件——此次估算距离与前次估算距离之差大于等于1像素
AH=heading(getX(),getY(),x,y);
return(AH);
}
double aim_1()//瞄准模式1:根据敌当前位置直接开火。
{
double AH;
AH=Ebearing;
return(AH);
}
double aim_2()//瞄准模式2:采取直接瞄准加修正角的方式
{
double AH;
double modiAngle;
double p1,p2,p3;
int unit;//由敌我距离决定的量化单位
int i,j,k;
int angle;
p1=p2=0;
unit=(int) ((40/Edistance)/PI*180);//该量化单位内只能容纳不到1车身
if(unit==0)
unit=1;
else if(unit>90)
unit=90;
for(i=0;i<=90-unit;i++)
{
for(j=0;j<unit;j++)
{
k=i+j;
p1=p1+eq[k];
}
if(p1>p2)
{
p2=p1;
angle=i;
}
p1=0;
}
if(p2==0)
modiAngle=0;
else
modiAngle=(angle+unit/2-45)*PI/180;
AH=Ebearing+modiAngle;
if(AH>2*PI)
AH=AH-2*PI;
if(AH<0)
AH=AH+2*PI;
return(AH);
}
void getAimMode()
{
struct Mshoot *p,*c,*n;
double erroAngle;//直瞄误差(弧度,以开火时的敌机方位为0度,逆时针为正方向)
double EA;
double crld;//当前考察的那次射击实际子弹与敌机最小距离
int i;
if(fireFlag)
{
if(head==NULL)
{
end=head=(struct Mshoot *)malloc(sizeof(struct Mshoot));
head->pre=NULL;
head->next=NULL;
}
else
{
end->next=(struct Mshoot *)malloc(sizeof(struct Mshoot));
p=end;
end=end->next;
end->pre=p;
end->next=NULL;
}//建立命中精度统计链表
if(aimMode==0)
{
end->h0=aimHeading;
end->h1=aim_1();
end->h2=aim_2();
}
if(aimMode==1)
{
end->h0=aim_0();
end->h1=aimHeading;
end->h2=aim_2();
}
if(aimMode==2)
{
end->h0=aim_0();
end->h1=aim_1();
end->h2=aimHeading;
}
end->am=aimMode;
end->FP=firePower;
end->BV=MbulletVelocity;//得到子弹速度;
end->x0=end->x1=end->x2=end->fx=getX();
end->y0=end->y1=end->y2=end->fy=getY();
end->eb=Ebearing;
end->ld0=end->ld1=end->ld2=Edistance;//记录本次射击的预测状态
}
possiblePower=0;
for(c=head;c!=NULL;)
{
c->x0=(c->x0)+c->BV*cos(c->h0);
c->y0=(c->y0)+c->BV*sin(c->h0);
if((c->ld0)>distance(c->x0,c->y0,Ex,Ey))
c->ld0=distance(c->x0,c->y0,Ex,Ey);
c->x1=(c->x1)+c->BV*cos(c->h1);
c->y1=(c->y1)+c->BV*sin(c->h1);
if((c->ld1)>distance(c->x1,c->y1,Ex,Ey))
c->ld1=distance(c->x1,c->y1,Ex,Ey);
c->x2=(c->x2)+c->BV*cos(c->h2);
c->y2=(c->y2)+c->BV*sin(c->h2);
if((c->ld2)>distance(c->x2,c->y2,Ex,Ey))
c->ld2=distance(c->x2,c->y2,Ex,Ey);
if(c->am==0)
crld=c->ld0;
if(c->am==1)
crld=c->ld1;
if(c->am==2)
crld=c->ld2;
if(crld<(20+(c->BV)*2))
{
possiblePower+=c->FP;
}
if(distance(c->x0,c->y0,c->fx,c->fy)>(distance(Ex,Ey,c->fx,c->fy)+20))
{
for(i=0;i<90;i++)
{
eq=eq*0.65;
}
erroAngle=bearing(heading(c->fx,c->fy,Ex,Ey),c->eb);
EA=45+erroAngle/PI*180;//将erroAngle转换到以敌机方位为+45度的角度坐标系中
if(EA<0)
EA=0;
else if(EA>=90)
EA=89;
i=(int) EA;
eq=eq+4;//量化erroAngle,并统计入量化数组
ar0=ar0*0.65;
ar1=ar1*0.65;
ar2=ar2*0.65;
if(c->ld0<20)
ar0=ar0+4;
/*else if(c->ld0<33)
ar0=ar0+1;*/
if(c->ld1<20)
ar1=ar1+4;
/*else if(c->ld1<33)
ar1=ar1+1;*/
if(c->ld2<20)
ar2=ar2+4;
/*else if(c->ld2<33)
ar2=ar2+1;*/
if(ar0>=ar1)
{
if(ar0>=ar2)
aimMode=0;
else
aimMode=2;
}
else
{
if(ar1>=ar2)
aimMode=1;
else
aimMode=2;
}
p=c->pre;
n=c->next;
if(p==NULL && n==NULL)
{
head=NULL;
end=NULL;
free(c);
c=n;
}
if(p==NULL && n!=NULL)
{
head=n;
n->pre=NULL;
free(c);
c=n;
}
if(p!=NULL && n==NULL)
{
end=p;
p->next=NULL;
free(c);
c=n;
}
if(p!=NULL && n!=NULL)
{
p->next=c->next;
n->pre=c->pre;
free(c);
c=n;
}
}
else
c=c->next;
}
} |
|