怪物AI-状态模式

1、技术概述

  •   使用该技术的情况:在游戏开发中 怪物AI逻辑的实现
  • 学习必要性:实现怪物AI逻辑
  • 难点:该技术只是将状态模式运用于怪物AI的实现,没有特别的难点

2、技术案例

状态模式

在面向对象系统设计中,经常会遇到依赖于状态的对象。对象的行为会根据状态的改变而改变。

例如:一个怪物(人)对象,在饿的状态:会进入吃人的状态;在暴怒的状态:会进入暴动的状态;

如果一个对象(类)是依赖于状态的,那么程序员在描述改对象的类中,通常会使用许多条件语句来覆盖所有的条件以及 在 这些条件下的对象的行为。

例如:

if (monster is 饿)
吃人();
else if (monster is 暴怒)
暴走();
//但是这种方法对于比较复杂的状态判断容易产生错误。

基于大量的条件语句的处理方法有很多不便之处。

首先,增加一个新的状态将会导致对类的大量修改,因此该设计不容易扩展与维护;

另外,状态的转换不明显,也可能发生编程错误。

一个有效的方法就是利用状态模式

状态模式的结构类图如下:

 

 

 

1)Context:定义了与客户程序的接口,它保持了一个ConcreteState的代表现在状态的实例。

(2)State:定义了状态的接口,它的各个子类封装了在各种不同状态的行为。

(3)ConcreteState子类:封装了在各种不同状态下的行为。

状态模式在实现怪物AI中的例子

例子中,怪物只有两种装填:站立和巡逻:

  

 

 

 类图:

 

1)FSM:相当于Context类,Finite State Machine的缩写。
    属性parameter封装了怪物移动速度、血量、攻击力等数值;
    currentState表示当前怪物所处的状态;
    states维护了注册到FSM的状态,包括IdleState、ParolState;
    transitionState()方法的作用为切换状态。 (
2)IState:相当于State接口:
    OnEnter()方法在进入状态时执行;
    OnUpdate()方法在该状态下时执行;
    OnExit()方法在退出该状态时执行。 (
3)IdleState和PatrolState:
    相当于ConcreteState类,类中的manager表示状态机类FSM。

具体实现:

(1)在FSM类中注册站立状态和巡逻状态,即:将两个状态类的对象添加到states中。
(2)并将当前状态currentState设置为IdleState。
(3)当要切换状态时,状态类会在OnUpdate()方法中利用其属性manager调用FSM类的transitionState()方法,切换状态;

  transitionState()方法会利用currentState属性依次调用前一状态的OnExit()方法,和新状态的OnEnter()方法进行初始化。

Ts 代码:

1、首先两个状态类

/** 站立状态*/
export class IdleState implements IState {
    private manager: FSM = null!;
    private parameter: Parameter = null!;
    private timer: number = 0;

    public constructor(manager: FSM) {
        this.manager = manager;
        this.parameter = manager.parameter;
    }

    fight(): void {

    }

    public onEnter(): void {
        this.parameter.animator.setValue("走的动作属性", false);//停止走动画
        this.parameter.animator.setValue("站立的动作属性", true);//开始站立的动画
    }

    public onExit(): void {
        this.timer = 0;
    }

    public onUpdate(): void {
        this.timer += Time.deltaTime;
        if (this.timer >= this.parameter.idleTime) {
            this.manager.transitionState(StateType.Patrol);
        }
    }
}
/* 走状态 */
export class PatrolState implements IState {
    private manager: FSM = null!;
    private parameter: Parameter = null!;
    private patrolPosition: number = 0;

    public constructor(manager: FSM) {
        this.manager = manager;
        this.parameter = manager.parameter;
    }

    public onEnter(): void {
        this.parameter.animator.setValue("站立的动作属性", false);//停止站立动画
        this.parameter.animator.setValue("走的动作属性", true);//开始走的动画
    }

    public onExit(): void {
        this.patrolPosition++;
        if (this.patrolPosition >= this.parameter.patrolPoints.length) {
            this.patrolPosition = 0;
        }
    }

