智能巡邏兵
遊戲設計要求:
- 創建一個地圖和若干巡邏兵(使用動畫);
- 每個巡邏兵走一個3~5個邊的凸多邊型,位置數據是相對地址。即每次確定下一個目標位置,用自己當前位置爲原點計算;
- 巡邏兵碰撞到障礙物,則會自動選下一個點爲目標;
- 巡邏兵在設定範圍內感知到玩家,會自動追擊玩家
- 失去玩家目標後,繼續巡邏;
- 計分:玩家每次甩掉一個巡邏兵計一分,與巡邏兵碰撞遊戲結束;
程序設計要求:
必須使用訂閱與發佈模式傳消息
subject:OnLostGoal
Publisher: ?
Subscriber: ?
設計過程
設計模式參考之前的博客,大致如下
訂閱與發佈模式:
通過gameStatusOp類完成,這個類提供:
- score方法,調用一次加一分;其他類的事件通過訂閱這個函數完成遊戲的計分,巡邏兵類的checkNearByHero訂閱此函數,每次玩家離開巡邏範圍都能夠增加分數。
- gameover方法:巡邏兵類的OnCollisionStay訂閱此函數,每次玩家碰撞巡邏兵之後即可宣告結束。
設計效果如下:
按鍵控制
使用detectKeyInput()和Input.GetKey()函數進行控制,傳遞移動信息。
void detectKeyInput() {
if (Input.GetKey(KeyCode.UpArrow)) {
action.heroMove(Diretion.UP);
}
if (Input.GetKey(KeyCode.DownArrow)) {
action.heroMove(Diretion.DOWN);
}
if (Input.GetKey(KeyCode.LeftArrow)) {
action.heroMove(Diretion.LEFT);
}
if (Input.GetKey(KeyCode.RightArrow)) {
action.heroMove(Diretion.RIGHT);
}
}
巡邏兵工廠
生成4個相同的巡邏兵,很適合使用工廠模式進行。
public class PatrolFactory : System.Object {
private static PatrolFactory instance;
private GameObject PatrolItem;
private Vector3[] PatrolPosSet = new Vector3[] {
new Vector3(-5f, 0.2f, -5f),
new Vector3(-5f, 0.2f, 5f),
new Vector3(5f, 0.2f, -5f),
new Vector3(5f, 0.2f, 5f)};
public static PatrolFactory getInstance() {
if (instance == null)
instance = new PatrolFactory();
return instance;
}
public void initItem(GameObject _PatrolItem) {
PatrolItem = _PatrolItem;
}
public GameObject getPatrol() {
GameObject newPatrol = Camera.Instantiate(PatrolItem);
return newPatrol;
}
public Vector3[] getPosSet() {
return PatrolPosSet;
}
}
玩家的移動
通過一個函數,使得整個物體的朝向和位置發生改變即可
public void heroMove(int dir) {
myHero.transform.rotation = Quaternion.Euler(new Vector3(0, dir * 90, 0));
switch (dir) {
case Diretion.UP:
myHero.transform.position += new Vector3(0, 0, 0.1f);
break;
case Diretion.DOWN:
myHero.transform.position += new Vector3(0, 0, -0.1f);
break;
case Diretion.LEFT:
myHero.transform.position += new Vector3(-0.1f, 0, 0);
break;
case Diretion.RIGHT:
myHero.transform.position += new Vector3(0.1f, 0, 0);
break;
}
}
巡邏兵的移動
首先考慮隨機移動,通過隨機函數計算其朝向和移動距離,傳遞信息給action模塊,給巡邏兵添加移動。對於抓捕移動,則可以直接朝向主人公,並且不斷的更新位置,即可實現抓捕效果。
int getRandomDirection(int index, bool isActive) {
return PatrolLastDir[index] == 2 ? -1 : PatrolLastDir[index] + 1;
}
//判定巡邏兵走出了自己的區域
bool PatrolOutOfArea(int index, int randomDir) {
Vector3 patrolPos = PatrolSet[index].transform.position;
float posX = patrolPos.x;
float posZ = patrolPos.z;
switch (index) {
case 0:
if (randomDir == 1 && posX + 2 > 0
|| randomDir == 0 && posZ + 2 > 0)
return true;
break;
case 1:
if (randomDir == 1 && posX + 2 > 0
|| randomDir == 2 && posZ - 2 < 0)
return true;
break;
case 2:
if (randomDir == -1 && posX - 2 < 0
|| randomDir == 0 && posZ + 2 > 0)
return true;
break;
case 3:
if (randomDir == 1 && posX + 2 > 0
|| randomDir == 0 && posZ + 2 > 0)
return true;
break;
}
return false;
}
//追捕hero
public void addDirectMovement(GameObject sourceObj) {
int index = getIndexOfObj(sourceObj);
PatrolLastDir[index] = -2;
sourceObj.transform.LookAt(myHero.transform);
Vector3 oriTarget = myHero.transform.position - sourceObj.transform.position;
Vector3 target = new Vector3(oriTarget.x / 4.0f, 0, oriTarget.z / 4.0f);
target += sourceObj.transform.position;
//Debug.Log("addDirectMovement: " + target);
addSingleMoving(sourceObj, target, PERSON_SPEED_CATCHING, true);
}
```