Unity3D学习 - P&D有限状态机
视频地址
GITHUB地址
主要代码实现
状态转换图![]()
- 本次作业要求实现自动过河的牧师与魔鬼有限状态机。主要是在之前实现过的牧师与魔鬼运动分离版的基础上,对原代码进行修改,以提供方法给自动过河类AutoMove来调用。
-
本次的重点AutoMove类。首先该类设计为单例模式,通过静态变量autoMove来调用该类的方法。然后声明所需变量。
public static AutoMove autoMove = new AutoMove(); public FirstController firstScene; private int devilNum; private int priestNum; private int BoatCoast; // -1 -> left, 1 -> right. //P:船运载一个牧师 //D:船运载一个恶魔 //PP:船运载两个牧师 //DD:船运载两个恶魔 //PD:船运载一个牧师,一个恶魔 private enum Boataction {empty, P, D, PP, DD, PD } private bool isFinished = true; private Boataction nextState; private int count = 0; private int num = 0; private AutoMove() { }
-
然后是每次点击Next按钮将会直接调用的move函数,该函数首先调用getNext函数得到当前岸边的状态,确认接下来要进行的过程,再调用DoAction函数执行流程。
public void move() { if (isFinished) { isFinished = false; Debug.Log(count); int[] fromCount = firstScene.fromCoast.GetobjectsNumber(); priestNum = fromCount[0]; devilNum = fromCount[1]; BoatCoast = firstScene.boat.get_State(); if (count == 0) { nextState = getNext(); if ((int)nextState >= 3) { num = 2; } else if ((int)nextState > 0) num = 1; else num = 0; count++; } Debug.Log("next state is " + nextState); DoAction(); } }
-
DoACtion主要是按顺序调用各种模拟点击动作。
private void DoAction() { if (count == 1 && num != 0) { if (nextState == Boataction.D) { devilOnBoat(); } else if (nextState == Boataction.DD) { devilOnBoat(); } else if (nextState == Boataction.P) { priestOnBoat(); } else if (nextState == Boataction.PP) { priestOnBoat(); } else if (nextState == Boataction.PD) { priestOnBoat(); } count++; } else if (num == 2 && count == 2) { if (nextState == Boataction.DD) { devilOnBoat(); } else if (nextState == Boataction.PP) { priestOnBoat(); } else if (nextState == Boataction.PD) { devilOnBoat(); } count++; } else if((num == 1 && count == 2) || (num == 2 && count == 3) || (num == 0 && count == 1)) { firstScene.MoveBoat(); count++; } else if ((num == 1 && count >= 3) || (num == 2 && count >= 4) || (num == 0 && count>=2)) { GetOffBoat(); } isFinished = true; }
-
DoAction函数进行的动作分为三种,第一种devilOnBoat模拟点击魔鬼让其上船,第二种priestOnBoat模拟点击天使,第三种船移动。
private void GetOffBoat() { if((priestNum == 0 && devilNum == 2) || (priestNum == 0 && devilNum == 0)) { if (firstScene.boat.get_State() == -1) { foreach (var x in firstScene.boat.passenger) { if (x != null) { firstScene.ObjectIsClicked(x); break; } } if (firstScene.boat.isEmpty()) count = 0; } else count = 0; } else if (((priestNum == 0 && devilNum == 1)) && firstScene.boat.get_State() == 1) { count = 0; } else { foreach (var x in firstScene.boat.passenger) { if (x != null && x.getType() == 1) { firstScene.ObjectIsClicked(x); count = 0; break; } } if (count != 0) { foreach (var x in firstScene.boat.passenger) { if (x != null) { firstScene.ObjectIsClicked(x); count = 0; break; } } } } } private void priestOnBoat() { if(BoatCoast == 1) { foreach(var x in firstScene.fromCoast.passengerPlaner) { if (x!=null && x.getType() == 0) { firstScene.ObjectIsClicked(x); return; } } } else { foreach (var x in firstScene.toCoast.passengerPlaner) { if (x != null && x.getType() == 0) { firstScene.ObjectIsClicked(x); return; } } } } private void devilOnBoat() { if (BoatCoast == 1) { foreach (var x in firstScene.fromCoast.passengerPlaner) { if (x != null && x.getType() == 1) { firstScene.ObjectIsClicked(x); return; } } } else { foreach (var x in firstScene.toCoast.passengerPlaner) { if (x != null && x.getType() == 1) { firstScene.ObjectIsClicked(x); return; } } } }
-
得到下一步的方法根据状态图确认下一步进行的操作和目标。
private Boataction getNext() { Boataction next = Boataction.empty; if (BoatCoast == 1) { if (devilNum == 3 && priestNum == 3)//3P3DB { next = Boataction.PD; } else if (devilNum == 2 && priestNum == 3)//3P2DB { next = Boataction.DD; } else if (devilNum == 1 && priestNum == 3)//3P1DB { next = Boataction.PP; } else if (devilNum == 2 && priestNum == 2)//2P2DB { next = Boataction.PP; } else if (devilNum == 3 && priestNum == 0)//3DB { next = Boataction.DD; } else if (devilNum == 1 && priestNum == 1)//1P1DB { next = Boataction.PD; } else if (devilNum == 2 && priestNum == 0)//2DB { next = Boataction.D; } else if (devilNum == 1 && priestNum == 2)//2P1DB { next = Boataction.P; } else if (devilNum == 2 && priestNum == 1)//1P2DB { next = Boataction.P; } else if (devilNum == 1 && priestNum == 0)//1DB { next = Boataction.D; } else if(devilNum == 3 && priestNum == 2)//2P3DB { next = Boataction.D; } else next = Boataction.empty; } else { if (devilNum == 2 && priestNum == 2)//2P2D { next = Boataction.empty; } else if (devilNum == 1 && priestNum == 3)//3P1D { next = Boataction.empty; } else if (devilNum == 2 && priestNum == 3)//3P2D { next = Boataction.D; } else if (devilNum == 0 && priestNum == 3)//3P { next = Boataction.empty; } else if (devilNum == 1 && priestNum == 1)//1P1D { next = Boataction.D; } else if (devilNum == 2 && priestNum == 0)//2D { next = Boataction.D; } else if (devilNum == 1 && priestNum == 0)//1D { next = Boataction.empty; } else next = Boataction.empty; } return next; }
这次初步实现了简单的“智能”系统,这种系统可以方便的运用于对付简单NPC智能。这次是在之前作业基础上实现的,实现的时候因为第一次没考虑给这次留接口,所以写的时候还是挺困难的,以后要注意一下。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。