    public onUpdate(): void {
        let position = this.parameter.patrolPoints[this.patrolPosition];
        tween(this.manager.node).to(this.parameter.moveSpeed * Time.deltaTime, { position: position });

        if (math.Vec3.distance(this.manager.node.position, position) < 0.1) {
            this.manager.transitionState(StateType.Idle);
        }
    }
}

2、然年状态机 类



/**
 * enum StateType
 */
export enum StateType {
    //站立
    Idle,
    //跑路
    Patrol
}

/*
* * Paramater * 怪物包含的参数 */ export interface Parameter { //行走的速度 moveSpeed: number; //站立的时间 idleTime: number; //行走的点 patrolPoints: Vec3[]; //动作控制,这里使用的3D最新的玩偶动画 animator: animation.AnimationController; } /* 怪物的有限状态机FSM */ export default class FSM extends Component { public parameter: Parameter = null!; private currentState: IState = null!; private states: Dictionary<StateType, IState> = new Dictionary<StateType, IState>(); start(): void { this.states.add(StateType.Idle, new IdleState(this)); this.states.add(StateType.Patrol, new PatrolState(this)); this.transitionState(StateType.Idle); } update(): void { this.currentState.onUpdate(); } public transitionState(type: StateType): void { if (this.currentState != null) { this.currentState.onExit(); } this.currentState = this.states.tryGetValue(type); this.currentState.onEnter(); } }

 

Unity代码:

/* IState接口 */
public interface IState
{
    void OnEnter();
    void OnUpdate();
    void OnExit();
}
/* 站立状态 */
public class IdleState : IState
{
    private FSM manager;
    private Parameter parameter;
    private float timer;

    public IdleState(FSM manager)
    {
        this.manager = manager;
        this.parameter = manager.parameter;
    }

    public void OnEnter()
    {
    }

    public void OnExit()
    {
        timer = 0;
    }

    public void OnUpdate()
    { 
        timer += Time.deltaTime;
        if (timer >= parameter.idleTime)
        {
            manager.transitionState(StateType.Patrol);
        }
    }
}
/* 巡逻状态 */
public class PatrolState : IState
{
    private FSM manager;
    private Parameter parameter;
    private int patrolPosition;

    public PatrolState(FSM manager)
    {
        this.manager = manager;
        this.parameter = manager.parameter;
    }

    public void OnEnter()
    {
    }

    public void OnExit()
    {
        patrolPosition++;
        if (patrolPosition >= parameter.patrolPoints.Length)
        {
            patrolPosition = 0;
        }
    }

    public void OnUpdate()
    {
        manager.transform.position = Vector2.MoveTowards(manager.transform.position,
           parameter.patrolPoints[patrolPosition].position, parameter.moveSpeed * Time.deltaTime);
        if (Vector2.Distance(manager.transform.position, parameter.patrolPoints[patrolPosition].position) < 0.1f)
        {
            manager.transitionState(BeeStateType.Idle);
        }
    }
}
/* 状态枚举 */
public enum StateType
{
      Idle,Patrol
}
/* 怪物包含的参数 */
public class Parameter
{
       public float moveSpeed;
    public float idleTime;
       public Transform[] patrolPoints;
       public Animator animator;
}
/* 怪物的有限状态机FSM */
public class FSM : MonoBehaviour
{
    public Parameter parameter;

    private IState currentState;
    private Dictionary<StateType, IState> states = new Dictionary<StateType, IState>();

    void Start()
    {
        states.Add(StateType.Idle, new IdleState(this));
        states.Add(StateType.Patrol, new PatrolState(this));

        transitionState(StateType.Idle);
    }

    void Update()
    {
        currentState.OnUpdate();
    }

    public void transitionState(StateType type)
    {
        if (currentState != null)
        {
            currentState.OnExit();
        }
        currentState = states[type];
        currentState.OnEnter();
    }
}

 

posted @ 2022-09-21 10:18  jiaxin2015  阅读(362)  评论(0)    收藏  举报