首页 » IT学院 » 正文

Unity3D:有限状态机

Unity3D:有限状态机

 

在U3D游戏开发中,我们不可避免的要处理一些游戏状态的改变,对于状态,逻辑简单一点的游戏来说,我们一般是这么做的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
enum State_Type
{
GameMenu,
GameLoading,
GameLogic,
GameOver,
}
 
 
void Update()
{
     switch(currentstate)
     {
    case State_Type. GameMenu:
        if( 按了开始按钮 )
        {
            currentstate=State_Type. GameLoading;
        }
        if( 按了成就 )
        {
            currentstate=State_Type……..;
        }
        if(按了高分榜)
        {
            currentstate=State_Type……..;
        }
 
    break;
             case State_Type. GameLoading:
        if( 加载游戏完成 )
        {
            currentstate=State_Type. GameLogic;
        }
    break;
             case State_Type. GameLogic:
        if( 死了 )
        {
            currentstate=State_Type. GameOver;
        }
    break;
             case State_Type. GameOver:
            currentstate=State_Type. GameMenu;
    break;
    }
}
但是,这种状态机的使用只能应对一些简单的状态,如果游戏过程非常复杂,那么,这种方法就很难实现了。
对于复杂的游戏状态,我们通常使用有限状态机(FSM)

下面是一个例子

两个实体
ActorOne
ActorTwo

第一个实体ActorOne
复制代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
using UnityEngine;
using System.Collections;
public class ActorOne  : BaseGameEntity {
    //有限状态机
    StateMachine<ActorOne> m_pStateMachine;
    void Start () {
        //设置实体的id必须唯一
        SetID((int)EntityID.m_ActorOne);
 
        //注册
        m_pStateMachine = new StateMachine<ActorOne>(this);
        /*
            一个状态分为三个阶段
                   Enter()       //进入
                   Execute() //执行
                   Exit()           //离开
 
            当m_pStateMachine.SetCurrentState(ActorOne_StateOne .Instance());
 
            会先执行ActorOne_StateOne 的Enter()方法,
            然后执行ActorOne_StateOne 的Execute()方法, Execute方法会一直执行直到切换状态
 
            当在ActorOne_StateOne(Enter(), Execute())中调用Entity.GetFSM().ChangeState(ActorOne_StateTwo.Instance());
 
            会先执行ActorOne_StateOne 的Exit();
            然后执行ActorOne_StateTwo的Enter()方法,
            然后执行ActorOne_StateTwo的Execute()方法,
 
 
        */
 
 
        //设置当前的状态为ActorOne_StateOne
        m_pStateMachine.SetCurrentState(ActorOne_StateOne .Instance());   
        //设置全局的状态
        m_pStateMachine.SetGlobalStateState(ActorOne_GloballState .Instance());
 
 
        //实体注册到实体管理器中
        EntityManager.Instance().RegisterEntity(this);
    }
 
    void Update ()
    {   
        //状态机update
        m_pStateMachine.SMUpdate();
    }
 
 
    public StateMachine<ActorOne> GetFSM ()
    {
        //获得状态机
        return m_pStateMachine;
    }
 
    public override bool HandleMessage (Telegram telegram)
    {
        //解析消息
        return     m_pStateMachine.HandleMessage(telegram);
    }
}

第2个实体ActorTwo
复制代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
using UnityEngine;
using System.Collections;
public class ActorTwo  : BaseGameEntity {
 
    StateMachine<ActorTwo> m_pStateMachine;
 
    public Transform TwoTransform;
 
    // Use this for initialization
    void Start () {
 
 
        // set id
        SetID((int)EntityID.m_ActorTwo);
 
        m_pStateMachine = new StateMachine<ActorTwo>(this);
 
        m_pStateMachine.SetCurrentState(ActorTwo_StateOne.Instance());   
 
 
        m_pStateMachine.SetGlobalStateState(ActorTwo_GloballState.Instance());
        EntityManager.Instance().RegisterEntity(this);
    }
 
    void Update ()
    {   
 
        m_pStateMachine.SMUpdate();
    }
 
 
    public StateMachine<ActorTwo> GetFSM ()
    {
        return m_pStateMachine;
    }
 
    public override bool HandleMessage (Telegram telegram)
    {
        return     m_pStateMachine.HandleMessage(telegram);
 
 
    }
}

ActorOneState 第一个实体的状态

复制代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
using UnityEngine;
using System.Collections;
 
 
/*
状态分为两种
1全局状态 一般情况下会一直执行 可以负责调度
2普通状态 也就是上面的GameMenu,GameLoading,GameLogic,GameOver,
*/
//全局状态
public class ActorOne_GloballState :State<ActorOne >
{
    private static ActorOne_GloballState instance;
    public static ActorOne_GloballState Instance ()
    {
        if (instance == null)
            instance = new ActorOne_GloballState ();
 
        return instance;
    }
 
    //当状态被调用是执行一次
    public override void Enter (ActorOne Entity)
    {
        //base.Enter (Entity);
    }
 
 
    //相当于update方法
    public override void Execute (ActorOne Entity)
    {
        //base.Execute (Entity);   
    }
 
    //状态退出是被调用
    public override void Exit (ActorOne Entity)
    {
        //base.Exit (Entity);
    }
 
    //接收消息
    public override bool OnMessage (ActorOne Entity, Telegram telegram)
    {
        return false;
    }
}
 
 
public class ActorOne_StateOne : State<ActorOne>
{
    private static ActorOne_StateOne instance;
    public static ActorOne_StateOne Instance ()
    {
        if (instance == null)
            instance = new ActorOne_StateOne ();
 
        return instance;
    }
 
