Unity 有限状态机(FSM)

有限状态机可以为敌人提供一个简单的AI系统,它能够允许我们手动的去操作单独编写每个状态,并为其播放动画,但是需要玩家控制的player并不太适合有限状态机,玩家的输入事件太过复杂

编写一个IState接口,让所有的状态都去实现这三个接口,

接口中定义三个抽象函数,分别是:
OnEnter() :在每次进入该状态时会调用一次, 
OnExecute() : 每帧执行一次
OnExit(): 退出状态时执行一次
public interface IState{
    
    
	void onEnter();
	void OnExecute();
	void OnExit();
}

完善有限状态机脚本

1.定义枚举类型的所需状态
2.定义我们所需要的类,并且时期能够被序列化[Serliazeable]
using System; //使用[Serializable]所需要的命名空间
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum StateType{
    
    
	Idle, Attack, Patrol
}

[Serializable]
public class Parameter{
    
    
	public float idleTime;
	public Animation animator;
	public Transform target;
}

public class FSM : MonoBevirour{
    
    
	
	public Parameter parameter;
	public IState currentState ;
	private Dictionary<StateType, IState> dict = new Dictionart<StateType, IState>();
	void Start(){
    
    
		dict.Add(StateType.Idle, new IdleState(this));
        dict.Add(StateType.Attack, new AttackState(this));
        dict.Add(StateType.Patrol, new PatrolState(this));
		TransitionState(StateType.Idle);

	}
	
	//物理运动建议使用FixedUpdate 函数来更新
	void FixedUpdate(){
    
    
		currentState.OnExecute();
	}
	
	//提供一个公共函数来转换状态
	void TransitionState(StateType targetState){
    
    
		if(currentState != null){
    
    
			currentState.OnExit();
		}
		currentState = dict[targetState];
		currentState.OnEnter();
	}
}

接下来让具体状态类继承接口并且去实现抽象函数

可以把所有的具体状态放在一个文件中修改
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class IdleState : IState{
    
    
	
	private FSM manager;
    private Parameter parameter;
    private float timer = 0;
    public IdleState(FSM manager)
    {
    
    
        this.manager = manager;
        this.parameter = manager.parameter;
    }

    public void OnEnter()
    {
    
    
        parameter.animator.SetTrigger("idle");
    }

    public void OnExecute()
    {
    
       
        // parameter.animator.SetTrigger("idle");
        timer += Time.deltaTime;

        if(timer > parameter.idleTime){
    
    
            manager.TransitionState(StateType.Patrol);
        }
        
        if(parameter.target)
        {
    
       
            manager.TransitionState(StateType.Attack);
        }
    }

    public void OnExit()
    {
    
    
        timer = 0;
    }
	
}

//巡逻
public class PatrolState : IState
{
    
    
    private FSM manager;

    private Parameter parameter;

    private int patrolPosition = 0;
    public PatrolState(FSM manager)
    {
    
    
        this.manager = manager;
        this.parameter = manager.parameter;
    }


    public void OnEnter()
    {
    
    
        parameter.animator.SetBool("isRun",true);
    }

    public void OnExecute()
    {
    
       
        //如果发现了玩家,并追击范围
        //note : 应该主动撤销target的方式来节俭判定
        if(parameter.target)
        {
    
       
            manager.TransitionState(StateType.Chase);
        }

        //使敌人持续朝向下一个巡逻点
        manager.FlipTo(parameter.patrolPoints[patrolPosition]);
        
        // Debug.Log("Patrol" + parameter.animator.GetBool("isRun"));

        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(StateType.Idle);
        }
    }

    public void OnExit()
    {
    
    
        parameter.animator.SetBool("isRun",false);

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


//攻击
public  class AttackState : IState {
    
    
	private FSM manager;

    private Parameter parameter;

    private AnimatorStateInfo info;

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

    public void OnEnter()
    {
    
    
        parameter.animator.Play("Attack");
    }

    public void OnExecute()
    {
    
       
        //得到动画器的播放状态
        info = parameter.animator.GetCurrentAnimatorStateInfo(0);
        if(info.normalizedTime > .95f){
    
    
            manager.TransitionState(StateType.Chase);
        }
    }

    public void OnExit()
    {
    
       

    }
} 


代码仅提供思路,由于是默写的,不能确保没有错误

猜你喜欢

转载自blog.csdn.net/blastospore/article/details/130580078