Geekpeer 发表于 2021-12-27 11:33:42

unity编程实践-士兵巡逻技术实现代码分享

作业要求创建一个地图和若干巡逻兵(使用动画);
每个巡逻兵走一个3~5个边的凸多边型,位置数据是相对地址。即每次确定下一个目标位置,用自己当前位置为原点计算;
巡逻兵碰撞到障碍物,则会自动选下一个点为目标;
巡逻兵在设定范围内感知到玩家,会自动追击玩家;
失去玩家目标后,继续巡逻;
计分:玩家每次甩掉一个巡逻兵计一分,与巡逻兵碰撞游戏结束;

游戏设计要求工厂模式生产巡逻兵
部署工作
建立预制体

建立游戏地图预制,玩家预制和巡逻兵预制。其中,巡逻兵需要添加两个Collider,一个是Capsule Collider,添加在预制体父节点上,用于检测巡逻兵与玩家的碰撞。另一个是Box Collider,添加在预制体的子节点上,用于检测玩家进入巡逻兵巡逻的范围,可以通过调整Size的大小来控制检测的范围

重要代码分析
巡逻兵创建-PatrolData
public class PatrolData : MonoBehaviour
{
      public int sign;                      //标志巡逻兵在哪一块区域
      public bool follow_player = false;    //是否跟随玩家
      public int wall_sign = -1;            //当前玩家所在区域标志
      public GameObject player;             //玩家游戏对象
      public Vector3 start_position;      //当前巡逻兵初始位置   
}


巡逻兵创建-PropFactory利用工厂模式生产巡逻兵,用数组记录每个巡逻兵的位置,创建的9个巡逻兵的位置有规律,所以可以用循环初始化位置坐标。当游戏结束时候,巡逻兵跑的动作被停止,将巡逻兵的动画设置为初始状态。 using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PropFactory : MonoBehaviour
{
      private GameObject patrol = null;                              //巡逻兵
      private List<GameObject> used = new List<GameObject>();      //正在被使用的巡逻兵
      private Vector3[] vec = new Vector3;                        //保存每个巡逻兵的初始位置

      public FirstSceneController sceneControler;                  //场景控制器

      public List<GameObject> GetPatrols()
      {
          int[] pos_x = { -6, 4, 13 };
          int[] pos_z = { -4, 6, -13 };
          int index = 0;
          for(int i=0;i < 3;i++)
          {
            for(int j=0;j < 3;j++)
            {
                  vec = new Vector3(pos_x, 0, pos_z);
                  index++;
            }
          }
          for(int i=0; i < 9; i++)
          {
            patrol = Instantiate(Resources.Load<GameObject>("Prefabs/Patrol"));
            patrol.transform.position = vec;
            patrol.GetComponent<PatrolData>().start_position = vec;
            used.Add(patrol);
          }   
          return used;
      }
      
      public void StopPatrol()
      {
          for (int i = 0; i < used.Count; i++)
          {
            used.gameObject.GetComponent<Animator>().SetBool("run", false);
          }
      }
}
巡逻兵巡逻-GoPatrolAction巡逻兵巡逻的动作,逻兵的巡逻轨迹为矩形,根据四个方向来选择要去到的目的地,当当前位置与目的地相差0.9f的时候,换一个方向继续巡逻;当发现附近存在玩家时,会调用回调函数,使得巡逻兵改为追踪状态,追踪玩家。public class GoPatrolAction : SSAction
{
      private enum Dirction { EAST, NORTH, WEST, SOUTH };
      private float pos_x, pos_z;               //移动前的初始x和z方向坐标
      private float move_length;                  //移动的长度
      private float move_speed = 1.2f;            //移动速度
      private bool move_sign = true;            //是否到达目的地
      private Dirction dirction = Dirction.EAST;//移动的方向
      private PatrolData data;                  //侦察兵的数据
      

      private GoPatrolAction() {}
      public static GoPatrolAction GetSSAction(Vector3 location)
      {
          GoPatrolAction action = CreateInstance<GoPatrolAction>();
          action.pos_x = location.x;
          action.pos_z = location.z;
          //设定移动矩形的边长
          action.move_length = Random.Range(4, 7);
          return action;
      }
      public override void Update()
      {
          if (data.alive == false){
            this.destroy = true;
          }
          //防止碰撞发生后的旋转
          if (transform.localEulerAngles.x != 0 || transform.localEulerAngles.z != 0)
          {
            transform.localEulerAngles = new Vector3(0, transform.localEulerAngles.y, 0);
          }            
          if (transform.position.y != 0)
          {
            transform.position = new Vector3(transform.position.x, 0, transform.position.z);
          }
          Gopatrol();
          if (data.follow_player)
          {
            this.destroy = true;
            this.callback.SSActionEvent(this,0,this.gameobject);
          }
      }
      public override void Start()
      {
          this.gameobject.GetComponent<Animator>().SetBool("run", true);
          data= this.gameobject.GetComponent<PatrolData>();
      }

      void Gopatrol()
      {
          if (move_sign)
          {
            switch (dirction)
            {
                  case Dirction.EAST:
                      pos_x -= move_length;
                      break;
                  case Dirction.NORTH:
                      pos_z += move_length;
                      break;
                  case Dirction.WEST:
                      pos_x += move_length;
                      break;
                  case Dirction.SOUTH:
                      pos_z -= move_length;
                      break;
            }
            move_sign = false;
          }
          this.transform.LookAt(new Vector3(pos_x, 0, pos_z));
          float distance = Vector3.Distance(transform.position, new Vector3(pos_x, 0, pos_z));
          if (distance > 0.9)
          {
            transform.position = Vector3.MoveTowards(this.transform.position, new Vector3(pos_x, 0, pos_z), move_speed * Time.deltaTime);
          }
          else
          {
            dirction = dirction + 1;
            if(dirction > Dirction.SOUTH)
            {
                  dirction = Dirction.EAST;
            }
            move_sign = true;
          }
      }

}
巡逻兵追踪-PatrolFollowAction巡逻兵将目标位置定位为玩家位置,将会向着玩家位置移动,直到玩家逃离追踪范围。 public class PatrolFollowAction : SSAction

