文档章节

XYGame-AI设计2-FSM

梦想游戏人
 梦想游戏人
发布于 2017/04/28 11:40
字数 958
阅读 36
收藏 0

把具体的行为代码(移动,攻击)写在Enemy 里面,然后决策(仇恨)用FSM 状态机来做

AI状态 流程图

 

把流程图拆解为 几个状态后,编写以下代码

AIEnemy.cs

/*
* Email:   me@dreamyouxi.com
using FSM to peocess lite AI
 */
using UnityEngine;
using System.Collections;

namespace AIEnemy
{
    public class FSMBase : GAObject
    {
        public Enemy host = null;
        public FSMMachine machine = null;
        public override void UpdateMS()
        {

        }
        public override void OnEnter()
        {

        }
        public override void OnExit()
        {

        }
        public override bool Init()
        {
            base.Init();
            return true;
        }
        //  ------ helper function
        public void ChangeTo<T>() where T : FSMBase, new()
        {
            machine.ChangeTo<T>();
        }
    }
    /// <summary>
    /// 锁定塔状态 
    /// 该状态下只会攻击塔
    /// </summary>
    public class LockTower : FSMBase
    {
        public override void UpdateMS()
        {
            if (host.target == null)
            {
                this.ChangeTo<Free>();
            }
        }
        public override void OnEnter()
        {
            host.bullet_atk1_info.AddHitTarget(host.target);//锁定只攻击  Tower
        }
        public override void OnExit()
        {

        }
    }

    /// <summary>
    /// 自由状态 
    /// 目标死亡 或者 刚出生 才会在该状态下
    /// </summary>
    public class Free : FSMBase
    {
        public override void UpdateMS()
        {
            if (BuildingMgr.ins.GetBuildingsCount() > 0)
            { //存在塔
                ArrayList list = HeroMgr.ins.GetHeros();
                bool has_hero = false;
                if (list.Count > 0)
                {
                    foreach (Hero h in list)
                    {
                        if (host.target_distance > h.ClaculateDistance(host))
                        {//范围内 有玩家
                            has_hero = true;
                            break;
                        }
                    }
                }
                if (has_hero) // 仇恨范围内有玩家
                {//锁定玩家攻击
                    if (host.AI_SearchNearestTarget(list, true)) ;
                    {
                        this.ChangeTo<LockHero>();
                    }
                }
                else // 仇恨范围内没有玩家,直接进入半锁定塔状态
                {
                    this.ChangeTo<LockHalfTowerBefore>();
                }
            }
            else
            {//不存在塔,直接锁定最近玩家攻击
                if (host.AI_SearchNearestTarget(HeroMgr.ins.GetHeros(), true))
                {
                    this.ChangeTo<LockHero>();
                }
                else
                {//没有任何攻击目标 随机走动
                    if (Utils.random_frameMS.Next(0, 300) == 5 || dir == -1)
                    {
                        Terrain terrain = AppMgr.GetCurrentApp<BattleApp>().GetCurrentWorldMap().GetTerrain();
                        Vector2 to = new Vector2(Utils.random_frameMS.Next((int)(terrain.limit_x_left * 1000), (int)(terrain.limit_x_right * 1000)) / 1000f, Utils.random_frameMS.Next((int)(terrain.limit_z_down * 1000), (int)(terrain.limit_z_up * 1000)) / 1000f);
                        dir = (int)Utils.GetAngle(host.pos, to);
                    }
                    host.dir = dir;// Utils.random_frameMS.Next(0, 361);
                }
            }
        }
        public override void OnEnter()
        {
            if (host != null)
            {//目标没死
                host.bullet_atk1_info.hit_targets.Clear();//清空目标
            }
        }
        public override void OnExit()
        {

        }

        private int dir = -1;

    }

