游戏中的有限状态机 (StateMachine)

/**
 * 状态机的组成主要是:状态机框架对象(我程序代码中的StateMachine)状态机中的三种状态eat,work,sleep
 * 状态机负责指挥这三种状态(甚至更多种状态)的变换,让他们是按照一定的先后顺序来走,符合我们的预期目的。
 * 然后就是到底谁需要使用状态机呢,我程序里面有2个对象用到了状态机,分别是vokie和NBA.
 * 他们是通过"sm = new StateMachine(this);"这样一句代码来实现对状态机的绑定,
 * 他们各自拥有一个状态机,不过我这里偷懒了,用了很蹩脚的instanceof方法来做的,其实可以写成2个状态机
 * 绑定以后,我们就可以在eat,work,sleep中处理Person跟Team对象了。
 * @author Administrator
 *
 */


首先是可能存在的状态的接口定义:(基本的流程)

public interface IState {
	public void enter(Object o);
	public void excute(Object o);
	public void exit(Object o);
}

状态机中包含的三种状态定义:

/**
 * 吃饭状态机,任何绑定使用该状态机的对象(Person Team)都可以在StateMachine的指导下、完成吃饭状态
 *
 */

public class EatState implements IState{
	public EatState() {
	}

	@Override
	public void enter(Object obj) {
		if(obj instanceof Person)
		{
			Person p = (Person)obj;
			System.out.println("Eat-1:煮饭~   执行者:"+p.getName());
		}else{
			Team t = (Team)obj;
			System.out.println("Eat-1:煮饭~   执行者:"+t.getName());
		}
	}

	@Override
	public void excute(Object obj) {
		if(obj instanceof Person)
		{
			Person p = (Person)obj;
			System.out.println("Eat-2:吃饭~   执行者:"+p.getName());
		}else{
			Team t = (Team)obj;
			System.out.println("Eat-2:吃饭~   执行者:"+t.getName());
		}
	}

	@Override
	public void exit(Object obj) {
		if(obj instanceof Person)
		{
			Person p = (Person)obj;
			System.out.println("Eat-3:洗碗~   执行者:"+p.getName());
		}else{
			Team t = (Team)obj;
			System.out.println("Eat-3:洗碗~   执行者:"+t.getName());
		}
	}
}
public class WorkState implements IState{
	public WorkState() {
	}

	@Override
	public void enter(Object obj) {
		if(obj instanceof Person)
		{
			Person p = (Person)obj;
			System.out.println("work-1:上班~   执行者:"+p.getName());
		}else{
			Team t = (Team)obj;
			System.out.println("work-1:上班~   执行者:"+t.getName());
		}
	}

	@Override
	public void excute(Object obj) {
		if(obj instanceof Person)
		{
			Person p = (Person)obj;
			System.out.println("work-2:工作~   执行者:"+p.getName());
		}else{
			Team t = (Team)obj;
			System.out.println("work-2:工作~   执行者:"+t.getName());
		}
	}

	@Override
	public void exit(Object obj) {
		if(obj instanceof Person)
		{
			Person p = (Person)obj;
			System.out.println("work-3:下班~   执行者:"+p.getName());
		}else{
			Team t = (Team)obj;
			System.out.println("work-3:下班~   执行者:"+t.getName());
		}
	}
}
public class SleepState implements IState{
	public SleepState() {
	}

	@Override
	public void enter(Object obj) {
		if(obj instanceof Person)
		{
			Person p = (Person)obj;
			System.out.println("Sleep-1:关灯~   执行者:"+p.getName());
		}else{
			Team t = (Team)obj;
			System.out.println("Sleep-1:关灯~   执行者:"+t.getName());
		}
	}

	@Override
	public void excute(Object obj) {
		if(obj instanceof Person)
		{
			Person p = (Person)obj;
			System.out.println("Sleep-2:睡觉~   执行者:"+p.getName());
		}else{
			Team t = (Team)obj;
			System.out.println("Sleep-2:睡觉~   执行者:"+t.getName());
		}
	}

	@Override
	public void exit(Object obj) {
		if(obj instanceof Person)
		{
			Person p = (Person)obj;
			System.out.println("Sleep-3:起床~   执行者:"+p.getName());
		}else{
			Team t = (Team)obj;
			System.out.println("Sleep-3:起床~   执行者:"+t.getName());
		}
	}
}


需要使用到状态机的对象:Person & Team

public class Person {
	private String name;
	
	private StateMachine sm;
	
	public Person(String name) {
		this.name = name;
		sm = new StateMachine(this);
		sm.setState(new WorkState());
		sm.getState().enter(this);
	}

	public StateMachine getStateMachine()
	{
		return sm;
	}

	public String getName() {
		// TODO Auto-generated method stub
		return name;
	}
}
import java.util.ArrayList;

public class Team {
	private ArrayList<String> nameList = new ArrayList<String>();
	
	private StateMachine sm;
	
