ai是游戏的一个重要组成部分,指的是玩家与npc之间的相互活动。
设计上:
npc ai流程:逻辑线程主循环-->场景管理器遍历->场景循环-->遍历所有npc-->npc循环-->ai状态机切换和ai状态处理
ai主要功能包括
正常状态:ai状态切换和ai状态处理
死亡状态:死亡状态机
ai状态切换
根据状态机来切换。
游荡状态->追击状态 或 攻击状态
追击状态->攻击状态 或 回归状态
攻击状态->追击状态 或 回归状态
回归状态->游荡状态
ai状态处理
(1)发呆状态(不做事情)
(2)游荡状态 (随机移动)
(3)追击状态(ai的寻路是使用网格计算,目前是a星的优化算法)
(4)攻击状态(战斗使用普通屏索引、优化计算使用有效屏索引)
(5)回归状态 (目前刷新到出生点)
数据结构
AI状态控制器
ai类型(ai活动逻辑)
ai状态机
(1)ai类型之间的切换(ai状态机切换)。
(2)ai类型的执行。
(3)ai对象的死亡循环执行。
处理时机
(1)在npc的循环里执行ai状态的切换和ai类型动作
(2)处理技能状态定时器和npc定时状态
(3)死亡状态下会有死亡循环。
1、npc总体流程
npc的ai循环的调用层次:
逻辑线程主循环-->场景管理器遍历->场景循环-->遍历所有npc-->npc循环-->ai状态机切换和ai状态处理
(1)npc循环
bool scene_npc::loop()
{
const SceneObjectState &state = getEntryState();
if(state == SceneObject_Normal)//npc 正常状态
{
if (AIC)//ai控制器
{
if(this->base->npcType == MSG::NpcType_Gun)
{
gunAction();//特殊类型npc 的ai状态
}
else
{
AIC->processPhase();//ai状态机切换
normalAction();//ai状态处理
}
}
if(_one_sec(main_logic_thread::currentTime))
{
this->statem->stateTimer();//技能状态管理器定时器(执行技能状态对象),参考:http://blog.csdn.net/chenjiayi_yun/article/details/19429133
this->statem->loop();//技能状态循环(回收标识销毁的技能状态对象)
//死亡状态life 为0 ,_life_timer 定时器到时
if(npcState.life && (_life_timer)(main_logic_thread::currentTime))
{
killMe();//npc死亡九屏同步,死亡处理
}
timeCount++;
//根据策划配置时间定时回血 ,采集状态检查
......
}
}
else if(state == SceneObject_Death)
{
this->statem->deleteAll();//npc死亡删除状态管理器的所有状态对象
deathLoop();//npc 对象死亡状态后的死亡循环处理
}
return true;
}
2、ai状态机
(1)ai类型
ai类型实际上就是复杂动作的一个结合体。可以直接在c++代码里面写,也可以写在脚本方便热切换 ,针对ai的处理又要耗费较多的cpu时间,所以一般就在c++里面写。
ai类型之间的切换是在AI状态切换控制器里面管理的。
目前主要的ai类型有如下:
enum eAIType
{
NPC_AI_NORMAL,///游荡
NPC_AI_MOVETO,///追击
NPC_AI_ATTACK,///攻击
NPC_AI_RETURN_TO_REGION,///回归
NPC_AI_STUN,//发呆
};
ai类型定义:
struct t_NpcAIDefine
{
///类型,NPC在该阶段的主要动作
eAIType type;
///位置 根据不同动作位置的意义也略不相同
///移动时表示目的地,其他表示活动范围中心
nPos pos;
///追击目标点
nPos chaseLoc;
///范围
///移动时表示到达目的地的判定范围,其他表示活动范围
int32 regionX, regionY;
};
(2)AI状态控制器
AI状态控制器(是npc对象scene_npc的成员)来修改ai状态,记录当前ai动作类型,来根据当前ai类型执行动作。
AI控制器:
保存当前和上一个ai类型
当前ai类型的转换(切换条件判断)
class NpcAIController
{
///本控制器控制的npc
scene_npc * npc;
///当前的AI类型和保存的前一个AI类型
t_NpcAIDefine curAI,oldAI;
///活动范围的中心
nPos actPos;
//追击的半径
nPos chasePos;
///活动范围的宽和高
int actRegionX, actRegionY;
/**
* \description 判断Npc是否走出了活动范围之外
* 如果没有在跟踪用户状态,需要在活动范围行走
* 追逐时范围扩大10
* \return 是否超出活动范围
*/
bool outOfRegion() const;
//回到活动范围,追踪敌人超出范围时以5倍速返回
/**
* \description 设置回到范围的AI使NPC回到活动范围
* 如果NPC是跟踪敌人而超出了活动范围,则以5倍速返回活动范围内,同时放弃跟踪目标
*/
void returnToRegion();
/**
* \description 判断npc是否到达某位置的某范围内(范围判断函数)
* \param pos 中心位置,默认是当前AI的目标位置
* \param regionX 范围宽,默认是当前AI的范围宽
* \param regionY 范围高,默认是当前AI的范围高
* \return 是否在范围内
*/
bool arrived(nPos pos = nPos(0,0), int x = -1, int y = -1);
void setNormalAI();
/**
* \description 设置NPC的活动范围
* \param pos 中心位置
* \param x,y 范围的宽和高
* \return
*/
void setActRegion(nPos pos = nPos(0,0), int x = -1, int y = -1);
/**
* \description 设置NPC的活动范围
* \param pos 左上位置
* \param x,y 范围的宽和高
* \return
*/
void setActRegionS(nPos pos = nPos(0,0), int x = -1, int y = -1);
/**
* \description 得到NPC的活动范围
* \param pos 输出:中心位置
* \param x,y 输出:范围的宽和高
*/
void getActRegion(nPos &, int &, int &);
/**
* \description 状态切换管理
* 该方法在scene_npc::loop中执行
*/
void processPhase();
//当前ai定义
t_NpcAIDefine *GetCurAI() {return &curAI;}
};
(2-1)ai类型切换
ai的状态切换函数处理,进行ai状态的切换条件的判断和执行切换
void NpcAIController::processPhase()
{
switch(curAI.type)
{
case NPC_AI_STUN://发呆状态
{
if(this->stunTime < main_logic_thread::currentTime._msec &&this->npc->enm->enemySize == 0)//没有敌人,并在发呆时间内
{
int rand = nMisc::randBetween(0,100);//随机跳入游荡状态
if(rand > 90)
{
curAI.type = NPC_AI_NORMAL;
}
return;
}
else
{
curAI.type = NPC_AI_NORMAL;
}
}
break;
case NPC_AI_NORMAL://游荡状态
{
//获取仇恨列表中的最近的玩家
scene_player* player = (scene_player*)this->npc->enm->getNearestEnemy();
if(!player)//在仇恨列表里没有目标则搜索警戒范围内的目标
{
//警戒范围之内发现了目标,切换Ai,移向敌人
//指定范围上的点是根据npc对象的坐标点为中心的,一定