日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

用Unity3D实现智能巡逻兵游戏

發布時間:2024/6/3 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 用Unity3D实现智能巡逻兵游戏 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

用Unity3D實現智能巡邏兵游戲

項目地址

智能巡邏兵游戲

完成效果圖

類圖

要求

  • 游戲設計要求:
    • 創建一個地圖和若干巡邏兵(使用動畫);
    • 每個巡邏兵走一個3~5個邊的凸多邊型,位置數據是相對地址。即每次確定下一個目標位置,用自己當前位置為原點計算;
    • 巡邏兵碰撞到障礙物,則會自動選下一個點為目標;
    • 巡邏兵在設定范圍內感知到玩家,會自動追擊玩家;
    • 失去玩家目標后,繼續巡邏;
    • 計分:玩家每次甩掉一個巡邏兵計一分,與巡邏兵碰撞游戲結束;
  • 程序設計要求:
    • 必須使用訂閱與發布模式傳消息
    • 工廠模式生產巡邏兵
  • 友善提示1:生成 3~5個邊的凸多邊型
    • 隨機生成矩形
    • 在矩形每個邊上隨機找點,可得到 3 - 4 的凸多邊型
    • 5 ?
  • 友善提示2:參考以前博客,給出自己新玩法

實現心得

首先要設計出玩法規則,比如:

  • 按方向鍵進行移動
  • 每次甩掉一個巡邏兵計一分,與巡邏兵碰撞游戲結束
  • 游戲中會隨機出現10個寶箱,收集完所有的寶箱那么游戲獲勝

然后創建游戲預制:

游戲對象預制可以從Unity3D的資源商店導入,地圖和寶箱用到的資源是HighQualityBricks&Walls和Pup Up Productions,玩家對象用到的資源是RPGHero,巡邏兵用到的資源是ToonyTinyPeople,將導入資源的預制放到Resource/Prefabs目錄下,接著為玩家對象和巡邏兵對象創建AnimatorController。

玩家對象的AnimatorController:

將玩家對象的普通狀態動畫放到Normal狀態中,跑步動畫放到Run狀態中,Die動畫放到Death狀態中,在Normal狀態到Run狀態的箭頭處設置bool類型run參數,為真則從Normal狀態到Run狀態,為假則從Run狀態到Normal狀態,在Any State狀態到Death狀態的箭頭處設置trigger類型death參數。

巡邏兵對象的AnimatorController:

將巡邏兵對象的普通狀態動畫放到Normal狀態中,跑步動畫放到Run狀態中,攻擊動畫放到Attack狀態中,在Normal狀態到Run狀態的箭頭處設置bool類型run參數,為真則從Normal狀態到Run狀態,為假則從Run狀態到Normal狀態,在Any State狀態到Attack狀態的箭頭處設置trigger類型attack參數。

接著要設計單實例類:

因為要求場景單實例,所以可以導入一個Singleton單實例模板類:

public class Singleton<T> : MonoBehaviour where T : MonoBehaviour {protected static T instance;public static T Instance {get {if (instance == null) {instance = (T)FindObjectOfType (typeof(T));if (instance == null) {Debug.LogError ("An instance of " + typeof(T) +" is needed in the scene, but there is none.");}}return instance;}} }

或者使用導演類,使主控制器實現唯一:

public class Director : System.Object {private static Director instance;public MainController mainController { get; set; }public static Director GetInstance() {if (instance == null) {instance = new Director();}return instance;} }

然后實現游戲對象創建部分,使用工廠模式創建巡邏兵和寶箱:

GameObjectFactory.cs:

游戲對象工廠類負責創建巡邏兵和寶箱,其在場景中是單實例的,且使用了對象池,實現了緩存功能,由于游戲中巡邏兵的數量不變,寶箱的數量也只會減少,所以回收方法中只有使巡邏兵停止移動的方法,實現如下:

