Unity+4.x+Game+AI+programming CookBook 杂记
Chapter 1 :Introduction to AI
AI in games:游戏AI目的,创建难度适中的NPCs AI,尽量简化计算过程。
AI techniques:
(1) Finite State Machines(FSM):有限状态机
简单射击游戏敌人状态机
简单有限状态机的基本4组件:
1.状态(States):一系列游戏实体状态或者NPC可选择的状态(例如图中的Patrol(巡逻), Chase(追踪),Shoot(射击)。
2.过渡(Transitions):定义不同状态间的关系。
3.规则(Rules):触发过渡(如图player on sight, close enough to attack, and lost/killed player)。
4.事件(Events):触发规则检查。(guard's visible area, distance with the player, and so on)。
a monster in Quake 2(雷神之锤,没玩过- -) 可能有如下状态:standing, waliking, running, dodging(闪避), attacking, idle, and searching。
通常用if/else 和 switch 可以轻易实现简单的状态机。
(2)Random and probability in AI:随机概率。
(3)The sensor system: 感应系统。
Position of the plyaer(玩家位置):选择攻击,追踪,搜寻。
Buildings and objects nearby(附近的建筑和物体):隐藏或躲避。
Player’s health and its own health(玩家和自身血量):选择撤退或前进。
Location of resources on the map in an RTS game:选择占领或收集资源,需要创建和生产其他单位。
方法:
1.Polling:轮询。
在FixedUpdate中使用if/else or switch 检查AI 需要的信息。
2.The messaging system:消息系统。
一个对象拥有监听器listener来监听消息系统发来的消息,从而进行一系统列处理。通常 消息与轮询一起使用。当AI接收到事件时,使用轮询检查更多细节。
Flocking ,swarming ,and herding: 群体AI
Separation:间距。维持最小间距
Alignment:排列方式
Cohesioin:中心
Path following and steering:路径跟踪导航
Hierarchy of motion behaviors 动作行为层级。
Such behaviors include seek and
flee, pursue and evade, wander, arrival, obstacle avoidance, wall following, and
path following
A* pathfinding :A*搜寻
F = G + H
G and H, where G is the cost of movement from starting tile to current tile,
and H is the cost to reach the target tile from current tile.
G代表开始方格到当前方格的最短距离
H代表当前方格到目标方格的最短距离
Calculating G :G于格子左下角
Calculating H :H于格子右下角,既到目标最短距离。
F于格子左上角
Frist 计算开始点(图中浅绿色格子)相邻的FGH值,先选取F值最小的
Second 计算新的点图(F=4处)相邻FGH值,因都为6任选,此处选取如图红色方框高亮格子
Third 计算得新的开始点周围绕的新格F值为8,则6<8,从下一个F=6的格子开始计算。
重复以上步骤,最终得到上图。最终路径可能为图中黄色格子
The behavior trees 行为树
tasks
Selector task
Sequence tasks
Chapter 2 :Finite State Machines
The PlayerTankController Class:
The bullet Class:
Setting up waypoints:
The abstract FSM class:
The enemy tank AI:
Using an FSM framework://有限状态机框架
(1) Transition:过渡enum
(2)StateID:状态ID enum
(3)FSMState:状态基类,abstract抽象类
Dictionary KEY:Transition和VALUE:tateID的map;
StateID 状态ID
增删过渡
获取过渡后的状态ID
过渡原因函数
行动函数
(4)FSMSystem:整个状态机系统
状态表
当前状态和ID
构造函数:初始化状态表
增删状态
执行过渡。
(5)具体NPC控制类:NPCController
设置过渡函数
Chapter3:Random And Probability 随机概率
Character Personality
FSM with probability:
FSM using probability
利用数组构建状态池, 按状态池中状态比例计算结果。
Dynamic AI
The Flow Channel
Chapter4:Implementing Sensors
Aspect : enum aspect 面貌 ,指物体的类别如player,enemy
Sense: 感官基类: Aspect, 检测频率/距离,检测计时器, 虚函数初始化/更新
Perspective:Scense 透视(视野),是否在物体的视野内。
Touch: 触摸,当其他物体进入碰撞区域。
总结:We can use the sensory system in combination with a behavior system to execute certain
behaviors for certain senses.
For example, we can use an FSM to change to chase and attack states from the patrol state once we have detected that there's an enemy within the line-of-sight
Chapter5 Flocking:
Boid:术语类似鸟群的集群
Flocking algorithm 鸟群算法
Base:
(1)Flock:跟随领头鸟
(2)FlockController:领头鸟确定方向,地点
Chapter6:PathFollowing and steer behavior
Following a Path:
Path:空物体,记录路径点
PathFollow:沿路径点移动
Avoiding Obstacles:
简单方法:用射线简单检测前方一定距离的障碍物。如果有障碍物,重新选择方向,使用原方向的法向量。
Chapter7:A*pathfinding
循环函数使用Debug.log要小心。
Node:Icomparable
public float noteTotalCost;//G
public float estimatedCost;//F
public bool bObastacle;
public Node parent;
public Vector3 position;
实现CompareTo 比较函数.
MakeAsObstacle
Other you like to add …..
PriorityQueue:
Node ArrayList表
Contains
First
PUSH:这里sort,易于查找最优路径
POP:这里sort
GridManager:
单例模式
行数,列数,单元格子Size,bool showGrid, showObstacleBlocks,初始位置,obstacle数组。 Node二维数组
Awake(): 初始化obstacle数组,初始位置,CalculateObstacles(计算障碍物的节点和初始化节点表)。
CalculateObstacles(): 初始化所有节点表,标记障碍物
public Vector3 GetGridCellCenter (int index)
public Vector3 GetGridCellPosition(int index)
public int GetGridIndex(Vector3 pos)
public bool IsInBounds(Vector3 pos)
public int GetRow(int index)
public int GetColumn(int index)
public void GetNeighbours(Node node, ArrayList neighbors)
void AssignNeighbour(int row, int column, ArrayList neighbors)
void OnDrawGizmos()
public void DebugDrawGrid(Vector3 origin, int numRows, int numCols, float gridCellSize, Color color)
Astar:
public class AStar : MonoBehaviour
{
private static PriorityQueue closedList, openList;//优先列表:已访问列表, 未访问列表
private static float HeuristicEstimateCost (Node curNode, Node goalNode)//计算估值H
{
Vector3 vecCost = curNode.position - goalNode.position;
return vecCost.magnitude;
}
public static ArrayList FindPath (Node start, Node goal)//寻找路径算法:起点,终点
{
openList = new PriorityQueue ();//初始化未访问列表
openList.Push (start);//将初始点Push
start.noteTotalCost = 0.0f;//G = 0
start.estimatedCost = HeuristicEstimateCost (start, goal);//H = dis<s,g>
closedList = new PriorityQueue ();//初始化已访问列表
Node node = null;
while (openList.Length != 0) {//如果未访问列表有值
node = openList.First ();
if (node.position == goal.position) {//如果当前节点就是终点节点
return CalculatePath (node);//计算路径,返回路径List
}
ArrayList neighbours = new ArrayList ();//数组列表 邻近
GridManager.instance.GetNeighbours (node, neighbours);//获取当前节点的邻近
for (int i = 0; i < neighbours.Count; i++) {//遍历邻近表
Node neighbourNode = (Node)neighbours [i];
if (!closedList.Contains (neighbourNode)) {//如果已访问列表不存在此邻近节点
float cost = HeuristicEstimateCost (node, neighbourNode);//计算邻近节点到此节点距离
float totalCost = node.noteTotalCost + cost;//计算邻近节点的G
float neighbourNodeEstCost = HeuristicEstimateCost (neighbourNode, goal);//计算邻近节点的H
neighbourNode.noteTotalCost = totalCost;//G
neighbourNode.parent = node;//邻近节点的父节点为此节点
neighbourNode.estimatedCost = totalCost + neighbourNodeEstCost;//F
if (!openList.Contains (neighbourNode)) {//如果未访问列表不存在此邻近节点
openList.Push (neighbourNode);//压入
}
}
}
closedList.Push (node);//此节点压入已访问列表
openList.Remove (node);//未访问列表移除此节点
}
if (node.position != goal.position) {//当所有可访问的节点都访问完的时候.
Debug.LogError ("Goal Not Found");
return null;
}
return CalculatePath (node);
}
private static ArrayList CalculatePath (Node node)
{
ArrayList list = new ArrayList ();
while (node != null) {
list.Add (node);
node = node.parent;
}
list.Reverse ();
return list;
}
}
Chapter8 NavMesh