    public override void Enter (ActorOne Entity)
    {
        //base.Enter (Entity);
    }
 
 
    public override void Execute (ActorOne Entity)
    {
        /*
        调用实体的GetFSM()获得状态机器
        在调用状态机的ChangeState(ActorOne_StateTwo.Instance())
        改变状态
        这里是从当前状态ActorOne_StateOne切换到ActorOne_StateTwo状态;
        */
        Entity.GetFSM().ChangeState(ActorOne_StateTwo.Instance());
        //base.Execute (Entity);
    }
 
 
    public override void Exit (ActorOne Entity)
    {
        //base.Exit (Entity);
    }
 
 
    public override bool OnMessage (ActorOne Entity, Telegram telegram)
    {
        return false;
    }
}
 
 
 
 
public class ActorOne_StateTwo : State<ActorOne>
{
    private static ActorOne_StateTwo instance;
    public static ActorOne_StateTwo Instance ()
    {
        if (instance == null)
            instance = new ActorOne_StateTwo ();
 
        return instance;
    }
 
    public override void Enter (ActorOne Entity)
    {
        /*
            MessageDispatcher.Instance().DispatchMessage();用于在实体间传送消息
 
 
            下面代码的意思就是
            发送消息给ActorTwo,延迟5秒发送,消息的类型msg_oneMessage
        */
        MessageDispatcher.Instance().DispatchMessage(
                5f, // delay 消息的延迟时间
                                Entity.ID(),        // sender 发送者
                               (int)EntityID.m_ActorTwo,            // receiver 接收者
                               (int)message_type.msg_oneMessage,    //message
                                Entity);  //附加信息
        //base.Enter (Entity);
    }
 
 
    public override void Execute (ActorOne Entity)
    {
        //base.Execute (Entity);
    }
 
 
    public override void Exit (ActorOne Entity)
    {
        //base.Exit (Entity);
    }
 
 
    public override bool OnMessage (ActorOne Entity, Telegram telegram)
    {
        /*
            接收ActorTwo发送过来的消息(message_type.msg_twoMessage)
        */
        if(telegram.Msg == (int)message_type.msg_twoMessage)
        {
            /*
                接收成功
            */
            return true;
        }
 
        return false;
    }
}

ActorTwo 第2个实体的具体状态
复制代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
using UnityEngine;
using System.Collections;
 
 
public class ActorTwo_GloballState : State<ActorTwo>
{
    private static ActorTwo_GloballState instance;
    public static ActorTwo_GloballState Instance ()
    {
        if (instance == null)
            instance = new ActorTwo_GloballState ();
 
        return instance;
    }
 
 
 
 
    public override void Enter (ActorTwo Entity)
    {
        //base.Enter (Entity);
    }
 
 
    public override void Execute (ActorTwo Entity)
    {
        //base.Execute (Entity);   
    }
 
 
    public override void Exit (ActorTwo Entity)
    {
        //base.Exit (Entity);
    }
 
 
    //消息处理
    public override bool OnMessage (ActorTwo Entity, Telegram telegram)
    {
        /*
            接收ActorOne发送来的消息(message_type.msg_oneMessage)
        */
        if (telegram.Msg == (int)message_type.msg_oneMessage) {
            /*
                接收成功处理消息从当前状态切换到ActorTwo_StateTwo状态;
            */
            Entity.GetFSM ().ChangeState (ActorTwo_StateTwo.Instance ());
            return true;
        }
 
        return false;
    }
}
 
 
public class ActorTwo_StateOne : State<ActorTwo>
{
    private static ActorTwo_StateOne instance;
    public static ActorTwo_StateOne Instance ()
    {
        if (instance == null)
            instance = new ActorTwo_StateOne ();
 
        return instance;
    }
 
 
    public override void Enter (ActorTwo Entity)
    {
        //base.Enter (Entity);
    }
 
 
    public override void Execute (ActorTwo Entity)
    {
        //base.Execute (Entity);
    }
 
 
    public override void Exit (ActorTwo Entity)
    {
        //base.Exit (Entity);
    }
 
 
    public override bool OnMessage (ActorTwo Entity, Telegram telegram)
    {
        return false;
    }
}
 
 
 
 
public class ActorTwo_StateTwo : State<ActorTwo>
{
    private static ActorTwo_StateTwo instance;
    public static ActorTwo_StateTwo Instance ()
    {
        if (instance == null)
            instance = new ActorTwo_StateTwo ();
 
        return instance;
    }
 
 
    public override void Enter (ActorTwo Entity)
    {
        /*
            发送消息给ActorOne,延迟1秒,消息类型msg_twoMessage
        */
        MessageDispatcher.Instance ().DispatchMessage(
                1f,
                Entity.ID (),
                (int)EntityID.m_ActorOne,
                (int)message_type.msg_twoMessage,
                Entity);
 
 
        //base.Enter (Entity);       
    }
 
 
    public override void Execute (ActorTwo pMiner)
    {
        //base.Execute (Entity);
 
 
    }
 
 
    public override void Exit (ActorTwo Entity)
    {
        //base.Exit (Entity);
    }
 
 
    public override bool OnMessage (ActorTwo Entity, Telegram telegram)
    {
 
        return false;
    }
}

这样看起来就很清晰了修改起来只要修改具体的状态类就行了。

在使用的时候最好写一个状态表

实体一
当前状态                             条件                                            目标状态/实体
睡觉                           被打醒了                                         狂暴
狂暴                        无条件                               投降

 (转自:http://www.ceeger.com/forum/read.php?tid=817)

发表评论