HW10-Al坦克
一、作業要求
坦克對戰游戲 AI 設計
- 從商店下載游戲:“Kawaii” Tank 或 其他坦克模型,構建 AI 對戰坦克。具體要求
使用“感知-思考-行為”模型,建模 AI 坦克 - 場景中要放置一些障礙阻擋對手視線
- 坦克需要放置一個矩陣包圍盒觸發器,以保證 AI 坦克能使用射線探測對手方位
- AI 坦克必須在有目標條件下使用導航,并能繞過障礙。(失去目標時策略自己思考)
- 實現人機對戰
二、相關知識
1.“感知-思考-行為”模型
“sense-think-act” paradigm(范式) 是構造 agent、robot、NPC(Non-Player Character) 的基礎概念。
- 感知是 agent 接收世界信息的行為,其獲取的數據將是思考的輸入。
- Think 就是算法,它的輸入是感知的數據,輸出是行為(behaviours)。 思考的算法,通常就是我們所說的游戲規則的一部分,即 agent 能做什么,該做什么。
- 行動(Act)將思考(Think)的結果作為輸入,該部分的任務就是使得 agent 行為更符合物理世界的規律,使得“心想事成”這樣理想的結果變得不確定。
2.導航與尋路
Unity 導航系統允許創建給游戲角色導航的游戲世界。官方文檔導航系統
- NavMesh (Navigation Mesh) 是一種數據結構,它描述了游戲對象可行走的表面。通過三角網格,計算其中任意兩點之間的最短路徑,用于游戲對象的導航。它是根據場景幾何結構自動創建或烘焙構建。
- NavMesh Agent組件創建具有尋路能力的角色。Agent 使用NavMesh 推理,避免彼此以及移動障礙物。
- Off-Mesh Link組件允許將不連接的塊之間建立“傳送門”。例如,跳過溝渠或圍欄,或在穿過它之前打開門,都可以被描述為 Off-Mesh Link。
- NavMesh 障礙 組件允許您描述 agent 在移動時應避免的移動障礙。由物理系統控制的桶或箱子就是很典型的障礙。在障礙物移動的過程中,- Agent 盡力避開它,但一旦障礙物變得靜止,它將在導航網格上開一個洞,以便 Agent 可以改變他們的路徑以繞過它,或者靜止的障礙物阻塞路徑,使得 Agent 找到其他路線。
三、關鍵部分
1.工廠模式生產需要用到的資源如坦克、子彈等,以及它們的回收利用。
//生產坦克 if (freeTanks.Count <= 0){newTank = GameObject.Instantiate<GameObject>(enemy) as GameObject;usingTanks.Add(newTank);newTank.transform.position = new Vector3(Random.Range(-100, 100), 0, Random.Range(-100, 100));}else{newTank = freeTanks[0];freeTanks.RemoveAt(0);usingTanks.Add(newTank);} //生產子彈 if(freeBullets.Count <= 0){newBullet = GameObject.Instantiate<GameObject>(bullet) as GameObject;usingBullets.Add(newBullet);newBullet.transform.position = new Vector3(Random.Range(-100, 100), 0, Random.Range(-100, 100));}else{newBullet = freeBullets[0];freeBullets.RemoveAt(0);usingBullets.Add(newBullet);} //回收 public void recycleEnemy(GameObject enemyTank){usingTanks.Remove(enemyTank);freeTanks.Add(enemyTank);enemyTank.GetComponent<Rigidbody>().velocity = Vector3.zero;enemyTank.SetActive(false);}public void recycleBullet(GameObject Bullet){usingBullets.Remove(Bullet);freeBullets.Add(Bullet);Bullet.GetComponent<Rigidbody>().velocity = Vector3.zero;Bullet.SetActive(false);}2.坦克、子彈等基類
//坦克基類 public class Tank : MonoBehaviour {private float hp =500.0f;public Tank(){hp = 500.0f;}public float getHP(){return hp;}public void setHP(float hp){this.hp = hp;}public void beShooted(){hp -= 100;}public void shoot(TankType type){GameObject bullet = Singleton<MyFactory>.Instance.getBullets(type);bullet.transform.position = new Vector3(transform.position.x, 1.5f, transform.position.z) + transform.forward * 1.5f;bullet.transform.forward = transform.forward; //方向bullet.GetComponent<Rigidbody>().AddForce(bullet.transform.forward * 20, ForceMode.Impulse);} }//玩家操縱的坦克,移動及血量 void Start () {setHP(700);}void Update () {if(getHP() <= 0) {this.gameObject.SetActive(false);destroyEvent();}}public void moveForward(){gameObject.GetComponent<Rigidbody>().velocity = gameObject.transform.forward * 30;}public void moveBackWard(){gameObject.GetComponent<Rigidbody>().velocity = gameObject.transform.forward * -30;}public void turn(float offsetX){float x = gameObject.transform.localEulerAngles.x;float y = gameObject.transform.localEulerAngles.y + offsetX*2;gameObject.transform.localEulerAngles = new Vector3(x, y, 0);} //敵人的坦克尋路及射擊 void Update() {playerLocation = GameDirector.getInstance().currentSceneController.getPlayer().transform.position;gameover = GameDirector.getInstance().currentSceneController.getGameOver();if (!gameover){if (getHP() <= 0 && recycleEnemy != null){recycleEnemy(this.gameObject);}else{NavMeshAgent agent = gameObject.GetComponent<NavMeshAgent>();agent.SetDestination(playerLocation);}}else{NavMeshAgent agent = gameObject.GetComponent<NavMeshAgent>();agent.velocity = Vector3.zero;agent.ResetPath();}}IEnumerator shoot(){while (!gameover){for(float i =1;i> 0; i -= Time.deltaTime){yield return 0;}if(Vector3.Distance(playerLocation,gameObject.transform.position) < 14){shoot(TankType.ENEMY);}}}3.子彈的設定
//射出的子彈 private void OnCollisionEnter(Collision collision){if(collision.transform.gameObject.tag == "tankEnemy" && this.tankType == TankType.ENEMY ||collision.transform.gameObject.tag == "tankPlayer" && this.tankType == TankType.PLAYER){return;} //工廠模式生產子彈MyFactory factory = Singleton<MyFactory>.Instance;ParticleSystem explosion = factory.getParticleSystem();explosion.transform.position = gameObject.transform.position;Collider[] colliders = Physics.OverlapSphere(gameObject.transform.position, explosionRadius);foreach(var collider in colliders){float distance = Vector3.Distance(collider.transform.position, gameObject.transform.position);float hurt; //玩家射出的和敵人射出的傷害不同if (collider.tag == "tankEnemy" && this.tankType == TankType.PLAYER){hurt = 400.0f / distance;collider.GetComponent<Tank>().setHP(collider.GetComponent<Tank>().getHP() - hurt);}else if(collider.tag == "tankPlayer" && this.tankType == TankType.ENEMY){hurt = 100.0f / distance;collider.GetComponent<Tank>().setHP(collider.GetComponent<Tank>().getHP() - hurt);}explosion.Play();} //回收子彈if (gameObject.activeSelf){factory.recycleBullet(gameObject);}}四、成品
坦克等的模型資源在Assert商店中有
做出來效果如下
最后感謝師兄的博客給了很大的幫助!
視頻:視頻
總結
- 上一篇: acrobat PDF删除部分_墙裂推荐
- 下一篇: MyEclipse 2014配置Andr