    /// <summary>
    /// 半锁定塔 状态后
    /// 在该状态下  只有被玩家攻击才会 攻击玩家 否则 一直攻击塔
    /// </summary>
    public class LockHalfTowerAfter : FSMBase
    {
        public override void UpdateMS()
        {
            if (host.target == null || host == null)
            {//如果塔 失效
                ChangeTo<Free>();
                return;
            }
        }
        public override void OnEnter()
        {

        }
        public override void OnDispose()
        {
            EventDispatcher.ins.RemoveEventListener(this, Events.ID_BATTLE_ENTITY_BEFORE_TAKEATTACKED);
        }
        public override void OnExit()
        {

        }
        public override void OnEvent(int type, object userData)
        {
            if (this.IsInValid()) return;
            if (type == Events.ID_BATTLE_ENTITY_BEFORE_TAKEATTACKED)
            {
                AttackInfo info = userData as AttackInfo;
                if (info.target as Enemy != host) return;

                {//已经命中 塔 后 被攻击 会切换,在搜索阶段 被命中 也会进入锁定hero
                    //自己被命中
                    if (info.ownner.IsMaxTarget() == false)
                    {
                        host.target = info.ownner;
                        machine.ChangeTo<LockHero>();
                    }
                }
            }
        }
        public override bool Init()
        {
            base.Init();

            EventDispatcher.ins.AddEventListener(this, Events.ID_BATTLE_ENTITY_BEFORE_TAKEATTACKED);
            return true;
        }

    }
    /// <summary>
    /// 半锁定塔 命中前,
    /// 该状态 下 仇恨指向 塔  但未命中塔 在此期间 如果范围内 有玩家 会更改为锁定玩家攻击
    /// </summary>
    public class LockHalfTowerBefore : FSMBase
    {
        public override void UpdateMS()
        {
            if (has_find)//已找到塔 
            {
                if (has_shoot == false)
                { //发起攻击 塔
                    if (host.target == null || host == null)
                    {
                        ChangeTo<Free>();
                        return;
                    }
                    this.Shoot();
                }
            }
            else
            {
                if (host.AI_SearchNearestTarget(BuildingMgr.ins.GetBuildings(), false))//寻找最近的建筑作为目标
                {//找到 目标  
                    has_find = true;
                }
                else
                {//搜索失败 ,进入Free
                    machine.ChangeTo<Free>();
                    return;
                }
            }

            //在此期间如果仇恨范围内有玩家,那么切换仇恨为玩家
            ArrayList list = HeroMgr.ins.GetHeros();
            bool has_hero = false;
            if (list.Count > 0)
            {
                foreach (Hero h in list)
                {
                    if (host.target_distance > h.ClaculateDistance(host))
                    {//范围内 有玩家
                        has_hero = true;
                        break;
                    }
                }
            }
            if (has_hero) // 仇恨范围内有玩家
            {//锁定玩家攻击
                if (host.AI_SearchNearestTarget(list, true)) ;
                {
                    this.ChangeTo<LockHero>();
                    return;
                }
            }
        }
        public override void OnEnter()
        {
            has_shoot = false;
            has_find = false;
        }
        public override void OnExit()
        {
            if (info_backup != null)
            {
                host.bullet_atk1_info = info_backup;
                info_backup = null;
            }
        }
        private void Shoot()
        {
            info_backup = host.bullet_atk1_info;
            //      host.atk = true;

            BulletConfigInfo info = BulletConfigInfo.Create();
            info.AddHitTarget(host.target);
            info.plistAnimation = "";
            info.distance = 0.2f;
            info.distance_atk = 1f;
            info.number = 1;
            info.collider_size = new Vector3(2f, 2f, 2f);
            info.AddHitTarget(host.target);
            info._OnTakeAttack = (Bullet bullet, object userData) =>
            {
                //命中后  
                ChangeTo<LockHalfTowerAfter>();
            };
            has_shoot = true;
            host.bullet_atk1_info = info;
        }

        public override bool Init()
        {
            base.Init();
            return true;
        }
        private BulletConfigInfo info_backup = null;
        private bool has_shoot = false;
        private bool has_find = false;

    }

    /// <summary>
    /// 锁定玩家状态
    /// 该状态只会攻击玩家 直到 玩家死亡
    /// </summary>
    public class LockHero : FSMBase
    {
        public override void UpdateMS()
        {
            if (host.target == null)
            {
                this.ChangeTo<Free>();
            }
        }
        public override void OnEnter()
        {
            host.bullet_atk1_info.AddHitTarget(host.target);//锁定只攻击 Hero
        }
        public override void OnExit()
        {

        }
    }

