敌人移动AI初探

前言

在公司做flash有一段时间了,在这几个月做的功能中,有几个存在敌人移动的小游戏,发现敌人移动AI是一个值得学习与研究的方向,于是把学习记录于此。

格子类型游戏

简介

常见的格子类型游戏,可以理解为就是指把50X50(宽*高)的面板分成25个格子,每个格子的宽高为10*10,一个敌人初始化在某一个格子中,之后移动都是从某一个格子移动到临近的格子,不存在移动半格的情况。一般游戏中还会存在障碍物,敌人与自己均不能移动到存在障碍物的格子当中。

创建地图(格子)结构

由于地图结构是固定的格子,因此可以直接使用二维数组来进行存储。数组元素的值可以用来代表格子的不同状态,这里0代表空格子,1代表存在障碍物的格子。代码如下所示:

1
2
3
4
5
6
// 为了方便,以3 * 3 大小格子为例
const MAP:Array = [[0, 0, 0],
[1, 1, 0],
[1, 0, 0]];
const ROW:int = 3;
const COLUMN:int = 3;

判断临近格子是否可以移动

临近格子一般为上下左右四个方向,向每个方向移动只需要判断格子是否可行即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
* @params posX 格子竖直方向的位置下标
* @params posY 格子水平方向的位置下标
*/
function canMove(posX:int, posY:int):Boolean {
var nextPos:Array = [[0, 1], [0, -1], [1, 0], [-1, 0]]; // 用于计算上下左右四个方向的下标
var temp:Array;
var len:int = nextPos.length;
var nextPosX:int;
var nextPosY:int
for (var i:int = 0; i < len; i ++) {
temp = nextPos[i];
nextPosX = posX + temp[0];
nextPosY = posY + temp[1];
if (judgeGrid(nextPosX, nextPosY)) {
// 做敌人移动到下标为nextPosX, nextPosY格子的逻辑

break;
}
}
}

// 判断格子下标是否合法且为空格子
function judgeGrid(posX:int, posY:int):Boolean {
if (posX < 0 || posX >= ROW || posX < 0 || posY >= COLUMN) {
return false;
}

return MAP[posX][posY] == 0;
}

上述代码逻辑虽然是以计算上下左右四个方向为例的,但其实也同样适用于八个方向(加左上、左下、右上、右下四个方向),只需要改变下nextPos数组的值即可。后续还是以四个方向为例

1
2
// 用于计算临近8个方向,后续代码逻辑同上,无需变动
var nextPos:Array = [[0, 1], [0, -1], [1, 0], [-1, 0], [1, 1], [-1, -1], [1, -1], [-1, 1]];

移动方向选择(下个格子选取)

完全随机选择

也就是说每次走完一个格子,都重新从上下左右四个格子中选取,但是由于选取的格子不一定是可移动的,因此当遇到不可移动的格子时,需选取下一个方向

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var nextPos:Array = [[0, 1], [0, -1], [1, 0], [-1, 0]];
var len:int = nextPos.length;
var direct:int;
var temp:Array;
for (var i:int = 0; i < len; i ++) {
direct = int (Math.random() * 4);
temp = nextPos[direct];
// 用于判断下一个方向
direct ++;
direct %= len;
// 可移动的话做移动逻辑,并退出循环,结束此次移动,否则判断下一个方向是否可移动
if (judgeGrid(temp[0], temp[1])) {

break;
}
}

最近移动的方向优先选择

只需要把最近的方向存起来优先判断即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var nextPos:Array = [[0, 1], [0, -1], [1, 0], [-1, 0]];
var len:int = nextPos.length;
var direct:int = curDirect; // curDirect为存的最近移动方向
var temp:Array;
for (var i:int = 0; i < len; i ++) {
temp = nextPos[direct];
direct = int (Math.random() * 4);
// 用于判断下一个方向
direct ++;
direct %= len;
// 可移动的话做移动逻辑,并退出循环,结束此次移动,否则判断下一个方向是否可移动
if (judgeGrid(temp[0], temp[1])) {
// 在移动之前记得把移动方向更新
curDirect = direct;

break;
}
}

-------------本文结束感谢您的阅读-------------