游戏玩法
游戏一开始会在场景中布置n多个小人,以及6个AI玩家,和一个真实的玩家自己
6个AI玩家和玩家自己共同抢夺场景中的小人,
1:谁抢夺到小人小人就归谁,并且加入到自己的队伍中,来提高自己队伍的吸人能力
2:在抢夺小人的过程中如果遇到玩家相遇,则相互吃,大的玩家就吃小的玩家
3: 在面对吃的时候,真实玩家可以依靠自己的判断,选择是吃还是跑,AI玩家则依靠状态机来做处理
状态划分
| 攻击---->InAttackArea 在攻击区域
| 逃跑---->InRunAwayArea 在逃跑区域
巡逻|| 吃别人---->CanEatObj 可以吃对象
| 死亡---->BeEaten 被吃掉
| 原地等待---->Init 初始化
|攻击---->InAttackArea 在攻击区域 可以发起攻击
|逃跑---->InRunAwayArea 在逃跑区域
吃别人||巡逻---->NotEatObj 没有可以吃的对象了 就转为巡逻状态吧
|死亡---->BeEaten 被被人吃掉了
|原地等待---->Init 初始化
|巡逻---->AttackGoalDeath 将目标打死了
|巡逻---->AttackTimeOut 攻击超时
攻击 ||死亡---->BeEaten 力量不及对手 反被吃掉了
|原地等待---->Init 初始化
|巡逻---->AwayEscape 已经逃到安全距离 可以转为巡逻状态了啊
|攻击---->AwayCanEat 在逃跑的路上发现有可以吃的对象
逃跑 ||死亡---->BeEaten 在逃跑的路上被吃掉了
|巡逻---->AwayGoalDeath 在逃跑的时候 发现本来要干我的坏人死掉了 那就安全了啊,可以转为巡逻
|原地等待---->Init 初始化
死亡 |原地等待--->Init 初始化
|巡逻-------> Revival 复活
原地等待 |巡逻--->Start
转变ID:
enum CharacterTransitionID
{
NullTransition,
Init,
Start,
CanEatObj,
NotEatObj,
InAttackArea,
AttackTimeOut,
AttackGoalDeath,
InRunAwayArea,
AwayEscape,
AwayCanEat,
AwayGoalDeath,
BeEaten,
Revival
}
状态ID:
enum CharacterStateID
{
NullState, //空状态
Patrol, //巡逻
EatObj, //吃
Attack, //攻击
RunAway, //逃跑
Death, //死亡
Stay //原地停留
}
CharacterManager
这个类主要负责管理角色
这是一个入口类,负责调度管理所有角色的状态
public start()
{
this.isStart = true;
this.mainCharacterController.start();
for (let i = 0; i < this.aiCharacterControllers.length; i++)
{
this.aiCharacterControllers[i].start();
}
this.checkCharacterDisIndex = 0;
Laya.timer.frameLoop(1, this, this.update);
}
//下面这个函数会每一帧更新一次
//假设真实玩家一共有m个,那么每一帧只更新一个玩家与其它所有玩家之间的距离
//假设这里的m是5
//第一帧:0 ---1 2 3 4
//第二帧: 1 ---2 3 4
//第三帧:2----3 4
//第四帧:3----4
//ok 四帧就是一个比较的轮回
//后面的就继续重复
private update()
{
this.setMaxShowPeople();
for (let i = 0; i < this.allCharacterControllers.length; i++)
{
this.allCharacterControllers[i].update();
if (i > this.checkCharacterDisIndex)
{
this.allCharacterControllers[this.checkCharacterDisIndex].updateCharacterDis(this.allCharacterControllers[i]);
}
}
this.checkCharacterDisIndex++;
this.checkCharacterDisIndex = this.checkCharacterDisIndex >= this.allCharacterControllers.length ? 0 : this.checkCharacterDisIndex;
}
FSMState:状态
这个是状态的基类,任何状态都会继承该类
该状态机含有下面这些状态
巡逻,停留,死亡,逃跑,攻击,吃
abstract class FSMState
{
//每一个状态
protected map: Dictionary<number, number> = new Dictionary<number, number>();
protected stateID: number;
public get id()
{
return this.stateID;
}
public addTransition(trans: number, id: number)
{
if (trans == 0)
{
console.log("FSMState Error: NullTransition");
return;
}
if (id == 0)
{
console.log("FSMState Error: NullStateID");
return;
}
if (this.map.ContainsKey(trans))
{
console.log("FSMState Error: Map already has TransitionID: " + trans.toString());
return;
}
this.map.Add(trans, id);
}
public deleteTransition(trans: number)
{
if (trans == 0)
{
console.log("FSMState Error: NullTransition");
return;
}
if (this.map.ContainsKey(trans))
{
this.map.Remove(trans);
return;
}
console.log("FSMState Error: Map not has TransitionID:" + trans.toString());
}
//获取输出状态
public getOutputState(trans: number): number
{
if (this.map.ContainsKey(trans))
{
return this.map.TryGetValue(trans);
}
return 0;
}
//进入新的状态之前
public abstract doBeforeEntering();
//进入新的状态之后
public abstract doBeforeLeaving();
//每一帧都会调用这个函数
//寻求新的状态更新
public abstract reason();
//更换状态以后 做动作
public abstract act();
}
状态子类
巡逻,停留,死亡,逃跑,攻击,吃
//巡逻状态
class PatrolState extends FSMState
{
private aiController: AICharacterController;
private transform: Transform3D;
private patrolPoint: Vector3;
private currentPatrolTime: number;
private patrolTime: number;
constructor(aiController: AICharacterController)
{
super();
this.stateID = CharacterStateID.Patrol;
this.aiController = aiController;
this.transform = this.aiController.obj.transform;
}
public doBeforeEntering()
{
this.setPatrolPoint();
this.patrolTime = Maths.randomFloat(CharacterConfig.aiPatrolTime[0], CharacterConfig.aiPatrolTime[1]);
this.currentPatrolTime = 0;
}
public doBeforeLeaving()
{
}
public reason()
{
if (this.aiController.isDeath)
{
this.aiController.setTransition(CharacterTransitionID.BeEaten);
return;
}
if (this.aiController.aiType == AIType.Bottom)
{
return;
}
let targetCharacter: CharacterController[] = this.aiController.getTargetCharacter();
if (targetCharacter[0] != null)
{
// Debug.log("patrol runaway:", targetCharacter[0].name);
this.aiController.runAwayCharacter = targetCharacter[0];
this.aiController.setTransition(CharacterTransitionID.InRunAwayArea);
return;
}
if (this.aiController.aiType == AIType.Lower)
{
return;
}
if (this.aiController.aiType == AIType.Senior || this.aiController.aiType == AIType.Middle)
{
if (targetCharacter[1] != null)
{
this.aiController.attackCharacter = targetCharacter[1];
this.aiController.setTransition(CharacterTransitionID.InAttackArea);
return;
}
}
let eatPeople: PeopleController = this.aiController.getInEatAreaPeople();
if (eatPeople != null && !eatPeople.hasFollow)
{
this.aiController.setTransition(CharacterTransitionID.CanEatObj);
}
}
public act()
{
if (this.getPatrolPointDistanceSquared() <= 0.3)
{
this.currentPatrolTime = 0;
this.setPatrolPoint();
}
if (this.currentPatrolTime >= this.patrolTime)
{
this.currentPatrolTime = 0;
this.setPatrolPoint();
}
else
{
this.currentPatrolTime += CharacterConfig.aiActionTimestep;
}
this.aiController.actionTargetPoint = this.patrolPoint;
}
private setPatrolPoint()
{
this.patrolPoint = ActiveAreaManager.instance.getCenterSpawnAndRoutePoints()[0];
// Gizmos.drawXYZ(this.patrolPoint);
}
private getPatrolPointDistanceSquared()
{
return Vector3.distanceSquared(this.transform.position, this.patrolPoint);
}
}
class EatObjState extends FSMState
{
private aiController: AICharacterController;
private transform: Transform3D;
private eatPeople: PeopleController;
private currentEatTime: number;
constructor(aiController: AICharacterController)
{
super();
this.stateID = CharacterStateID.EatObj;
this.aiController = aiController;
this.transform = this.aiController.obj.transform;
}
public doBeforeEntering()
{
this.eatPeople = this.aiController.getInEatAreaPeople();
// Debug.log(this.aiController.name, " enter eat obj:", this.eatPeople.peopleId);
this.currentEatTime = 0;
}
public doBeforeLeaving()
{
}
public reason()
{
if (this.aiController.isDeath)
{
this.aiController.setTransition(CharacterTransitionID.BeEaten);
return;
}
let targetCharacter: CharacterController[] = this.aiController.getTargetCharacter();
if (targetCharacter[0] != null)
{
this.aiController.runAwayCharacter = targetCharacter[0];
this.aiController.setTransition(CharacterTransitionID.InRunAwayArea);
return;
}
if (targetCharacter[1] != null)
{
this.aiController.attackCharacter = targetCharacter[1];
this.aiController.setTransition(CharacterTransitionID.InAttackArea);
return;
}
if (this.eatPeople == null)
{
this.aiController.setTransition(CharacterTransitionID.NotEatObj);
}
}
public act()
{
if (this.eatPeople != null && this.eatPeople.hasFollow)
{
this.eatPeople = this.aiController.getInEatAreaPeople();
// Debug.log("eat other:", this.eatPeople.peopleId);
}
if (this.eatPeople != null)
{
this.aiController.actionTargetPoint = this.eatPeople.obj.transform.position;
}
}
}
class AttackState extends FSMState
{
private aiController: AICharacterController;
private transform: Transform3D;
private attackCharacter: CharacterController;
private attackTime: number;
private attackDiffTime: number = 2;
private currentAttackDiffTime: number;
private targetPos: Vector3;
private isAttack: boolean;
constructor(aiController: AICharacterController)
{
super();
this.stateID = CharacterStateID.Attack;
this.aiController = aiController;
this.transform = this.aiController.obj.transform;
}
public doBeforeEntering()
{
this.attackCharacter = this.aiController.attackCharacter;
this.attackTime = 0;
this.currentAttackDiffTime = 0;
this.isAttack = true;
this.targetPos = this.attackCharacter.transform.position;
}
public doBeforeLeaving()
{
}
public reason()
{
if (this.aiController.isDeath)
{
this.aiController.setTransition(CharacterTransitionID.BeEaten);
return;
}
if (this.attackCharacter.isDeath)
{
this.aiController.setTransition(CharacterTransitionID.AttackGoalDeath);
return;
}
if (this.attackTime >= CharacterConfig.aiAttackTime && this.currentAttackDiffTime >= this.attackDiffTime)
{
this.aiController.setTransition(CharacterTransitionID.AttackTimeOut);
return;
}
}
public act()
{
this.attackTime += CharacterConfig.aiActionTimestep;
if (this.attackTime >= CharacterConfig.aiAttackTime)
{
if (this.isAttack)
{
if (Maths.randomBoolean())
{
this.attackTime = 0;
this.currentAttackDiffTime = 0;
this.isAttack = true;
this.targetPos = this.attackCharacter.transform.position;
}
else
{
if (this.aiController.getInEatAreaPeople() == null)
{
this.targetPos = new Vector3(-this.attackCharacter.transform.position.x, 0, -this.attackCharacter.transform.position.z);
}
else
{
this.targetPos = this.aiController.getInEatAreaPeople().obj.transform.position;
this.isAttack = false;
}
}
}
else
{
this.currentAttackDiffTime += CharacterConfig.aiActionTimestep;
}
}
else
{
this.targetPos = this.attackCharacter.transform.position;
}
this.aiController.actionTargetPoint = this.targetPos;
}
}
//逃跑状态
class RunAwayState extends FSMState
{
private aiController: AICharacterController;
private transform: Transform3D;
private runAwayCharacter: CharacterController;
private currentRunAwayTime: number;
private awayPoint: Vector3;
private isRandomRunAway: boolean = false;
private tempV: Vector3;
constructor(aiController: AICharacterController)
{
super();
this.stateID = CharacterStateID.RunAway;
this.aiController = aiController;
this.transform = this.aiController.obj.transform;
this.awayPoint = Vector3.ZERO.clone();
this.tempV = Vector3.ZERO.clone();
}
public doBeforeEntering()
{
// Debug.log(this.aiController.name, " enter run away");
this.runAwayCharacter = this.aiController.runAwayCharacter;
this.currentRunAwayTime = 0;
this.isRandomRunAway = false;
// Gizmos.drawXYZ(this.awayPoint, 3);
}
public doBeforeLeaving()
{
}
public reason()
{
if (this.aiController.isDeath)
{
this.aiController.setTransition(CharacterTransitionID.BeEaten);
return;
}
if (this.runAwayCharacter == null || this.runAwayCharacter.isDeath)
{
this.aiController.setTransition(CharacterTransitionID.AwayGoalDeath);
return;
}
let targetCharacter: CharacterController[] = this.aiController.getTargetCharacter();
if (targetCharacter[1] != null && targetCharacter[1] == this.runAwayCharacter)
{
this.aiController.attackCharacter = targetCharacter[1];
this.aiController.setTransition(CharacterTransitionID.AwayCanEat);
return;
}
if (this.canNotRunAway())
{
this.aiController.setTransition(CharacterTransitionID.AwayEscape);
return;
}
}
public act()
{
let targetCharacter: CharacterController[] = this.aiController.getTargetCharacter();
if (targetCharacter[0] != null && targetCharacter[0] != this.runAwayCharacter)
{
this.runAwayCharacter = targetCharacter[0];
this.currentRunAwayTime = 0;
}
if (this.currentRunAwayTime > CharacterConfig.aiRunAwayTime)
{
this.awayPoint.x = Maths.randomFloat(-1, 1);
this.awayPoint.z = Maths.randomFloat(-1, 1);
Vector3.normalize(this.awayPoint, this.awayPoint);
this.currentRunAwayTime = 0;
if (!this.isRandomRunAway)
{
this.isRandomRunAway = true;
}
}
else
{
this.currentRunAwayTime += CharacterConfig.aiActionTimestep;
if (!this.isRandomRunAway)
{
Vector3.subtract(this.aiController.transform.position, this.runAwayCharacter.transform.position, this.awayPoint);
Vector3.normalize(this.awayPoint, this.awayPoint);
}
}
// Debug.log(this.awayPoint);
Vector3.add(this.awayPoint, this.aiController.transform.position, this.tempV);
this.aiController.actionTargetPoint = this.tempV;
}
private canNotRunAway()
{
if (this.runAwayCharacter == null)
{
Debug.log("not runAwayCharacter");
return true;
}
if (Vector3.distanceSquared(this.aiController.transform.position, this.runAwayCharacter.transform.position) >= CharacterConfig.aiNotRunAwayDis * CharacterConfig.aiNotRunAwayDis)
{
// Debug.log("runaway patrol:", Vector3.distanceSquared(this.aiController.getXZPos(), this.runAwayCharacter.getXZPos()));
return true;
}
return false;
}
}
class DeathState extends FSMState
{
private aiController: AICharacterController;
constructor(aiController: AICharacterController)
{
super();
this.stateID = CharacterStateID.Death;
this.aiController = aiController;
}
public doBeforeEntering()
{
// Debug.log(this.aiController.name, " enter death");
}
public doBeforeLeaving()
{
}
public reason()
{
if (!this.aiController.isDeath)
{
this.aiController.setTransition(CharacterTransitionID.Revival);
}
}
public act()
{
}
}
class StayState extends FSMState
{
private aiController: AICharacterController;
constructor(aiController: AICharacterController)
{
super();
this.stateID = CharacterStateID.Stay;
this.aiController = aiController;
}
public doBeforeEntering()
{
Debug.log(this.aiController.name, " enter stay");
}
public doBeforeLeaving()
{
}
public reason()
{
if (this.aiController.getIsStart())
{
this.aiController.setTransition(CharacterTransitionID.Start);
}
}
public act()
{
}
}
FSMSystem:状态机
class FSMSystem
{
private states: FSMState[] = [];
private _currentStateID: number;
private _currentState: FSMState;
public get currentStateID(): number
{
return this._currentStateID;
}
public get currentState(): FSMState
{
return this._currentState;
}
public FSMSystem()
{
this.states = [];
}
//添加一个状态
public addState(s: FSMState)
{
if (s == null)
{
console.log("FSMSystem Error: Null FSMState");
}
if (this.states.length == 0)
{
this.states.push(s);
this._currentState = s;
this._currentStateID = s.id;
return;
}
for (let i = 0; i < this.states.length; i++)
{
if (this.states[i].id == s.id)
{
console.log("FSMSystem Error: FSMState:" + s.id.toString() + "already been added");
return;
}
}
this.states.push(s);
}
//删除状态
public deleteState(id: number)
{
if (id == 0)
{
console.log("FSMSystem Error: NullStateID");
return;
}
for (let i = 0; i < this.states.length; i++)
{
if (this.states[i].id == id)
{
this.states.splice(i, 1);
return;
}
}
console.log("FSMSystem Error:" + id.toString() + "not has");
}
/*
受外界调节刺激,来表现一个新的状态
这个状态一定是被事先注册进来的
* @param trans
*/
public performTransition(trans: number)
{
if (trans == 0)
{
console.log("FSMSystem Error: NullTransition");
return;
}
let outputState: number = this._currentState.getOutputState(trans);
if (outputState == 0)
{
console.log("FSMSystem Error:" + this._currentStateID.toString() + " does not have a target state for transition " + trans.toString());
return;
}
this._currentStateID = outputState;
for (let i = 0; i < this.states.length; i++)
{
if (this.states[i].id == this._currentStateID)
{
this._currentState.doBeforeLeaving();
this._currentState = this.states[i];
this._currentState.doBeforeEntering();
break;
}
}
}
}
AICharacterController:角色控制类
每一个角色都有一个该类的实例
/**
*
* 每一个ai角色都会有一个下面AICharacterController的实例化对象
*/
class AICharacterController extends CharacterController
{
private fsm: FSMSystem;
/**
* 将要被我攻击的玩家 对方玩家很弱 将要被我攻击
*/
private _attackCharacter: CharacterController;
/**
* 将要攻击我的玩家 对方玩家很强 将要攻击我 所以我准备逃跑
*/
private _runAwayCharacter: CharacterController;
/**
* 0 表示一个将要吃掉自己的玩家 1 表示一个自己将要吃掉的玩家
*/
private runAwayAttackCharacter: CharacterController[] = [null, null];
private runAwayAttackDis: number[] = [null, null];
private _aiType: AIType; //ai类型
private aiAttackDisSqu: number;//ai攻击距离
private aiRunAwayDisSqu: number;//ai逃跑距离
private _actionTargetPoint: Vector3 = null;
private currentActionTime: number = 0;
private tempV: Vector3 = Vector3.ZERO.clone();
public get aiType(): AIType
{
return this._aiType;
}
public set aiType(value: AIType)
{
this._aiType = value;
if (this._aiType == AIType.Senior)
{
this.aiEatObjDisSqu = CharacterConfig.aiMaxEatObjDis * CharacterConfig.aiMaxEatObjDis;
this.aiAttackDisSqu = CharacterConfig.aiMaxAttackDis * CharacterConfig.aiMaxAttackDis;
}
else if (this._aiType == AIType.Middle)
{
this.aiEatObjDisSqu = CharacterConfig.aiMinEatObjDis * CharacterConfig.aiMinEatObjDis;
this.aiAttackDisSqu = CharacterConfig.aiMinAttackDis * CharacterConfig.aiMinAttackDis;
}
else if (this._aiType == AIType.MiddleNoKill)
{
this.aiEatObjDisSqu = CharacterConfig.aiMinEatObjDis * CharacterConfig.aiMinEatObjDis;
this.aiAttackDisSqu = null;
}
else
{
this.aiEatObjDisSqu = null;
this.aiAttackDisSqu = null;
}
this.aiRunAwayDisSqu = CharacterConfig.aiRunAwayDis * CharacterConfig.aiRunAwayDis;
}
public get attackCharacter(): CharacterController
{
return this._attackCharacter;
}
public set attackCharacter(value: CharacterController)
{
this._attackCharacter = value;
}
public get runAwayCharacter(): CharacterController
{
return this._runAwayCharacter;
}
public set runAwayCharacter(value: CharacterController)
{
this._runAwayCharacter = value;
}
public set actionTargetPoint(value: Vector3)
{
this._actionTargetPoint = value;
}
public get obj()
{
return this._obj;
}
public getIsStart()
{
return this.isStart;
}
public init()
{
// this.eatCharacterFunction = this.eatCharacter;
this.updateCharacterDisFunction = this.onUpdateCharacterDis;
this.registerFSM();
}
public setInitPeopleNum(initPeopleNum: number)
{
this.peopleNum = initPeopleNum + 1;
}
public starting()
{
this.rotateSpeed = CharacterConfig.aiRotateSpeed;
this.maxSpeed = CharacterConfig.maxSpeed;
this.setInitPeople(this.peopleNum - 1);
this.initCharacter();
this.startCharacter();
}
public start()
{
this.isStart = true;
this._isDeath = false;
this.currentActionTime = 0;
this.playRunAni();
this.initPeopleStartMove();
}
public restart()
{
this.init();
this.initCharacter();
this.isStart = true;
this._isDeath = false;
this.currentActionTime = 0;
}
public revival(revivalPeopleNum: number, revivalPos: Vector3)
{
// this.revivalCharacter(CharacterConfig.revivalRadiusKeepRate);
this.isStart = true;
this._isDeath = false;
this.currentActionTime = 0;
this.revivalCharacter(revivalPeopleNum,revivalPos);
}
public pause()
{
this.isStart = !this.isStart;
}
public end()
{
this.isStart = false;
if (this.isStart)
{
this.setTransition(CharacterTransitionID.Init);
}
}
public clear()
{
this.clearCharacter();
}
public eatCharacter(character: CharacterController)
{
}
/**
* 更新当前玩家和这个玩家之间的距离
* @param character
*/
public onUpdateCharacterDis(character: CharacterController)
{
// Debug.log("onUpdateCharacterDis")
if (this._aiType == AIType.Bottom)
{
return;
}
if (character.isDeath)
{
return;
}
if ((character.peopleNum - this.peopleNum) >= CharacterConfig.eatNumDiff)
{
//外边来的这个玩家所携带的人数比当前这个玩家所携带的人多 所以当前这个玩家有可能被消灭掉
//下面是判断
let runAwayAttack: any = this.canAttackByDis(character.transform.position, this.aiRunAwayDisSqu);
// Debug.log("runaway:", this.name, " ", character.name, runAwayActive.dis,runAwayActive.isCan);
if (runAwayAttack.isCan && (this.runAwayAttackDis[0] == null || runAwayAttack.dis < this.runAwayAttackDis[0]))
{
this.runAwayAttackCharacter[0] = character; //这个外来玩家将要杀死当前玩家 先保存下来
this.runAwayAttackDis[0] = runAwayAttack.dis;
}
if (!runAwayAttack.isCan && this.runAwayAttackCharacter[0] == character)
{
this.runAwayAttackCharacter[0] = null;
this.runAwayAttackDis[0] = null;
}
}
if (this._aiType == AIType.Lower || this._aiType == AIType.MiddleNoKill)
{
return;
}
if ((this.peopleNum - character.peopleNum) >= CharacterConfig.eatNumDiff)
{
//当前玩家所携带的人数大于外来玩家的人数 那么外来玩家有可能被消灭掉
let attackAttack: any = this.canAttackByDis(character.transform.position, this.aiAttackDisSqu);
if (attackAttack.isCan && (this.runAwayAttackDis[1] == null || attackAttack.dis < this.runAwayAttackDis[1]))
{
this.runAwayAttackCharacter[1] = character; //这个外来玩家将要被当前玩家吃掉 先保存下来
this.runAwayAttackDis[1] = attackAttack.dis;
}
if (!attackAttack.isCan && this.runAwayAttackCharacter[1] == character)
{
this.runAwayAttackCharacter[1] = null;
this.runAwayAttackDis[1] = null;
}
}
}
/**
* 获取目标玩家
* 要么来消灭我的玩家 要么我可以消灭的玩家
*/
public getTargetCharacter(): CharacterController[]
{
if (this.runAwayAttackCharacter[0] != null && this.runAwayAttackCharacter[0].isDeath)
{
this.runAwayAttackCharacter[0] = null;
this.runAwayAttackDis[0] = null;
}
if (this.runAwayAttackCharacter[1] != null && this.runAwayAttackCharacter[1].isDeath)
{
this.runAwayAttackCharacter[1] = null;
this.runAwayAttackDis[1] = null;
}
return this.runAwayAttackCharacter;
}
/**
* 是否来得及逃跑或者说还有存活的机会吗
* @param targetPos
* @param disSqu
*/
private canAttackByDis(targetPos: Vector3, disSqu: number): any
{
let distance: number = Vector3.distanceSquared(targetPos, this.transform.position);
if (distance <= disSqu)
{
//在攻击范围
return { isCan: true, dis: distance };
}
else
{
//不在攻击范围
return { isCan: false, dis: distance };
}
}
public update()
{
super.update();
if (!this.isStart)
{
return;
}
this.currentActionTime += Laya.timer.delta / 1000;
if (this.currentActionTime >= CharacterConfig.aiActionTimestep)
{
if (this.fsm != null)
{
//调用这个函数进行状态更替
this.fsm.currentState.reason();
//注意上面的函数调用以后 当前状态可能会发生改变
this.fsm.currentState.act();
}
this.currentActionTime = 0;
}
this.moveCharacter();
}
//注册状态机
private registerFSM()
{
//状态机
this.fsm = new FSMSystem();
//巡逻
let patrolState: PatrolState = new PatrolState(this);
//巡逻的时候 可以攻击
patrolState.addTransition(CharacterTransitionID.InAttackArea, CharacterStateID.Attack);
//巡逻的时候 可以逃跑
patrolState.addTransition(CharacterTransitionID.InRunAwayArea, CharacterStateID.RunAway);
//巡逻的时候 可以吃别人
patrolState.addTransition(CharacterTransitionID.CanEatObj, CharacterStateID.EatObj);
//巡逻的时候 可以死亡
patrolState.addTransition(CharacterTransitionID.BeEaten, CharacterStateID.Death);
//巡逻的时候 可以原地等待
patrolState.addTransition(CharacterTransitionID.Init, CharacterStateID.Stay);
//吃
let eatObjState: EatObjState = new EatObjState(this);
//吃的时候 可以攻击
eatObjState.addTransition(CharacterTransitionID.InAttackArea, CharacterStateID.Attack);
//吃的时候 可以逃跑
eatObjState.addTransition(CharacterTransitionID.InRunAwayArea, CharacterStateID.RunAway);
//吃的时候 可以死亡
eatObjState.addTransition(CharacterTransitionID.BeEaten, CharacterStateID.Death);
//吃的时候 可以巡逻
eatObjState.addTransition(CharacterTransitionID.NotEatObj, CharacterStateID.Patrol);
//吃的时候 可以原地等待
eatObjState.addTransition(CharacterTransitionID.Init, CharacterStateID.Stay);
//攻击
let attackState: AttackState = new AttackState(this);
//在攻击的时候 可以巡逻
attackState.addTransition(CharacterTransitionID.AttackGoalDeath, CharacterStateID.Patrol);
//在攻击的时候 可以巡逻
attackState.addTransition(CharacterTransitionID.AttackTimeOut, CharacterStateID.Patrol);
//在攻击的时候 可以死亡
attackState.addTransition(CharacterTransitionID.BeEaten, CharacterStateID.Death);
//在攻击的时候 可以原地等待
attackState.addTransition(CharacterTransitionID.Init, CharacterStateID.Stay);
//逃跑
let runAwayState: RunAwayState = new RunAwayState(this);
//在逃跑的时候 可以巡逻
runAwayState.addTransition(CharacterTransitionID.AwayEscape, CharacterStateID.Patrol);
//在逃跑的时候,可以攻击
runAwayState.addTransition(CharacterTransitionID.AwayCanEat, CharacterStateID.Attack);
//在逃跑的时候,可以死亡
runAwayState.addTransition(CharacterTransitionID.BeEaten, CharacterStateID.Death);
//在逃跑的时候,可以巡逻
runAwayState.addTransition(CharacterTransitionID.AwayGoalDeath, CharacterStateID.Patrol);
//在逃跑的时候,可以原地打转
runAwayState.addTransition(CharacterTransitionID.Init, CharacterStateID.Stay);
//死亡
let deathState: DeathState = new DeathState(this);
//在死亡的时候,可以原地打转
deathState.addTransition(CharacterTransitionID.Init, CharacterStateID.Stay);
//在死亡的时候,可以巡逻
deathState.addTransition(CharacterTransitionID.Revival, CharacterStateID.Patrol);
//等待
let stayState: StayState = new StayState(this);
//在等待的时候,可以巡逻
stayState.addTransition(CharacterTransitionID.Start, CharacterStateID.Patrol);
this.fsm.addState(stayState);
this.fsm.addState(patrolState);
this.fsm.addState(eatObjState);
this.fsm.addState(attackState);
this.fsm.addState(runAwayState);
this.fsm.addState(deathState);
}
public setTransition(t: number)
{
this.fsm.performTransition(t);
}
//移动角色
public moveCharacter()
{
if (!this.isStart || this.isDeath)
{
return;
}
if (this._actionTargetPoint == null)
{
return;
}
this.tempV.x = this._transform.position.x;
this.tempV.y = 0;
this.tempV.z = this._transform.position.z;
Vector3.subtract(this._actionTargetPoint, this.tempV, this.tempV);
Vector3.normalize(this.tempV, this.tempV);
this.rotateForward = this.tempV;
this.move();
this.rotate();
}
}