Unity之智能巡邏兵

智能巡邏兵

遊戲設計要求:

  • 創建一個地圖和若干巡邏兵(使用動畫);
  • 每個巡邏兵走一個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);
    }
```

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章