文档章节

XYGame-AI设计2-FSM

梦想游戏人
 梦想游戏人
发布于 2017/04/28 11:40
字数 958
阅读 32
收藏 0
点赞 0
评论 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

© 著作权归作者所有

共有 人打赏支持
梦想游戏人
粉丝 34
博文 415
码字总数 116989
作品 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
《游戏程序设计模式》 1.6 - 状态模式

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

yintao
2015/08/05
0
0
游戏AI的开发框架组件--Behaviac

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

匿名
2016/03/29
14.9K
5
unity3d Ai 角色控制状态机设计

一:需求 二设计 ![在此输入图片描述][1][1]: http://static.oschina.net/uploads/space/2015/0227/132157_jV0j_186074.png 首先确定有多少种大的AI状态,继承AIState 产生基本状态子类 ![在...

李勇2
2015/02/27
0
0
状态机和行为树

最近在思考游戏AI,看到一些文章在鼓吹状态机(fsm)已经过时,行为树才是现在和将来。目前我的水平,对这个结论无法做评判。但是从读到的文章本身,没有看到有力的证据。 诚然,在复杂状态下,...

深蓝苹果
2014/08/07
4.2K
2
GTC CHINA2016在京举行 助力中国开启人工智能黄金时代

2016年9月13日——中国北京—— 全球久负盛名的GTCCHINA 2016 (GPU技术大会)今天在北京召开,NVIDIA联合创始人、总裁兼首席执行官黄仁勋出席大会,深度阐释GPU计算产品与解决方案平台将如何拓...

玄学酱
05/15
0
0
业界 | 让环境适应人类:百度展示AI时代的交互设计

  机器之心报道   作者:李泽南      在越来越先进的技术之外,AI 时代的设计应该是什么样的? 7 月 5 日下午,在百度 AI 开发者大会上,举办了一场 AI 设计论坛,从交互的角度向我们...

机器之心
07/09
0
0
所有APP即将马上消失?这家公司要用设计+AI创造新时代

用终局思维看待AI时代,也就是“万物有生”的时代,其本质即服务。AI时代的终极形态,就是一切产品皆服务,服务即产品。 洛可可.洛客李凡聪解读视频: “万物有生”时代,所有产品都将拥有“...

木子
07/07
0
0
【活动预告】第二届设计与人工智能会议:设计与数据智能的探索

回顾:2016年11月,同济x特赞设计与人工智能实验室成立,第一届设计与人工智能论坛也在同济大学圆满举行。2017年4月,设计与人工智能实验室联合同济大学设计创意学院、特赞、阿里巴巴智能设计...

Suyu GONE
2017/11/30
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Java设计模式学习之工厂模式

在Java(或者叫做面向对象语言)的世界中,工厂模式被广泛应用于项目中,也许你并没有听说过,不过也许你已经在使用了。 简单来说,工厂模式的出现源于增加程序序的可扩展性,降低耦合度。之...

路小磊
18分钟前
0
0
npm profile 新功能介绍

转载地址 npm profile 新功能介绍 npm新版本新推来一个功能,npm profile,这个可以更改自己简介信息的命令,以后可以不用去登录网站来修改自己的简介了 具体的这个功能的支持大概是在6这个版...

durban
29分钟前
0
0
Serial2Ethernet Bi-redirection

Serial Tool Serial Tool is a utility for developing serial communications, custom protocols or device testing. You can set up bytes to send accordingly to your protocol and save......

zungyiu
35分钟前
0
0
python里求解物理学上的双弹簧质能系统

物理的模型如下: 在这个系统里有两个物体,它们的质量分别是m1和m2,被两个弹簧连接在一起,伸缩系统为k1和k2,左端固定。假定没有外力时,两个弹簧的长度为L1和L2。 由于两物体有重力,那么...

wangxuwei
50分钟前
0
0
apolloxlua 介绍

##项目介绍 apolloxlua 目前支持javascript到lua的翻译。可以在openresty和luajit里使用。这个工具分为两种模式, 一种是web模式,可以通过网页使用。另外一种是tool模式, 通常作为大规模翻...

钟元OSS
57分钟前
0
0
Mybatis入门

简介: 定义:Mybatis是一个支持普通SQL查询、存储过程和高级映射的持久层框架。 途径:MyBatis通过XML文件或者注解的形式配置映射,实现数据库查询。 特性:动态SQL语句。 文件结构:Mybat...

霍淇滨
今天
0
0
开发技术瓶颈期,如何突破

前言 读书、学习的那些事情,以前我也陆续叨叨了不少,但总觉得 “学习方法” 就是一个永远在路上的话题。个人的能力、经验积累与习惯方法不尽相同,而且一篇文章甚至一本书都很难将学习方法...

_小迷糊
今天
0
0
安装tensorflow-XXX报错

报错: tensorflow-0.5.0-cp27-none-linux_x86_64.whl is not a supported wheel on this platform. 解决: wget https://bootstrap.pypa.io/get-pip.py sudo python2.7 get-pip.py sudo p......

Yao--靠自己
今天
0
0
JVM学习手册(一):JVM模型

一直从事JAVA开发,天天和JVM打交道,仔细想想对JVM还真的不是特别了解,实在是不应该.周六看了许多资料,也算有点心得,记录一下。 JVM内存模型分为5个区域:方法区,堆,虚拟机栈,本地方法栈,程序计...

勤奋的蚂蚁
今天
0
0
转行零基础该如何学Python?这些一定要明白!

转行零基础学Python编程开发难度大吗?从哪学起?近期很多小伙伴问我,如果自己转行学习Python,完全0基础能否学会呢?Python的难度到底有多大?今天,小编就来为大家详细解读一下这个问题。...

猫咪编程
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部