大人吃小人的游戏用到的状态机

游戏玩法

游戏一开始会在场景中布置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();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值