public class GameObjectFactory : MonoBehaviour {private List<GameObject> usedPatrol = new List<GameObject>(); // 正在被使用的巡邏兵對象private List<GameObject> usedTreasure = new List<GameObject>(); // 正在被使用的寶箱對象// 巡邏兵獲取方法public List<GameObject> GetPatrols() {// 巡邏兵游戲對象GameObject patrolPrefab = GameObject.Instantiate(Resources.Load<GameObject>("Prefabs/Patrol"), Vector3.zero, Quaternion.identity);patrolPrefab.SetActive(false);float[] posX = { -5.5f, 4.5f, 12.5f };float[] posZ = { -4.5f, 5.5f, -12.5f };// 生成巡邏兵的初始位置for (int i = 0; i < 3; ++i) {for (int j = 0; j < 3; ++j) {Vector3 startPos = new Vector3(posX[i], 0, posZ[j]);GameObject patrol = GameObject.Instantiate(patrolPrefab, startPos, Quaternion.identity);patrol.SetActive(true);patrol.GetComponent<PatrolData>().patrolAreaId = i * 3 + j + 1;patrol.GetComponent<PatrolData>().startPos = startPos;usedPatrol.Add(patrol);}}return usedPatrol;}// 巡邏兵回收方法public void FreePatrols() {// 巡邏兵停止for (int i = 0; i < usedPatrol.Count; ++i) {usedPatrol[i].gameObject.GetComponent<Animator>().SetBool("run", false);}}// 寶箱獲取方法public List<GameObject> GetTreasures() {// 寶箱游戲對象GameObject treasurePrefab = GameObject.Instantiate(Resources.Load<GameObject>("Prefabs/Treasure"), Vector3.zero, Quaternion.identity);treasurePrefab.SetActive(false);for (int i = 0; i < Director.GetInstance().mainController.GetTreasureNumber(); ++i) {int xIndex = Random.Range(0, 24) - 12;int zIndex = Random.Range(0, 24) - 12;GameObject treasure = GameObject.Instantiate(treasurePrefab, new Vector3(xIndex, 0, zIndex), Quaternion.identity);treasure.SetActive(true);usedTreasure.Add(treasure);}return usedTreasure;} }

PatrolData.cs:

PatrolData是巡邏兵的模型,包含了巡邏兵相應的數據:

public class PatrolData : MonoBehaviour {public int patrolAreaId; // 巡邏兵所在區域序號public bool isTrackPlayer = false; // 是否跟隨玩家public GameObject trackPlayer; // 追蹤的玩家對象public Vector3 startPos; // 巡邏兵初始位置 }

這樣就使用工廠方法 + 單實例 + 對象池完成了巡邏兵和寶箱的創建,實現要求。

接著實現記分管理類:

ScoreRecorder.cs:

記分類中有一個分數成員變量,一個獲取方法和一個加分方法:

public class ScoreController : MonoBehaviour {private int score = 0; // 分數public int GetScore() {return score;}public void IncreaseScore() {score++;} }

然后實現游戲對象動作部分,利用回調方法,完成了訂閱-發布模式傳遞消息:

SSAction.cs和SSActionManager.cs:

SSAction是動作基類,SSActionManager是動作管理者的基類,其實現分別為:

public class SSAction : ScriptableObject {public bool enable = true; // 動作可進行public bool destroy = false; // 動作已完成可被銷毀public GameObject gameobject { get; set; } // 附著游戲對象public Transform transform { get; set; } // 游戲對象的的運動public ISSActionCallback callback { get; set; } // 回調函數public virtual void Start() {} // Start()重寫方法public virtual void Update() {} // Update()重寫方法 }public class SSActionManager : MonoBehaviour, ISSActionCallback {// 動作集private Dictionary<int, SSAction> actions = new Dictionary<int, SSAction>();// 即將開始的動作的等待加入隊列private List<SSAction> waitingAdd = new List<SSAction>();// 已完成的的動作的等待刪除隊列private List<int> waitingDelete = new List<int>();protected void Update() {// 載入即將開始的動作foreach (SSAction ac in waitingAdd) {actions[ac.GetInstanceID()] = ac;}// 清空等待加入隊列waitingAdd.Clear();// 運行載入動作foreach (KeyValuePair<int, SSAction> kv in actions) {SSAction ac = kv.Value;if (ac.destroy) {waitingDelete.Add(ac.GetInstanceID());}else if (ac.enable) {ac.Update();}}// 清空已完成的動作foreach (int key in waitingDelete) {SSAction ac = actions[key];actions.Remove(key);Object.Destroy(ac);}// 清空等待刪除隊列waitingDelete.Clear();}// 初始化動作并加入到等待加入隊列public void RunAction(GameObject gameobject, SSAction action, ISSActionCallback manager){action.gameobject = gameobject;action.transform = gameobject.transform;action.callback = manager;waitingAdd.Add(action);action.Start();}// 巡邏兵正常巡邏或追蹤玩家行為結束后的回調方法public void SSActionEvent(SSAction source,SSActionEventType events = SSActionEventType.Competed,int intParam = 0,string strParam = null,GameObject objectParam = null){// 如果消息的回調參數為1,追蹤行為結束,開始正常巡邏if(intParam == 1) {// 繼續巡邏PatrolNormalAction move = PatrolNormalAction.GetSSAction(objectParam.gameObject.GetComponent<PatrolData>().startPos);this.RunAction(objectParam, move, this);// 玩家逃脫消息Singleton<GameEventManager>.Instance.PlayerGetAway();}// 如果消息的回調參數為0,正常巡邏結束,開始追蹤玩家else {// 追蹤玩家PatrolTrackAction trackAction = PatrolTrackAction.GetSSAction(objectParam.gameObject.GetComponent<PatrolData>().trackPlayer);this.RunAction(objectParam, trackAction, this);}}// 清除所有動作public void DestroyAll() {foreach (KeyValuePair<int, SSAction> kv in actions) {SSAction ac = kv.Value;ac.destroy = true;}} }

ISSActionCallback.cs:

ISSActionCallback是巡邏兵正常巡邏或追蹤玩家行為結束后的回調接口,當巡邏兵由正常巡邏轉為追蹤玩家,或由追蹤玩家轉為正常巡邏,就會調用這個接口里的SSActionEvent方法,開始新的行為和消息操作,由SSActionManager這個類繼承:

public enum SSActionEventType : int { Started, Competed } public interface ISSActionCallback {// 回調函數void SSActionEvent(SSAction source,SSActionEventType events = SSActionEventType.Competed,int intParam = 0,string strParam = null,Object objectParam = null); }

PatrolNormalAction.cs:

PatrolNormalAction是巡邏兵的普通巡邏方法,巡邏兵按照一個矩形進行移動,如果玩家進入巡邏兵的感知范圍,那么會發送普通巡邏行為結束消息:

public class PatrolNormalAction : SSAction {private Vector3 pos; // 巡邏兵位置private float rectLength; // 矩形長度public float speed = 1f; // 移動速度private bool isDest; // 是否每個方向的終點private int direction; // 巡邏兵的移動方向private PatrolData patrol; // 巡邏兵數據private MainController mainController;private const int EAST = 0;private const int NORTH = 1;private const int WEST = 2;private const int SOUTH = 3;// 獲取動作public static PatrolNormalAction GetSSAction(Vector3 location) {PatrolNormalAction action = CreateInstance<PatrolNormalAction>();action.pos = new Vector3(location.x, 0, location.z);// 設定矩形邊長action.rectLength = Random.Range(4, 8);return action;}public override void Start() {this.gameobject.GetComponent<Animator>().SetBool("run", true);patrol = this.gameobject.GetComponent<PatrolData>();mainController = Director.GetInstance().mainController;isDest = true;direction = EAST;}public override void Update() {// 巡邏兵按矩形移動MoveRect();// 如果巡邏兵和玩家在同一區域并在巡邏兵感知范圍內,那么開始追蹤if (mainController.GetPlayerAreaId() == patrol.patrolAreaId && patrol.isTrackPlayer) {this.destroy = true;this.callback.SSActionEvent(this, SSActionEventType.Competed, 0, null, this.gameobject);}}void MoveRect() {float newPosX = pos.x;float newPosZ = pos.z;if (isDest) {// 設定每個方向的新的移動終點switch (direction) {case EAST:newPosX -= rectLength;break;case NORTH:newPosZ += rectLength;break;case WEST:newPosX += rectLength;break;case SOUTH:newPosZ -= rectLength;break;}isDest = false;}Vector3 newPos = new Vector3(newPosX, 0, newPosZ);this.transform.LookAt(newPos);float distance = Vector3.Distance(transform.position, newPos);// 沿著方向直走if (distance > 1) {transform.position = Vector3.MoveTowards(this.transform.position, newPos, speed * Time.deltaTime);}// 在轉彎處改變方向else {direction = (direction + 1) % 4;isDest = true;}// 設定新的位置pos.x = newPosX;pos.z = newPosZ;} }

PatrolTrackAction.cs:

PatrolTrackAction是巡邏兵的追蹤方法,當玩家進入巡邏兵的感知范圍內時,巡邏兵會使用這一方法,開始追蹤玩家,如果玩家走出了巡邏兵的感知范圍,則會發送追蹤行為結束消息:

public class PatrolTrackAction : SSAction {private GameObject trackPlayer; // 追蹤的玩家private PatrolData patrol; // 巡邏兵private MainController mainController;public override void Start() {patrol = this.gameobject.GetComponent<PatrolData>();mainController = Director.GetInstance().mainController;}public override void Update() {// 朝玩家方向走transform.position = Vector3.MoveTowards(this.transform.position, trackPlayer.transform.position, 2 * Time.deltaTime);this.transform.LookAt(trackPlayer.transform.position);// 如果玩家和巡邏兵不在同一個區域,或巡邏兵沒有感知到玩家if (mainController.GetPlayerAreaId() != patrol.patrolAreaId || !patrol.isTrackPlayer) {// 發送追蹤行為結束消息this.destroy = true;this.callback.SSActionEvent(this, SSActionEventType.Competed, 1, null, this.gameobject);}}// 獲取動作public static PatrolTrackAction GetSSAction(GameObject player) {PatrolTrackAction action = CreateInstance<PatrolTrackAction>();action.trackPlayer = player;return action;} }

PatrolMoveManager.cs:

PatrolMoveManager是巡邏兵的移動方法管理器,里面有一個按照矩形移動的方法:

public class PatrolMoveManager : SSActionManager {// 按照矩形移動public void MoveRect(GameObject patrol) {PatrolNormalAction moveRect = PatrolNormalAction.GetSSAction(patrol.transform.position);this.RunAction(patrol, moveRect, this);} }

接著實現游戲事件處理部分,以及為游戲對象編寫的腳本所完成,使用訂閱與發布模式傳遞消息:

GameEventManager.cs:

GameEventManager是處理游戲事件的代理模型,有三個事件的代理,分別是增加分數,減少寶箱和游戲結束:

public class GameEventManager : MonoBehaviour {// 增加分數public delegate void AddScoreEvent();public static event AddScoreEvent AddScoreAction;// 減少寶箱public delegate void DecreaseTreasureEvent();public static event DecreaseTreasureEvent DecreaseTreasureAction;// 游戲結束public delegate void GameoverEvent();public static event GameoverEvent GameoverAction;// 玩家逃脫public void PlayerGetAway() {if (AddScoreAction != null) {AddScoreAction();}}// 減少寶箱數量public void DecreaseTreasureNum() {if (DecreaseTreasureAction != null) {DecreaseTreasureAction();}}// 玩家被抓到了public void PlayerGetCaught() {if (GameoverAction != null) {GameoverAction();}} }

TreasureCollision.cs:

TreasureCollision是寶箱的碰撞的腳本,當玩家碰撞到寶箱時,寶箱會從圖中消失,并發送減少寶箱數量的消息:

public class TreasureCollision : MonoBehaviour {void OnTriggerEnter(Collider collider) {// 如果是玩家碰到還在顯示中的寶箱if (collider.gameObject.tag == "Player" && this.gameObject.activeSelf) {this.gameObject.SetActive(false);// 減少寶箱數量Singleton<GameEventManager>.Instance.DecreaseTreasureNum();}} }

PlayerCollision.cs:

PlayerCollision是巡邏兵與玩家碰撞的處理腳本,當巡邏兵感知到與其發生碰撞的對象是玩家,那么調整玩家狀態,觸發玩家被抓事件,如果碰撞是墻,那么根據剛體性質,改換方向移動:

public class PlayerCollision : MonoBehaviour {void OnCollisionEnter(Collision collider) {// 當和巡邏兵相撞的是玩家,那么調整玩家狀態,觸發玩家被抓事件,如果碰撞是墻,那么改換方向移動if (collider.gameObject.tag == "Player") {collider.gameObject.GetComponent<Animator>().SetTrigger("death");this.GetComponent<Animator>().SetTrigger("attack");Singleton<GameEventManager>.Instance.PlayerGetCaught();}} }

AreaTrigger.cs:

AreaTrigger是地圖中每個區域的觸發腳本,地圖一共被分割成9個區域,每個區域有一個巡邏兵,當玩家進入某個區域時,區域會感知到玩家,并記錄玩家進入區域的序號:

public class AreaTrigger : MonoBehaviour {public int areaId; // 區域序號MainController mainController;private void Start() {mainController = Director.GetInstance().mainController as MainController;}void OnTriggerEnter(Collider collider) {// 記錄玩家進入區域的序號if (collider.gameObject.tag == "Player") {mainController.SetPlayerAreaId(areaId);}} }

PatrolTrigger.cs:

PatrolTrigger是巡邏兵的觸發腳本,當玩家進入或退出巡邏兵的感知范圍使,設置巡邏兵追蹤玩家的狀態和追蹤玩家的對象:

public class PatrolTrigger : MonoBehaviour {void OnTriggerEnter(Collider collider) {// 如果玩家進入巡邏兵感知范圍if (collider.gameObject.tag == "Player") {// 設置巡邏兵正在追蹤玩家,設置追蹤的玩家對象this.gameObject.transform.parent.GetComponent<PatrolData>().isTrackPlayer = true;this.gameObject.transform.parent.GetComponent<PatrolData>().trackPlayer = collider.gameObject;}}void OnTriggerExit(Collider collider) {// 如果玩家退出巡邏兵感知范圍if (collider.gameObject.tag == "Player") {// 設置巡邏兵不在追蹤玩家,設置追蹤的玩家對象為空this.gameObject.transform.parent.GetComponent<PatrolData>().isTrackPlayer = false;this.gameObject.transform.parent.GetComponent<PatrolData>().trackPlayer = null;}} }

最后實現主控制類和視圖部分:

MainController.cs:

主控制類MainController的代碼如下:

public class MainController : MonoBehaviour {private ScoreController scoreRecorder; // 記分器private PatrolMoveManager moveManager; // 移動管理器private int playerAreaId; // 玩家所處區域序號private GameObject player; // 玩家對象public Camera mainCamera; // 主相機public int treasureNumber = 10; // 寶箱數量public float moveSpeed = 5; // 移動速度public float rotateSpeed = 135f; // 旋轉速度private bool isGameOver; // 游戲是否結束void Start() {Director director = Director.GetInstance();director.mainController = this;scoreRecorder = gameObject.AddComponent<ScoreController>() as ScoreController;moveManager = gameObject.AddComponent<PatrolMoveManager>() as PatrolMoveManager;LoadResources();mainCamera.GetComponent<CameraFollow>().follow = player;isGameOver = false;}void Update() {CheckGameOver();}// 加載資源public void LoadResources() {// 生成地圖Instantiate(Resources.Load<GameObject>("Prefabs/Map"));// 生成玩家player = Instantiate(Resources.Load("Prefabs/Player"), new Vector3(0, 9, 0), Quaternion.identity) as GameObject;// 生成寶箱Singleton<GameObjectFactory>.Instance.GetTreasures();// 生成巡邏兵并讓其移動MovePatrol();}public void MovePatrol() {// 讓所有巡邏兵都移動List<GameObject> patrols = Singleton<GameObjectFactory>.Instance.GetPatrols();for (int i = 0; i < patrols.Count; i++) {moveManager.MoveRect(patrols[i]);}}// 玩家移動public void MovePlayer(float translationX, float translationZ) {if(!isGameOver) {MovePlayerAction(translationX, translationZ);if (player.transform.position.y != 0) {player.transform.position = new Vector3(player.transform.position.x, 0, player.transform.position.z);} }}// 設置玩家移動時的跑步動作public void MovePlayerAction(float translationX, float translationZ) {if (translationX != 0 || translationZ != 0) {player.GetComponent<Animator>().SetBool("run", true);}else {player.GetComponent<Animator>().SetBool("run", false);}// 移動和旋轉動作player.transform.Translate(0, 0, translationZ * moveSpeed * Time.deltaTime);player.transform.Rotate(0, translationX * rotateSpeed * Time.deltaTime, 0);}public void IncreaseScore() {scoreRecorder.IncreaseScore();}public void CheckGameOver() {// 所有寶箱都被收集,游戲結束if(treasureNumber == 0) {Gameover();}}// 游戲結束,釋放所有的巡邏兵public void Gameover() {isGameOver = true;Singleton<GameObjectFactory>.Instance.FreePatrols();moveManager.DestroyAll();}public void DecreaseTreasureNumber() {treasureNumber--;}public int GetScore() {return scoreRecorder.GetScore();}public void SetPlayerAreaId(int areaId) {playerAreaId = areaId;}public int GetPlayerAreaId() {return playerAreaId;}public int GetTreasureNumber() {return treasureNumber;}public bool GetGameover() {return isGameOver;}public void Restart() {SceneManager.LoadScene("Scenes/SampleSence");}void OnEnable() {GameEventManager.AddScoreAction += IncreaseScore;GameEventManager.GameoverAction += Gameover;GameEventManager.DecreaseTreasureAction += DecreaseTreasureNumber;}void OnDisable() {GameEventManager.AddScoreAction -= IncreaseScore;GameEventManager.GameoverAction -= Gameover;GameEventManager.DecreaseTreasureAction -= DecreaseTreasureNumber;} }

CameraFollow.cs:

CameraFollow是攝像機跟隨腳本,攝像機可以跟隨玩家移動,提高可玩性:

public class CameraFollow : MonoBehaviour {public GameObject follow; // 跟隨的物體public float speed = 5f; // 相機跟隨物體的的速度Vector3 offsetPos; // 相機和物體的相對偏移位置void Start() {offsetPos = transform.position - follow.transform.position;}void FixedUpdate() {Vector3 targetPos = follow.transform.position + offsetPos;// 攝像機平滑過渡到目標位置transform.position = Vector3.Lerp(transform.position, targetPos, speed * Time.deltaTime);} }

View.cs:

視圖類經過主控制器的控制,顯示相應內容:

public class View : MonoBehaviour {private MainController mainController;void Start() {mainController = Director.GetInstance().mainController as MainController;}void Update() {Move();}void OnGUI() {ShowScore();ShowRules();GUIStyle textStyle = new GUIStyle();textStyle.fontSize = 30;if(mainController.GetGameover() && mainController.GetTreasureNumber() != 0) {GUI.Label(new Rect(Screen.width / 2 - 55, Screen.width / 2 - 250, 100, 100), "游戲結束", textStyle);if (GUI.Button(new Rect(Screen.width / 2 - 45, Screen.width / 2 - 170, 100, 50), "重新開始")) {mainController.Restart();}}else if(mainController.GetTreasureNumber() == 0) {GUI.Label(new Rect(Screen.width / 2 - 55, Screen.width / 2 - 250, 100, 100), "恭喜勝利!", textStyle);if (GUI.Button(new Rect(Screen.width / 2 - 45, Screen.width / 2 - 170, 100, 50), "重新開始")) {mainController.Restart();}}}public void Move() {float translationX = Input.GetAxis("Horizontal");float translationZ = Input.GetAxis("Vertical");mainController.MovePlayer(translationX, translationZ);}public void ShowScore() {GUIStyle scoreStyle = new GUIStyle();GUIStyle textStyle = new GUIStyle();scoreStyle.normal.textColor = Color.yellow;scoreStyle.fontSize = 20;textStyle.fontSize = 20;GUI.Label(new Rect(Screen.width - 100, 5, 200, 50), "分數:", textStyle);GUI.Label(new Rect(Screen.width - 50, 5, 200, 50), mainController.GetScore().ToString(), scoreStyle);GUI.Label(new Rect(10, 5, 50, 50), "剩余寶箱數:", textStyle);GUI.Label(new Rect(125, 5, 50, 50), mainController.GetTreasureNumber().ToString(), scoreStyle);}// 展示規則public void ShowRules() {GUIStyle ruleStyle = new GUIStyle();ruleStyle.fontSize = 17;GUI.Label(new Rect(Screen.width / 2 - 80, 10, 100, 100), "按方向鍵進行移動", ruleStyle);GUI.Label(new Rect(Screen.width / 2 - 190, 30, 100, 100), "每次甩掉一個巡邏兵計一分,與巡邏兵碰撞游戲結束", ruleStyle);GUI.Label(new Rect(Screen.width / 2 - 130, 50, 100, 100), "收集完所有的寶箱那么游戲獲勝", ruleStyle);} }

Director.cs:

導演類,返回主控制器的唯一實例:

public class Director : System.Object {private static Director instance;public MainController mainController { get; set; }public static Director GetInstance() {if (instance == null) {instance = new Director();}return instance;} }

核心算法

在MainController的MovePlayerAction方法中,因為要模擬玩家的跑步動作,需要在普通狀態和跑步狀態之間切換,就需要根據位移對狀態機進行判斷操作,以實現跑步的效果,所編寫的代碼如下:

// 設置玩家移動時的跑步動作 public void MovePlayerAction(float translationX, float translationZ) {if (translationX != 0 || translationZ != 0) {player.GetComponent<Animator>().SetBool("run", true);}else {player.GetComponent<Animator>().SetBool("run", false);}// 移動和旋轉動作player.transform.Translate(0, 0, translationZ * moveSpeed * Time.deltaTime);player.transform.Rotate(0, translationX * rotateSpeed * Time.deltaTime, 0); }

在PatrolTrackAction的Update方法中,實現巡邏兵對玩家的追蹤,之后如果玩家走出了巡邏兵所在或者感知區域,那么就會發送追蹤行為結束消息,在代理處實現分數加一行為:

public override void Update() {// 朝玩家方向走transform.position = Vector3.MoveTowards(this.transform.position, trackPlayer.transform.position, 2 * Time.deltaTime);this.transform.LookAt(trackPlayer.transform.position);// 如果玩家和巡邏兵不在同一個區域,或巡邏兵沒有感知到玩家if (mainController.GetPlayerAreaId() != patrol.patrolAreaId || !patrol.isTrackPlayer) {// 發送追蹤行為結束消息this.destroy = true;this.callback.SSActionEvent(this, SSActionEventType.Competed, 1, null, this.gameobject);} }

游戲截圖:

游戲界面:

被巡邏兵抓到,巡邏兵攻擊,倒地游戲失敗:

收集完全部寶箱,游戲成功:

巡邏兵偏離巡邏軌跡,開始追蹤:

總結

以上是生活随笔為你收集整理的用Unity3D实现智能巡逻兵游戏的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。