开启辅助访问
 找回密码
 注册帐号

扫一扫,访问微社区

开发者专栏

关注:1729

当前位置:游戏蛮牛 技术专区 开发者专栏

__________________________________________________________________________________
开发者干货区版块规则:

  1、文章必须是图文形式。(至少2幅图)
      2、文章字数必须保持在1500字节以上。(编辑器右下角有字数检查)
      3、本版块只支持在游戏蛮牛原创首发,不支持转载。
      4、本版块回复不得无意义,如:顶、呵呵、不错......【真的会扣分的哦】
      5、......
__________________________________________________________________________________
查看: 1844|回复: 29

[livin] 装逼者日记3-超简单有限状态机

[复制链接]  [移动端链接]
排名
222
昨日变化
2

24

主题

396

帖子

3008

积分

Rank: 9Rank: 9Rank: 9

UID
10602
好友
15
蛮牛币
6292
威望
0
注册时间
2013-12-18
在线时间
846 小时
最后登录
2017-6-27

专栏作家认证开发者

发表于 2016-5-26 10:27:54 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册帐号

x
       手游开发中,怪物的AI部分,用的最多的实现方式莫过于有限状态机了,那什么是有限状态机了,这个你自己百度好了,概念我就不解释了       我个人的经验对于有限状态机的理解是,有限状态机是一种状态的管理集合,集合里面存储者各种各样的状态,那么什么是状态了,在游戏的开发中,人或者怪物的行动会定义