	public Team(ArrayList<String> nameList) {
		this.nameList = nameList;
		sm = new StateMachine(this);
		sm.setState(new WorkState());
		sm.getState().enter(this);
	}

	public StateMachine getStateMachine()
	{
		return sm;
	}

	public String getName() {
		StringBuilder sb = new StringBuilder();
		for(String str:nameList)
			sb.append("  |  ").append(str);
		return sb.toString();
	}
}

然后是状态机这个大框架:

/**
 * 从一种状态向另一种状态的转移,最常见的就是操作系统里面的状态图,游戏中也经常用到关于状态图
 * 比如游戏中篮球运动员投篮的一套动作流程:运球->急停->起跳->投篮.
 * 我这里用例是人一天的作息状态转换:工作->吃饭->休息
 */
class StateMachine
{
	public IState currentState;  //当前正在执行的状态
	public IState previousState;  //前一个状态
	public Object owner;  //状态机的拥有者,也就是说明该对象需要使用状态机的机制
	public StateMachine(Object t_obj)
    {
    	owner = t_obj;
    	currentState = null;
    	previousState = null;
    }

    public boolean excute()
    {
    	if(currentState != null)
     	{
        	currentState.excute(owner);
        	return true;
    	}
    	return false;
    }

    //状态机改变状态
    public boolean changeState(IState newState)
    {
    	if(newState == null)
    	{
        	return false;
    	}
    	previousState = currentState;   //保存当前的状态
    	currentState.exit(owner);   //退出当前状态
    	currentState = newState;
    	currentState.enter(owner);  //进入新的状态
     	return true;
    }

    public boolean reverseToPreviousState()
    {
    	return changeState(previousState);
    }
    
    public void setState(IState state)
    {
    	currentState = state;
    }
    
    public IState getState()
    {
    	return currentState;
    }
}

最后是测试代码:

import java.util.ArrayList;

public class Demo {
	public static void main(String[] args) {
		Person vokie = new Person("vokie");
		
		//执行工作状态机的excute方法
		vokie.getStateMachine().excute();
		//传入SleeState,让SleepState来处理person类中的变量等等
		vokie.getStateMachine().changeState(new SleepState());
		vokie.getStateMachine().excute();
		vokie.getStateMachine().changeState(new EatState());
		vokie.getStateMachine().excute();
		vokie.getStateMachine().changeState(new WorkState());
		vokie.getStateMachine().excute();
		vokie.getStateMachine().changeState(new SleepState());
		
		//下面测试代码的作用是想表达的是:状态机可以处理其拥有者owner的逻辑,变量
		ArrayList<String> nameList = new ArrayList<String>();
		nameList.add("Smith");
		nameList.add("Kobe");
		nameList.add("James");
		Team NBA = new Team(nameList);
		NBA.getStateMachine().excute();
		//传入SleepState,让SleepState来处理Team类中的所有成员
		NBA.getStateMachine().changeState(new SleepState());
		NBA.getStateMachine().excute();
		NBA.getStateMachine().changeState(new EatState());
		NBA.getStateMachine().excute();
		NBA.getStateMachine().changeState(new WorkState());
		NBA.getStateMachine().excute();
		NBA.getStateMachine().changeState(new SleepState());
	}
}


运行结果:

work-1:上班~   执行者:vokie
work-2:工作~   执行者:vokie
work-3:下班~   执行者:vokie
Sleep-1:关灯~   执行者:vokie
Sleep-2:睡觉~   执行者:vokie
Sleep-3:起床~   执行者:vokie
Eat-1:煮饭~   执行者:vokie
Eat-2:吃饭~   执行者:vokie
Eat-3:洗碗~   执行者:vokie
work-1:上班~   执行者:vokie
work-2:工作~   执行者:vokie
work-3:下班~   执行者:vokie
Sleep-1:关灯~   执行者:vokie
work-1:上班~   执行者:  |  Smith  |  Kobe  |  James
work-2:工作~   执行者:  |  Smith  |  Kobe  |  James
work-3:下班~   执行者:  |  Smith  |  Kobe  |  James
Sleep-1:关灯~   执行者:  |  Smith  |  Kobe  |  James
Sleep-2:睡觉~   执行者:  |  Smith  |  Kobe  |  James
Sleep-3:起床~   执行者:  |  Smith  |  Kobe  |  James
Eat-1:煮饭~   执行者:  |  Smith  |  Kobe  |  James
Eat-2:吃饭~   执行者:  |  Smith  |  Kobe  |  James
Eat-3:洗碗~   执行者:  |  Smith  |  Kobe  |  James
work-1:上班~   执行者:  |  Smith  |  Kobe  |  James
work-2:工作~   执行者:  |  Smith  |  Kobe  |  James
work-3:下班~   执行者:  |  Smith  |  Kobe  |  James
Sleep-1:关灯~   执行者:  |  Smith  |  Kobe  |  James


原文地址:https://www.cnblogs.com/vokie/p/3602068.html