| | |
|
岱瀛
(deving)
| |
| | |
|
| | |
|
组别 | 经略使 |
级别 | 左将军 |
好贴 | 1 |
功绩 | 2293 |
帖子 | 1370 |
编号 | 55810 |
注册 | 2005-12-22 |
来自 | 人间 |
家族 | 慕容世家 |
| |
| | |
|
|
|
原帖由 赵辉 于 2009-12-1 13:02 发表
我广搜算法的优先顺序是上、下、左、右,所以应该是上1右1.
原版的我不知道,这就等岱儿他们来回答吧 我简单的说一下曹操传的AI算法吧。
我们知道,曹操传的AI是分了很多种的,比如坚守原地啊,主动出击啊,被动初级啊,跟随某人啊,攻击某人啊,而这里面的一个重要核心思想是 寻路算法。
我认为光荣的寻路算法应该是从 long long ago就沿用的,因为当初我看了那长长的汇编代码,读懂那个寻路算法的时候,忽然就想到了三国志第二代的一个现象。 我们操作某个人的时候,一点,周围可移动的格子里有一些奇怪的数字,7,6,5,4.有时候又7,4,1这样的。后来看曹操传代码,觉得就是一脉相承的东西了。
简单在这里说一下,印象中的曹操传寻路算法。
他是一个递归算法。
首先,我们简单看一下相关的数据结构,既然会C++,我就用C++来解释,这样都方便一些。
#define MAX_LANDFORM 16
#define MAX_METIER 23 //假设有23种职业
//假设一个30*30的地图
int nMapWidth = 30;
int nMapHeight = 30;
struct Map
{
int nLandformID; //地形
int nState; //状态,0表示没有人占,-1表示敌人占,1表示我方或者友方占
};
struct Metier //职业
{
int nLandformConsume[MAX_LANDFORM]; //某职业的地形消耗数组
int nAction; //移动力
//.... 职业里还有很多层数据结构
};
Metier g_metier[MAX_METIER];
Class CBattelPerson : public CPerson //战场上的人,继承于人
{
private:
int nID; //人物的ID;
int nMetierID; //人对应的职业
int nXposition; //当前地图所在的X坐标位置
int nYposition; //当前地图所在的Y坐标位置
int nStatus; //当前状态 0表示未行动,1表示行动
int nActionState; //当前移动力状态 (可能强行,可能下降,可能是正常)
int nRole; //人物角色,1表示我军或者友军, -1表示敌军
//.... 战场上的人其实还有很多种属性,从略
private:
void mfGetActionPath(int nActionValue, int nXpos,int nYpos) ;
public:
void GetAcitonPath();
};
//会计算出一个所谓的移动队列,我简单的用vector来表示,相信引用下stl库也不是太麻烦的事情。
struct Position
{
int nXpos;
int nYpos;
int nAIValue; //这个位置的AI参考值
};
vector<Position> actionQueue;
全局的地图
Map map[nWidth][nHeight];
int nFlag[nWidth][nHeight]; //用来标记地图的AI计算状态
void //求路径的递归函数,参数一,行动力,参数二,x坐标,参数三,y坐标
CBattelPerson::mfGetActionPath(int nActionValue, int nXpos,int nYpos)
{
if (nFlag[nXpos][nYpos] != 0) //说明这个位置遍历过,不遍历
return;
else
nFlag[nXpos][nYpos] = nID;
if (nActionValue <=0) return; //没有行动力了,退出
if (nRole * map[x][y]. nState < 0)
return; //这个位置上有敌人,不能通过,退出 ,这里面的设计没有考虑突击移动的特性,如果有突击移动的特性,这个判断就可以跳过
//为了解释清楚容易看点,下面代码拆细一些
//取出当前职业
Metier metier = g_metier[nMetierID];
//取出地形
if (nXpos - 1 >= 0 )
{
int nCurLandFormIDLeft = map[x-1][y]. nLandformID;
mfGetActionPath(nActionValue - metier . nLandformConsume[nCurLandFormIDLeft],x-1,y);
}
if (nXpos + 1 < nWidth )
{
int nCurLandFormIDRight = map[x+1][y]. nLandformID;
mfGetActionPath(nActionValue - metier . nLandformConsume[nCurLandFormIDRight],x+1,y);
}
if (nYpos - 1 >= 0)
{
int nCurLandFormIDTop = map[x][y-1]. nLandformID;
mfGetActionPath(nActionValue - metier . nLandformConsume[nCurLandFormIDTop],x,y-1);
}
if (nYpos + 1 < nHeight)
{
iint nCurLandFormIDBottom = map[x][y+1]. nLandformID;
mfGetActionPath(nActionValue - metier . nLandformConsume[nCurLandFormIDBottom],x,y+1);
}
Position position;
position.x = nXpos;
position.y = nYpos;
actionQueue.push_back(position); //把坐标压入向量
}
void
CBattelPerson ::GetAcitonPath()
{
int nActionValue = 0;
//当前移动力
nActionValue = g_metier[nMetierID]. nAction * nActionState; //假设移动力状态是个百分数,其实曹操转里面不是,不过这个无所谓了。
memset(nFlag,0,nWidht*nHeight); //把整个数组清零
mfGetActionPath(nActionValue ,nXpos,nYpos);
}
这样,外部函数只要调用到GetAcitonPath(),就能得到当前这个人物的可移动向量。
如果是给用户交互操作,直接就是给界面作下渲染。
如果是给AI,那么就根据这个向量,再根据当前选择的AI类别,遍历这个vector,计算出每个位置的nAIValue;
最后,对这个vector作一下排序,那么AI的结果就出来了。
[ 本帖最后由 岱瀛 于 2009-12-2 01:03 编辑 ]
|
|
|
|