各种各样的状态,比如RUN,ATTACK,IDLE,DEAD等等,在这里提个装逼小技巧,以前我面试一家公司的时候,那个装逼的CTO跟我说的,我说我熟悉有限状态机,他就问我,什么是状态,
我答了半天,他都不满意,最后他跟我说什么是状态,是一种输入输出控制的改变,比如玩家做了什么操作,对应着一种输入输出控制,至于他说的对不对,反正他在我面前装逼成功了。
好了,闲话不多撤,上代码
状态基类
[C#] 纯文本查看 复制代码
using UnityEngine;
/// <summary>
/// 状态基类,定义了状态的基础方法
/// 为什么需要定义为3个呢
/// 是因为有些逻辑都是进入状态或者退出状态的时候执行的,
/// 所以这里将逻辑分开:
/// 分为:
/// 1>进入状态,
/// 2>状态执行,
/// 3>状态退出
/// </summary>
/// <typeparam name="entity_type">使用泛型,哪个状态使用,就传入哪个状态</typeparam>
public class _State<entity_type>
{

    /// <summary>
    /// 使用状态的对象
    /// </summary>
    public entity_type Target;

    /// <summary>
    /// 进入状态的逻辑
    /// 只执行一次的逻辑
    /// </summary>
    /// <param name="entityType"></param>
    public virtual void Enter()
    {
        Debug.Log(this.ToString()+"    Enter");
    }

    /// <summary>
    /// 执行状态的逻辑
    /// </summary>
    /// <param name="entityType"></param>
    public virtual void Excute()
    {
    
    
    }

    /// <summary>
    /// 退出状态的逻辑
    /// </summary>
    /// <param name="entityType"></param>
    public virtual void Exit()
    {
        Debug.Log(this.ToString() + "    Exit");
    }


}


下面是状态机
[C#] 纯文本查看 复制代码
using UnityEngine;
using System.Collections;

/// <summary>
/// 状态机
/// 使用这个来驱动各种状态
/// </summary>
/// <typeparam name="entity_type"></typeparam>
public class _StateMachine<entity_type>
{
    //状态持有对象
    private entity_type m_pOwner;

    //
    private _State<entity_type> m_pCurrentState;//当前状态
    private _State<entity_type> m_pPreviouState;//上一个状态
    private _State<entity_type> m_pGlobalState;//全局状态


    /// <summary>
    /// 状态机的构造函数
    /// </summary>
    /// <param name="owner"></param>
    public _StateMachine(entity_type owner)
    {
        m_pOwner = owner;
        m_pPreviouState = null;
        m_pCurrentState = null;
        m_pGlobalState = null;
    }

    /// <summary>
    /// 设置当前状态
    /// </summary>
    /// <param name="GlobalState"></param>
    public void SetCurrentState(_State<entity_type> CurrentState)
    {
        if (CurrentState != null)
        {
            //保存 当前状态
            m_pCurrentState = CurrentState;
            //设置 状态中的 Target 为
            m_pCurrentState.Target = m_pOwner;
            m_pCurrentState.Enter();
        }
    }


    /// <summary>
    /// 进入全局状态
    /// 进行一些数据的刷新,比如说距离的计算等
    /// </summary>
    /// <param name="GlobalState"></param>
    public void SetGlobalState(_State<entity_type> GlobalState)
    {
        if (GlobalState != null)
        {
            m_pGlobalState = GlobalState;
            m_pGlobalState.Target = m_pOwner;
            m_pGlobalState.Enter();
        }
        else
        {
            Debug.LogError("不能设置空状态");
        }
    }


    /// <summary>
    /// 进入全局状态d
    /// </summary>
    public void GlobalStateEnter()
    {

    }






    /// <summary>
    /// Update方法
    /// </summary>
    public void SmUpdate()
    {
        //只要设置了.就会一直执行
        if (m_pGlobalState != null)
        {
            m_pGlobalState.Excute();
        }
        if (m_pCurrentState != null)
        {
            m_pCurrentState.Excute();
        }
    }


    /// <summary>
    /// 切换状态
    /// </summary>
    /// <param name="pNewState">希望变成的状态</param>
    public void ChangeState(_State<entity_type> pNewState)
    {

        if (pNewState == null)
        {
            Debug.Log("不能使用空的状态");
        }
        //触发状态退出方法
        m_pCurrentState.Exit();

        //保存上一状态
        m_pPreviouState = m_pCurrentState;

        //设置新状态为当前状态
        m_pCurrentState = pNewState;
        //传递 状态 使用 对象
        m_pCurrentState.Target = m_pOwner;

        //触发当前状态调用Enter方法
        m_pCurrentState.Enter();
    }

    /// <summary>
    /// 切换回上一状态
    /// </summary>
    public void RevertToPreviousState()
    {
        this.ChangeState(m_pPreviouState);
    }

    /// <summary>
    /// 获取当前状态
    /// </summary>
    /// <returns></returns>
    public _State<entity_type> Get_CurrentState()
    {
        return m_pCurrentState;
    }

    public _State<entity_type> Get_GlobalState()
    {
        return m_pGlobalState;
    }



    /// <summary>
    /// 获取上一状态
    /// </summary>
    /// <returns></returns>
    public _State<entity_type> Get_PreviousState()
    {
        return m_pPreviouState;
    }
}



下面来做个Demo
AI类
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public enum CubeState
{
    Run,
    Idle,

}

public class CubeAI : MonoBehaviour
{
    FsmStateMachine<CubeAI> m_Machine;//状态机对象用来管理状态的
    public Dictionary<CubeState, FsmState<CubeAI>> StateDic; //状态字典,用来存放状态


    void Awake()
    {
        StateDic = new Dictionary<CubeState, FsmState<CubeAI>>();
        StateDic.Add(CubeState.Run, new CubeRun());
        StateDic.Add(CubeState.Idle, new CubeIdle());
    }

    // Use this for initialization
    void Start()
    {
        m_Machine = new FsmStateMachine<CubeAI>(this);

        m_Machine.SetCurrentState(StateDic[CubeState.Idle]);
    }

    // Update is called once per frame
    void Update()
    {
        m_Machine.SmUpdate();
    }

    public void ChangeAIState(CubeState state)
    {
        m_Machine.ChangeState(StateDic[state]);
    }
}

RUN状态类
[C#] 纯文本查看 复制代码
using UnityEngine;
using System.Collections;

public class CubeRun : FsmState<CubeAI>
{
    int runTime = 0;
    float delateTime = 0;
    public override void Enter()
    {
        base.Enter();
        Debug.Log("Cube 进入了人生思考阶段");
        runTime = Random.Range(5, 10);
        delateTime = 0;
    }

    public override void Excute()
    {
        base.Excute();
        Target.transform.Translate(Vector3.forward * 1 * Time.deltaTime);
        Debug.Log("Cube 快乐的奔跑中,跑到了" + Target.transform.position);
        delateTime += Time.deltaTime;
        if (delateTime >= runTime)
        {
            Target.ChangeAIState(CubeState.Idle);
        }
    }

    public override void Exit()
    {
        base.Exit();
        Debug.Log("Cube 跑类了");
    }
}


Idle状态类
[C#] 纯文本查看 复制代码
using UnityEngine;
using System.Collections;

public class CubeIdle : FsmState<CubeAI>
{
    int idleTime = 0;
    float delateTime = 0;
    int i = 0;
    public override void Enter()
    {
        base.Enter();
        Debug.Log("Cube 进入了人生思考阶段");
        i = 0;
        delateTime = 0;
        idleTime = Random.Range(8, 16);
    }

    public override void Excute()
    {
        base.Excute();
        i++;
        Debug.Log("Cube 在思考人生" + i);
        delateTime += Time.deltaTime;
        if (delateTime >= idleTime)
        {
            Target.ChangeAIState(CubeState.Run);
        }
    }

    public override void Exit()
    {
        base.Exit();
        Debug.Log("Cube 结束了人生思考");
        i = 0;
    }

}





New Unity Project.zip

1.65 MB, 下载次数: 234

评分

参与人数 5鲜花 +9 收起 理由
001122xx + 2 赞一个!
zouzhixun + 2 很给力!
frank_wei + 1
tiansher123 + 2 很给力!
dengboge + 2 很给力!

查看全部评分


回复

使用道具 举报

4四处流浪
368/500
排名
4924
昨日变化
3

0

主题

49

帖子

368

积分

Rank: 4

UID
399
好友
1
蛮牛币
263
威望
20
注册时间
2013-6-20
在线时间
117 小时
最后登录
2017-6-16

专栏作家

发表于 2016-5-26 11:37:57 | 显示全部楼层
这么好的帖子为什么木有人来顶顶呢

回复 支持 反对

使用道具 举报

排名
222
昨日变化
2

24

主题

396

帖子

3008

积分

Rank: 9Rank: 9Rank: 9

UID
10602
好友
15
蛮牛币
6292
威望
0
注册时间
2013-12-18
在线时间
846 小时
最后登录
2017-6-27

专栏作家认证开发者

 楼主| 发表于 2016-5-26 15:28:15 | 显示全部楼层
phoenixlhs 发表于 2016-5-26 11:37
这么好的帖子为什么木有人来顶顶呢

哈哈,这个状态机可是能达到商业级的哦

回复 支持 反对

使用道具 举报

排名
222
昨日变化
2

24

主题

396

帖子

3008

积分

Rank: 9Rank: 9Rank: 9

UID
10602
好友
15
蛮牛币
6292
威望
0
注册时间
2013-12-18
在线时间
846 小时
最后登录
2017-6-27

专栏作家认证开发者

 楼主| 发表于 2016-5-26 15:28:18 | 显示全部楼层
phoenixlhs 发表于 2016-5-26 11:37
这么好的帖子为什么木有人来顶顶呢

哈哈,这个状态机可是能达到商业级的哦

回复 支持 反对

使用道具 举报

4四处流浪
460/500
排名
3248
昨日变化
1

0

主题

30

帖子

460

积分

Rank: 4

UID
65825
好友
1
蛮牛币
1911
威望
0
注册时间
2015-1-5
在线时间
108 小时
最后登录
2017-4-11
发表于 2016-5-27 09:23:48 | 显示全部楼层
速来围观

回复

使用道具 举报

4四处流浪
411/500
排名
10626
昨日变化
9

0

主题

63

帖子

411

积分

Rank: 4

UID
102788
好友
0
蛮牛币
286
威望
0
注册时间
2015-5-24
在线时间
289 小时
最后登录
2017-6-14
发表于 2016-5-27 09:27:58 | 显示全部楼层
学到了...
[发帖际遇]: 一个袋子砸在了 safdds 头上,safdds 赚了 1 蛮牛币. 幸运榜 / 衰神榜

回复

使用道具 举报

6蛮牛粉丝
1230/1500
排名
1862
昨日变化
5

3

主题

270

帖子

1230

积分

Rank: 6Rank: 6Rank: 6

UID
130474
好友
0
蛮牛币
2205
威望
0
注册时间
2015-12-1
在线时间
407 小时
最后登录
2017-6-28
发表于 2016-5-27 10:18:49 | 显示全部楼层
switch用多了,是时候学习状态有限状态机了顶一个

回复 支持 反对

使用道具 举报

5熟悉之中
989/1000
排名
2165
昨日变化
7

0

主题

106

帖子

989

积分

Rank: 5Rank: 5

UID
147766
好友
0
蛮牛币
322
威望
0
注册时间
2016-5-6
在线时间
403 小时
最后登录
2017-6-29
QQ
发表于 2016-5-27 13:48:10 | 显示全部楼层
学习一个先

回复

使用道具 举报

6蛮牛粉丝
1164/1500
排名
1576
昨日变化
3

1

主题

186

帖子

1164

积分

Rank: 6Rank: 6Rank: 6

UID
2272
好友
1
蛮牛币
1194
威望
0
注册时间
2013-8-20
在线时间
365 小时
最后登录
2017-6-7

VIP

发表于 2016-5-30 09:39:50 | 显示全部楼层
好牛逼,学习了,很有用

回复 支持 反对

使用道具 举报

3偶尔光临
161/300
排名
11155
昨日变化
6

0

主题

48

帖子

161

积分

Rank: 3Rank: 3Rank: 3

UID
55588
好友
0
蛮牛币
95
威望
0
注册时间
2014-11-15
在线时间
61 小时
最后登录
2016-8-29
发表于 2016-5-30 09:48:06 | 显示全部楼层
至于厉不厉害 反正在我面前装逼成功了

回复 支持 反对

使用道具 举报

6蛮牛粉丝
1003/1500
排名
2501
昨日变化
1

10

主题

160

帖子

1003

积分

Rank: 6Rank: 6Rank: 6

UID
59605
好友
0
蛮牛币
2088
威望
0
注册时间
2014-12-5
在线时间
415 小时
最后登录
2017-6-29
发表于 2016-5-31 09:02:22 | 显示全部楼层
学习了,下载运行下

回复 支持 反对

使用道具 举报

3偶尔光临
255/300
排名
7844
昨日变化
4

0

主题

66

帖子

255

积分

Rank: 3Rank: 3Rank: 3

UID
98960
好友
0
蛮牛币
365
威望
0
注册时间
2015-5-9
在线时间
86 小时
最后登录
2017-6-15
QQ
发表于 2016-5-31 23:11:52 | 显示全部楼层
有限状态机该好好研究下了,switch党飘过

回复 支持 反对

使用道具 举报

5熟悉之中
667/1000
排名
3878
昨日变化
5

1

主题

168

帖子

667

积分

Rank: 5Rank: 5

UID
34428
好友
0
蛮牛币
1228
威望
0
注册时间
2014-7-15
在线时间
228 小时
最后登录
2017-6-26
发表于 2016-6-1 11:08:08 | 显示全部楼层
牛掰 我会一直关注你的帖子

回复 支持 反对

使用道具 举报

5熟悉之中
667/1000
排名
3878
昨日变化
5

1

主题

168

帖子

667

积分

Rank: 5Rank: 5

UID
34428
好友
0
蛮牛币
1228
威望
0
注册时间
2014-7-15
在线时间
228 小时
最后登录
2017-6-26
发表于 2016-6-1 11:14:22 | 显示全部楼层
大牛  有没有简单的“行为

回复 支持 反对

使用道具 举报

5熟悉之中
667/1000
排名
3878
昨日变化
5

1

主题

168

帖子

667

积分

Rank: 5Rank: 5

UID
34428
好友
0
蛮牛币
1228
威望
0
注册时间
2014-7-15
在线时间
228 小时
最后登录
2017-6-26
发表于 2016-6-1 11:15:17 | 显示全部楼层
行为树        。。。。。。。。。。              

回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册帐号

本版积分规则

快速回复 返回顶部 返回列表