zoukankan      html  css  js  c++  java
  • 使用有限状态机(FSM)编写的敌人AI

     1 using UnityEngine;
     2 using System.Collections;
     3 
     4 public class AttackState : FSMState
     5 {
     6     public AttackState() 
     7     { 
     8         stateID = FSMStateID.Attacking;
     9     }
    10 
    11     public override void Reason(Transform player, Transform npc)
    12     {
    13         if (npc.GetComponent<AIController>().stateInfo.normalizedTime >= 1.0f && npc.GetComponent<AIController>().stateInfo.IsName("Attack"))
    14             npc.GetComponent<AIController>().SetTransition(Transition.AttackOver);
    15     }
    16 
    17     public override void Act(Transform player, Transform npc)
    18     {
    19     }
    20 }
     1 using UnityEngine;
     2 using System.Collections;
     3 
     4 public class DeadState : FSMState
     5 {
     6     public DeadState() 
     7     {
     8         stateID = FSMStateID.Dead;
     9     }
    10 
    11     public override void Reason(Transform player, Transform npc)
    12     {
    13 
    14     }
    15 
    16     public override void Act(Transform player, Transform npc)
    17     {        
    18                 Animation animComponent = npc.GetComponent<Animation>();
    19                 //animComponent.CrossFade("death");
    20     }
    21 }
     1 using UnityEngine;
     2 using System.Collections;
     3 
     4 public class MoveState : FSMState
     5 {
     6     float rotateTime;
     7     float curSpeed;
     8     public MoveState()
     9     {
    10         stateID = FSMStateID.Move;
    11 
    12         curSpeed = 1.0f;
    13         rotateTime = 0f;
    14     }
    15 
    16     public override void Reason(Transform player, Transform npc)
    17     {
    18         float distance = Vector3.Distance(player.position, npc.position);
    19         if (distance <= 5)
    20         {
    21             if (npc.GetComponent<AIController>().attackCd == 0f)
    22             {
    23                 npc.GetComponent<AIController>().SetTransition(Transition.ReachPlayer);
    24                 npc.GetComponent<AIController>().attackCd = 5.0f;
    25             }
    26         }
    27     }
    28 
    29     public override void Act(Transform player, Transform npc)
    30     {
    31         rotateTime -= Time.deltaTime;
    32         if (rotateTime <= 0)
    33         {
    34             rotateTime = 3.0f;
    35             Vector3 toTargetV3 = (player.position - npc.position).normalized;
    36             float direction = Vector3.Dot(toTargetV3, npc.forward);
    37             Vector3 u = Vector3.Cross(toTargetV3, npc.forward);
    38             if (direction > 1) { direction = 1f; }
    39             if (direction < -1) { direction = -1f; }
    40             if (Mathf.Abs(direction) == 1f)
    41                 return;
    42             direction = Mathf.Acos(direction) * Mathf.Rad2Deg;
    43             npc.rotation = npc.rotation * Quaternion.Euler(new Vector3(0, direction * (u.y >= 0 ? -1 : 1), 0));
    44         }
    45 
    46         float distance = Vector3.Distance(player.position, npc.position);
    47         if (distance >= 20)
    48         {
    49             npc.GetComponent<AIController>().animator.SetFloat("Blend", 1f);
    50             curSpeed = 2f;
    51         }
    52         else if (distance < 20 && distance >= 2)
    53         {
    54             npc.GetComponent<AIController>().animator.SetFloat("Blend", 0.5f);
    55             curSpeed = 1f;
    56         }
    57         else
    58         {
    59             npc.GetComponent<AIController>().animator.SetFloat("Blend", 0f);
    60             curSpeed = 0;
    61         }
    62         npc.Translate(npc.transform.forward * Time.deltaTime * curSpeed, Space.World);
    63     }
    64 }
      1 using UnityEngine;
      2 using System.Collections;
      3 using System.Collections.Generic;
      4 
      5 /// <summary>
      6 /// This class is adapted and modified from the FSM implementation class available on UnifyCommunity website
      7 /// The license for the code is Creative Commons Attribution Share Alike.
      8 /// It's originally the port of C++ FSM implementation mentioned in Chapter01 of Game Programming Gems 1
      9 /// You're free to use, modify and distribute the code in any projects including commercial ones.
     10 /// Please read the link to know more about CCA license @http://creativecommons.org/licenses/by-sa/3.0/
     11 /// </summary>
     12 
     13 //定义枚举,为可能的转换分配编号
     14 public enum Transition
     15 {    
     16     SawPlayer = 0, //看到玩家
     17     ReachPlayer,   //接近玩家
     18     LostPlayer,    //玩家离开视线
     19     NoHealth,      //死亡
     20     AttackOver,    //结束攻击
     21 }
     22 
     23 /// <summary>
     24 /// 定义枚举,为可能的状态分配编号ID
     25 /// </summary>
     26 public enum FSMStateID
     27 {    
     28     Move = 0,
     29     Attacking,       //攻击编号
     30     Patrolling ,  //巡逻编号
     31     Chasing,         //追逐编号
     32     Dead,           //死亡编号
     33 }
     34 
     35 public class AdvancedFSM : FSM 
     36 {
     37     //FSM中的所有状态组成的列表
     38     private List<FSMState> fsmStates;
     39     //当前状态的编号
     40     //The fsmStates are not changing directly but updated by using transitions
     41     private FSMStateID currentStateID;
     42     public FSMStateID CurrentStateID { get { return currentStateID; } }
     43     //当前状态
     44     private FSMState currentState;
     45     public FSMState CurrentState { get { return currentState; } }
     46 
     47     public AdvancedFSM()
     48     {
     49         //新建一个空的状态列表
     50         fsmStates = new List<FSMState>();
     51     }
     52 
     53     /// <summary>
     54     ///向状态列表中加入一个新的状态
     55     /// </summary>
     56     public void AddFSMState(FSMState fsmState)
     57     {
     58         //检查要加入的新状态是否为空,如果空就报错
     59         if (fsmState == null)
     60         {
     61             Debug.LogError("FSM ERROR: Null reference is not allowed");
     62         }
     63 
     64         // First State inserted is also the Initial state
     65         //   the state the machine is in when the simulation begins
     66         //如果插入的这个状态时,列表还是空的,那么将它加入列表并返回
     67         if (fsmStates.Count == 0)
     68         {
     69             fsmStates.Add(fsmState);
     70             currentState = fsmState;
     71             currentStateID = fsmState.ID;
     72             return;
     73         }
     74 
     75         // 检查要加入的状态是否已经在列表里,如果是,报错返回
     76         foreach (FSMState state in fsmStates)
     77         {
     78             if (state.ID == fsmState.ID)
     79             {
     80                 Debug.LogError("FSM ERROR: Trying to add a state that was already inside the list");
     81                 return;
     82             }
     83         }
     84         //如果要加入的状态不在列表中,将它加入列表
     85         fsmStates.Add(fsmState);
     86     }
     87 
     88 
     89     //从状态中删除一个状态   
     90     public void DeleteState(FSMStateID fsmState)
     91     {
     92         // 搜索整个状态列表,如果要删除的状态在列表中,那么将它移除,否则报错
     93         foreach (FSMState state in fsmStates)
     94         {
     95             if (state.ID == fsmState)
     96             {
     97                 fsmStates.Remove(state);
     98                 return;
     99             }
    100         }
    101         Debug.LogError("FSM ERROR: The state passed was not on the list. Impossible to delete it");
    102     }
    103 
    104     /// <summary>
    105     /// 根据当前状态,和参数中传递的转换,转换到新状态
    106     /// </summary>
    107     public void PerformTransition(Transition trans)
    108     {  
    109         // 根绝当前的状态类,以Trans为参数调用它的GetOutputState方法
    110         //确定转换后的新状态
    111         FSMStateID id = currentState.GetOutputState(trans);        
    112 
    113         //  将当前状态编号设置为刚刚返回的新状态编号        
    114         currentStateID = id;
    115 
    116         //根绝状态编号查找状态列表,将当前状态设置为查找到的状态
    117         foreach (FSMState state in fsmStates)
    118         {
    119             if (state.ID == currentStateID)
    120             {
    121                 currentState = state;
    122                 break;
    123             }
    124         }
    125     }
    126 }
     1 using UnityEngine;
     2 using System.Collections;
     3 
     4 public class FSM : MonoBehaviour 
     5 {
     6         //玩家位置
     7         protected Transform playerTransform;
     8 
     9         //下一个巡逻点
    10         protected Vector3 destPos;
    11 
    12         //巡逻点表单
    13         protected GameObject[] pointList;
    14 
    15         //子弹信息
    16         protected float shootRate;
    17         protected float elapsedTime;
    18 
    19         protected virtual void Initialize() {}
    20         protected virtual void FSMUpdate() {}
    21         protected virtual void FSMFixedUpdate() {}
    22 
    23         //初始化信息
    24         void Start()
    25         {
    26                 Initialize();
    27         }
    28 
    29     // 循环执行子类FSMUpdate方法
    30         void Update () 
    31         {
    32                 FSMUpdate();
    33         }
    34 
    35         void FixedUpdate()
    36         {
    37                 FSMFixedUpdate();
    38         }
    39 }
     1 using UnityEngine;
     2 using System.Collections;
     3 using System.Collections.Generic;
     4 
     5 /// <summary>
     6 /// This class is adapted and modified from the FSM implementation class available on UnifyCommunity website
     7 /// The license for the code is Creative Commons Attribution Share Alike.
     8 /// It's originally the port of C++ FSM implementation mentioned in Chapter01 of Game Programming Gems 1
     9 /// You're free to use, modify and distribute the code in any projects including commercial ones.
    10 /// Please read the link to know more about CCA license @http://creativecommons.org/licenses/by-sa/3.0/
    11 
    12 /// This class represents the States in the Finite State System.
    13 /// Each state has a Dictionary with pairs (transition-state) showing
    14 /// which state the FSM should be if a transition is fired while this state
    15 /// is the current state.
    16 /// Reason method is used to determine which transition should be fired .
    17 /// Act method has the code to perform the actions the NPC is supposed to do if it磗 on this state.
    18 /// </summary>
    19 public abstract class FSMState
    20 {
    21     //字典,字典中每一项都记录了一个“转换-状态”对 的信息
    22     protected Dictionary<Transition, FSMStateID> map = new Dictionary<Transition, FSMStateID>();
    23     //状态编号ID
    24     protected FSMStateID stateID;
    25     public FSMStateID ID { get { return stateID; } }
    26 
    27     /// <summary>
    28     /// 向字典添加项,每项是一个"转换--状态"对
    29     /// </summary>
    30     /// <param name="transition"></param>
    31     /// <param name="id"></param>
    32     public void AddTransition(Transition transition, FSMStateID id)
    33     {
    34         //检查这个转换(可以看做是字典的关键字)是否在字典里
    35         if (map.ContainsKey(transition))
    36         {
    37             //一个转换只能对应一个新状态
    38             Debug.LogWarning("FSMState ERROR: transition is already inside the map");
    39             return;
    40         }
    41         //如果不在字典,那么将这个转换和转换后的状态作为一个新的字典项,加入字典
    42         map.Add(transition, id);
    43     }
    44 
    45     /// <summary>
    46     /// 从字典中删除项
    47     /// </summary>
    48     /// <param name="trans"></param>
    49     public void DeleteTransition(Transition trans)
    50     {
    51         // 检查是否在字典中,如果在,移除
    52         if (map.ContainsKey(trans))
    53         {
    54             map.Remove(trans);
    55             return;
    56         }
    57         //如果要删除的项不在字典中,报告错误
    58         Debug.LogError("FSMState ERROR: Transition passed was not on this State List");
    59     }
    60 
    61 
    62     /// <summary>
    63     /// 通过查询字典,确定在当前状态下,发生trans转换时,应该转换到新的状态编号并返回
    64     /// </summary>
    65     /// <param name="trans"></param>
    66     /// <returns></returns>
    67     public FSMStateID GetOutputState(Transition trans)
    68     {
    69         return map[trans];
    70     }
    71 
    72     /// <summary>
    73     /// 用来确定是否需要转换到其他状态,应该发生哪个转换
    74     /// </summary>
    75     /// <param name="player"></param>
    76     /// <param name="npc"></param>
    77     public abstract void Reason(Transform player, Transform npc);
    78 
    79     /// <summary>
    80     /// 定义了在本状态的角色行为,移动,动画等
    81     /// </summary>
    82     /// <param name="player"></param>
    83     /// <param name="npc"></param>
    84     public abstract void Act(Transform player, Transform npc);
    85 }
      1 using UnityEngine;
      2 using System.Collections;
      3 
      4 public class AIController : AdvancedFSM 
      5 {
      6     private int health;
      7     public Animator animator;
      8     public AnimatorStateInfo stateInfo;
      9     public float attackCd;
     10     //Initialize the Finite state machine for the NPC tank
     11     protected override void Initialize()
     12     {
     13         health = 100;
     14 
     15         elapsedTime = 0.0f;
     16         shootRate = 0.5f;
     17         attackCd = 0f;
     18 
     19         //Get the target enemy(Player)
     20         GameObject objPlayer = GameObject.FindGameObjectWithTag("Player");
     21         playerTransform = objPlayer.transform;
     22 
     23         if (!playerTransform)
     24             print("Player doesn't exist.. Please add one with Tag named 'Player'");        
     25         animator = this.GetComponentInChildren<Animator>();
     26         //Start Doing the Finite State Machine
     27         ConstructFSM();
     28     }
     29 
     30     //Update each frame
     31     protected override void FSMUpdate()
     32     {
     33         //Check for health
     34         elapsedTime += Time.deltaTime;
     35         if (attackCd > 0)
     36         {
     37             attackCd -= Time.deltaTime;
     38             if (attackCd <= 0)
     39                 attackCd = 0;
     40         }
     41     }
     42 
     43     protected override void FSMFixedUpdate()
     44     {
     45         stateInfo = animator.GetCurrentAnimatorStateInfo(0);
     46         CurrentState.Reason(playerTransform, transform);
     47         CurrentState.Act(playerTransform, transform);
     48     }
     49 
     50     public void SetTransition(Transition t) 
     51     { 
     52         PerformTransition(t);
     53         animator.SetInteger("StateI", (int)CurrentStateID);
     54     }
     55 
     56     private void ConstructFSM()
     57     {
     58         //Get the list of points
     59         pointList = GameObject.FindGameObjectsWithTag("PatrolPoint");
     60 
     61         Transform[] waypoints = new Transform[pointList.Length];
     62         int i = 0;
     63         foreach(GameObject obj in pointList)
     64         {
     65             waypoints = obj.transform;
     66             i++;
     67         }
     68 
     69         MoveState move = new MoveState();
     70         move.AddTransition(Transition.ReachPlayer,FSMStateID.Attacking);
     71 
     72         AttackState attack = new AttackState();
     73         attack.AddTransition(Transition.AttackOver,FSMStateID.Move);
     74 
     75         AddFSMState(move);
     76         AddFSMState(attack);
     77     }
     78 
     79     /// <summary>
     80     /// Check the collision with the bullet
     81     /// </summary>
     82     /// <param name="collision"></param>
     83     void OnCollisionEnter(Collision collision)
     84     {
     85         //Reduce health
     86         if (collision.gameObject.tag == "Bullet")
     87         {
     88             health -= 50;
     89 
     90             if (health <= 0)
     91             {
     92                 Debug.Log("Switch to Dead State");
     93                 SetTransition(Transition.NoHealth);                
     94             }
     95         }
     96     }
     97 
     98 
     99     
    100     // Shoot the bullet    
    101     public void ShootBullet()
    102     {
    103         if (elapsedTime >= shootRate)
    104         {            
    105             elapsedTime = 0.0f;
    106         }
    107     }
    108 }
     1 using UnityEngine;
     2 using System.Collections;
     3 
     4 public class CameraFollow : MonoBehaviour
     5 {
     6     public Transform target;
     7     public Vector3 offest;
     8 
     9     void LateUpdate()
    10     {
    11         transform.position = target.position + offest;
    12     }
    13 }
  • 相关阅读:
    script中的event和for的意思
    jQuery选择器详解(一)转载自:http://blog.imbolo.com/jqueryselectors/#comments
    抽象类那点事(一步步案例分析,为什么需要它)
    关于application/xwwwformurlencoded等字符编码的解释说明 + 异步 True 或 False?+ onreadystatechange 事件
    SVG中中文字体的显示
    通过Virtualbox安装Ubuntu设置Emacs搭建Erlang环境
    试用Windows Live Writer
    Erlang中Eunit基本内容汇总
    xml特殊字符
    VS2010开发环境最佳字体及配色
  • 原文地址:https://www.cnblogs.com/bzyzhang/p/5444164.html
Copyright © 2011-2022 走看看