    /// <summary>
    /// FSM  状态机
    /// </summary>
    public class FSMMachine : GAObject
    {
        public override void UpdateMS()
        {
            if (host.ai_type != AIEnemyType.FSM) return;
            if (pause) return;
            if (current_fsm != null)
            {
                current_fsm.UpdateMS();
                //    Debug.Log("FSM: " + current_fsm.GetType().ToString());
            }
        }
        public override void OnEnter()
        {

        }
        public override void OnExit()
        {

        }
        public override bool Init()
        {
            base.Init();
            current_fsm = Utils.Create<Free>();
            current_fsm.machine = this;
            current_fsm.host = host;
            current_fsm.Init();
            return true;
        }
        public void ChangeTo(FSMBase fsm)
        {
            if (current_fsm != null)
            {
                current_fsm.OnExit();
                current_fsm.LazyDispose();
            }
            fsm.host = host;
            fsm.machine = this;
            fsm.OnEnter();
            current_fsm = fsm;
        }
        public void ChangeTo<T>() where T : FSMBase, new()
        {
            FSMBase fsm = Utils.Create<T>();
            fsm.Init();
            this.ChangeTo(fsm);
        }
        public void Pause()
        {
            pause = true;
        }
        public void Resume()
        {
            pause = false;
        }
        public bool IsPause()
        {
            return pause;
        }
        private bool pause = false;
        FSMBase current_fsm = null;
        public Enemy host = null;
    }
}

下篇,为行为树

源代码:https://git.oschina.net/dreamyouxi/XYGame

© 著作权归作者所有

共有 人打赏支持
梦想游戏人
粉丝 36
博文 429
码字总数 122078
作品 0
成都
[FreedomAI]第二周——FuSM

只使用FSM及其变种是很难应用在复杂的AI中的,因为其复杂度的扩展性很差,就比如,如果怪物有20种状态,你就需要考虑20*20种可能性的连接。 所以这时我们必须建立分层次的状态机设计,试想一...

qq_33999892
04/15
0
0
Silverlight 2.5D RPG游戏技巧与特效处理:(十一)AI系统

谈到人工智能(AI),这个话题就太大了;大学里有《人工智能教程》专门讲这方面的知识,什么大名鼎鼎的人工神经网络、遗传算法等等均可一窥究竟,这里如赘述似乎有些班门弄斧,我们暂且丢它一边...

晨曦之光
2012/03/09
0
0
游戏AI的开发框架组件--Behaviac

Behaviac是游戏AI的开发框架组件,也是游戏原型的快速设计工具。支持行为树BT,状态机FSM,HTN等多种范式,方便的编辑和调试。支持全平台,适用于客户端和服务器,助力游戏快速迭代开发。 编...

匿名
2016/03/29
14.9K
5
《游戏程序设计模式》 1.6 - 状态模式

忏悔时间:我有点过分了在这章塞下太多东西。表面我是讨论状态模式,但是我不可能在讨论这个时不涉及到更基本的有限状态机(FSM)的概念。一旦我讲到那了,我发现我又不得不介绍分层状态机(...

yintao
2015/08/05
0
0
AI算力需求100万倍增长,如何优化AI计算系统弥平鸿沟?

在深度学习激发的人工智能热潮下,许多创新力很强的企业的人工智能技术正逐步从研究实验走向应用与生产,在这一过程中,AI计算系统设计与优化的重要性愈发明显。 同时算法的发展对整个计算需...

技术小能手
09/27
0
0

没有更多内容

加载失败,请刷新页面

加载更多

通过ajax访问远程天气预报服务

http://www.webxml.com.cn/zh_cn/index.aspx 更改wsdl文件 打开文件将15行,51行,101行去掉 然后把文件复制到c盘 然后在桌面上面就生成了文件 将文件打成jar包 package cn.it.ws.weather;...

江戸川
今天
1
0
聊聊storm的tickTuple

序 本文主要研究一下storm的tickTuple 实例 TickWordCountBolt public class TickWordCountBolt extends BaseBasicBolt { private static final Logger LOGGER = LoggerFactory.getLogg......

go4it
今天
1
0
自动装箱和自动拆箱

自动装箱和自动拆箱 Java 提供了 8 种基本数据类型,每种数据类型都有其对应的包装类型,包装类是面向对象的类,是一种高级的数据类型,可以进行一些比较复杂的操作,它们是引用类型而不再基...

tsmyk0715
今天
2
0
简易审计系统

1、有时候我们需要对线上用户的操作进行记录,可以进行追踪,出现问题追究责任,但是linux自带的history并不会实时的记录(仅仅在内存中,当用户正常退出(exit logout )时才会记录到history文件里...

芬野de博客
今天
3
0
Qt那些事0.0.6

QML中使用Image,在设置source的后,通过Qt Quick2 Preview(qmlscene)遇到了图片找不到的问题: Image { id: success_img anchors.centerIn: parent ...

Ev4n
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部