{

      private float speed = 2f;            //跟随玩家的速度

      private GameObject player;         //玩家

      private PatrolData data;             //侦查兵数据



      private PatrolFollowAction() {}

      public static PatrolFollowAction GetSSAction(GameObject player)

      {

          PatrolFollowAction action = CreateInstance<PatrolFollowAction>();

          action.player = player;

          return action;

      }



      public override void Update()

      {

          if (data.alive == false){

            this.destroy = true;

          }

          if (transform.localEulerAngles.x != 0 || transform.localEulerAngles.z != 0)

          {

            transform.localEulerAngles = new Vector3(0, transform.localEulerAngles.y, 0);

          }

          if (transform.position.y != 0)

          {

            transform.position = new Vector3(transform.position.x, 0, transform.position.z);

          }

         

          Follow();

          if (!data.follow_player)

          {

            this.destroy = true;

            this.callback.SSActionEvent(this,1,this.gameobject);

          }

      }

      public override void Start()

      {

          data = this.gameobject.GetComponent<PatrolData>();

      }

      void Follow()

      {

          transform.position = Vector3.MoveTowards(this.transform.position, player.transform.position, speed * Time.deltaTime);

          this.transform.LookAt(player.transform.position);

      }

}巡逻兵追踪-PatrolFollowAction巡逻兵将目标位置定位为玩家位置,将会向着玩家位置移动,直到玩家逃离追踪范围。 public class PatrolFollowAction : SSAction
{
      private float speed = 2f;            //跟随玩家的速度
      private GameObject player;         //玩家
      private PatrolData data;             //侦查兵数据

      private PatrolFollowAction() {}
      public static PatrolFollowAction GetSSAction(GameObject player)
      {
          PatrolFollowAction action = CreateInstance<PatrolFollowAction>();
          action.player = player;
          return action;
      }

      public override void Update()
      {
          if (data.alive == false){
            this.destroy = true;
          }
          if (transform.localEulerAngles.x != 0 || transform.localEulerAngles.z != 0)
          {
            transform.localEulerAngles = new Vector3(0, transform.localEulerAngles.y, 0);
          }
          if (transform.position.y != 0)
          {
            transform.position = new Vector3(transform.position.x, 0, transform.position.z);
          }
         
          Follow();
          if (!data.follow_player)
          {
            this.destroy = true;
            this.callback.SSActionEvent(this,1,this.gameobject);
          }
      }
      public override void Start()
      {
          data = this.gameobject.GetComponent<PatrolData>();
      }
      void Follow()
      {
          transform.position = Vector3.MoveTowards(this.transform.position, player.transform.position, speed * Time.deltaTime);
          this.transform.LookAt(player.transform.position);
      }
}
动作管理类-SSActionManager此类管理巡逻兵是巡逻状态还是追踪状态,巡逻动作结束条件是需要追捕玩家,使用此类来实现追捕动作。而当玩家离开追捕范围后,需要重新巡逻,也需要使用此类实现从初始的位置和方向继续巡逻。在游戏结束后,此类也负责摧毁所有动作,停止巡逻兵的移动。public void SSActionEvent(SSAction source, int intParam = 0, GameObject objectParam = null)
      {
          if(intParam == 0)
          {
            //侦查兵跟随玩家
            PatrolFollowAction follow = PatrolFollowAction.GetSSAction(objectParam.gameObject.GetComponent<PatrolData>().player);
            this.RunAction(objectParam, follow, this);
          }
          else
          {
            //侦察兵按照初始位置开始继续巡逻
            GoPatrolAction move = GoPatrolAction.GetSSAction(objectParam.gameObject.GetComponent<PatrolData>().start_position);
            this.RunAction(objectParam, move, this);
            //玩家逃脱
            //Singleton<GameEventManager>.Instance.PlayerEscape();
          }
      }


      public void DestroyAll()
      {
          foreach (KeyValuePair<int, SSAction> kv in actions)
          {
            SSAction ac = kv.Value;
            ac.destroy = true;
          }
      }



页: [1]
查看完整版本: unity编程实践-士兵巡逻技术实现代码分享