美文网首页
浅谈游戏AI设计--有限状态机

浅谈游戏AI设计--有限状态机

作者: _codelover | 来源:发表于2018-08-05 13:24 被阅读0次

    游戏AI设计中,常用的方法有有限状态机行为树等,最基本的也就是状态机了,下面用一个实例来记录下有限状态机的实现。

    1,设计有限状态机

    首先需要为游戏AI设计出合理的状态图,并且确定各个状态的转换条件。下面设计一个简单的有限状态机。

    状态:
    • 巡逻
    • 攻击
    • 躲避
    状态转换条件
    • 敌人距离AI的距离
    • 血量


      图片.png

    2,代码实现

    设计模式--状态模式
    状态模式.png
    context类,状态机的一些初始化,以及切换状态
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using UnityEngine;
    
    namespace Assets
    {
        class Context
        {
            public Data data;
            public Ai ai;
    
            /// <summary>
            /// 当前状态
            /// </summary>
            Status status;
    
            /// <summary>
            /// 构造,默认巡逻状态
            /// </summary>
            public Context(Ai _ai)
            {
                ai = _ai;
                status = new FindStatus();
            }
            /// <summary>
            /// 改变状态   
            /// </summary>
            /// <param name="_status"></param>
            public void ChangeStatus(Status _status)
            {
                Debug.Log("血量:" + data.Hp + "距离player:" + data.DistanceAiToPlayer);
                status = _status;
            }
    
            /// <summary>
            /// 执行动作
            /// </summary>
            public void DoAction(Data _data)
            {
                data = _data;
                status.Action(this);
            }
            
        }
    }
    

    Status状态接口

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace Assets
    {
        interface Status
        {
            void Action(Context context);
        }
    }
    
    

    FindSatus具体状态,巡逻状态

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using UnityEngine;
    
    namespace Assets
    {
        class FindStatus : Status
        {
            public FindStatus()
            {
                Debug.Log("进入巡逻模式");
    
            }
            public const float MaxDistance = 5;
            public const float MaxRange = 5;
            public void Action(Context context)
            {
                context.ai.RecoveryHp();
                if(context.data.DistanceAiToPlayer < MaxDistance)
                {
                    context.ChangeStatus(new AttackStatus());
                }
                else
                {
                    context.ai.StopMove();
                }
            }
        }
    }
    
    

    AvoidStatus具体状态,躲避状态

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using UnityEngine;
    
    namespace Assets
    {
        class AvoidStatus : Status
        {
            public AvoidStatus()
            {
                Debug.Log("进入躲避模式");
    
            }
            public const float MinHp = 10;
            public void Action(Context context)
            {
               
                context.ai.FarAwayPlayer();
                if(context.data.DistanceAiToPlayer > FindStatus.MaxDistance)
                {
                    context.ChangeStatus(new FindStatus());
                }
            }
        }
    }
    
    

    AttackStatus具体状态,攻击状态

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using UnityEngine;
    
    namespace Assets
    {
        class AttackStatus : Status
        {
            public AttackStatus()
            {
                Debug.Log("进入攻击模式");
            }
            public void Action(Context context)
            {
                context.ai.MoveToPlayer();
                context.ai.BeAttack();
                if(context.data.Hp < AvoidStatus.MinHp)
                {
                    context.ChangeStatus(new AvoidStatus());
                }else if(context.data.Hp > AvoidStatus.MinHp && context.data.DistanceAiToPlayer > FindStatus.MaxDistance)
                {
                    context.ChangeStatus(new FindStatus());
                }
            }
        }
    }
    
    

    player控制脚本

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class player : MonoBehaviour {
        Rigidbody rigidbody;
    
        // Use this for initialization
        void Start () {
            rigidbody = GetComponent<Rigidbody>();
        }
        
        // Update is called once per frame
        void Update () {
            float x = Input.GetAxis("Horizontal");
            float z = Input.GetAxis("Vertical");
            rigidbody.AddForce(new Vector3(x, 0, z).normalized * 2);
        }
    }
    
    

    游戏AI控制脚本

    using Assets;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class Ai : MonoBehaviour {
    
        public GameObject player;
        float Hp = 20;
        Rigidbody rigidbody;
    
        Context context;
        // Use this for initialization
        void Start () {
            context = new Context(this);
            rigidbody = GetComponent<Rigidbody>();
        }
        
        // Update is called once per frame
        void Update () {
            
            context.DoAction(GetData());
        }
    
        /// <summary>
        /// 获取各种条件
        /// </summary>
        /// <returns></returns>
        Data GetData()
        {
            Data data = new Data();
            data.DistanceAiToPlayer = Vector3.Distance(transform.position, player.transform.position);
            data.Hp = Hp;
            return data;
        }
    
        public void MoveToPlayer()
        {
            rigidbody.AddForce((player.transform.position - transform.position).normalized);
        }
    
        public void StopMove()
        {
            rigidbody.AddForce(-rigidbody.velocity);
        }
    
        public void BeAttack()
        {
            Hp -= 0.01f;
        }
    
        public void FarAwayPlayer()
        {
            rigidbody.AddForce(-(player.transform.position - transform.position).normalized*2);
        }
    
        public void RecoveryHp()
        {
            if(Hp < 20)
            {
                Hp += 0.1f;
    
            }
        }
    }
    
    

    Data条件数据

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using UnityEngine;
    
    namespace Assets
    {
        class Data
        {
            public float DistanceAiToPlayer;
    
            public float Hp;
            
        }
    }
    
    

    代码中为了便于测试,ai在攻击下会直接减Hp,每一帧减少0.01,躲避和巡逻状态会增加Hp,每一帧增加0.1。
    运行结果


    运行情况.png

    视频转gif效果不是很好
    小球是玩家控制的,大球是游戏AI


    运行截图.gif

    相关文章

      网友评论

          本文标题:浅谈游戏AI设计--有限状态机

          本文链接:https://www.haomeiwen.com/subject/tjtwdftx.html