2DRoguelike拾荒者(unity)

同樣的,實現(xiàn)過程只記大致思路與新知識點,不記細節(jié)。
github: https://github.com/robotluo/2DRoguelike
大致實現(xiàn)功能:
 1.創(chuàng)建主角和敵人,創(chuàng)建地圖
 2.隨機生成敵人和食物
 3.獲取食物、碰撞檢測
 4.與敵人碰撞時狀態(tài)機的變換
 5.血量控制、關(guān)卡轉(zhuǎn)換
 6.添加音效

2DRoguelike 是官方的案例之一,與之前所用的有所區(qū)別在于使用了狀態(tài)機來控制人物動畫。
  狀態(tài)機保存了許多不同的狀態(tài),事件觸發(fā)可以改變狀態(tài)機的狀態(tài),實現(xiàn)效果的轉(zhuǎn)換。

創(chuàng)建地圖:

將素材裝入一個數(shù)組,隨機一個索引并創(chuàng)建實例。

// outWalls 為外墻數(shù)組
// Map 為一個空 GameOnject 的 Transform,用于裝載地圖,比較整潔 
int outWallIndex = Random.Range (0, outWalls.Length);
GameObject tmp = GameObject.Instantiate (outWalls [outWallIndex], new Vector3 (row, col, 0), Quaternion.identity) as GameObject;
tmp.transform.SetParent (Map);

當(dāng)我們有許多實例需要隨機生成時,例如,敵人、食物、障礙物等都需要隨機生成在地圖中,因此可以寫一個專門的方法。
先將地圖上能存實例的坐標存入 mapList:

private List<Vector2> mapList = new List<Vector2>();
//將地圖上能放置物品的坐標存入 mapList
        mapList.Clear ();
        for (int row = 2; row <= rowMax - 2; row++) {
            for(int col =2 ;col <= colMax - 2; col++) {
                mapList.Add (new Vector2 (row, col));
            }
        }

專門用于創(chuàng)建的方法:

void creatElement(int count, GameObject[] array){
        for (int i = 0; i < count; i++) {
            int listIndex = Random.Range (0, mapList.Count ); //隨機取得放置點
            int arrIndex = Random.Range (0, array.Length);  //隨機取得對象

            Vector2 pos = mapList [listIndex]; //取出放置點
            mapList.Remove(pos);            // list 中去掉該位置
            GameObject tmp = GameObject.Instantiate (array[arrIndex],pos,Quaternion.identity) as GameObject;
            tmp.transform.SetParent (Map);
        }
    }

調(diào)用時只需要傳入數(shù)量和數(shù)組即可。

狀態(tài)機的創(chuàng)建:

將素材多選直接拖入Hierarchy 中,會自動生成兩個文件。一個是動畫,這里命名為 Animation ,另一個是控制器,這里命名為AnimatorController。狀態(tài)機的邏輯非常簡單,將每個狀態(tài)的具體實現(xiàn)封裝起來,當(dāng)滿足某個條件,將狀態(tài)從當(dāng)前狀態(tài)轉(zhuǎn)換到另一狀態(tài),狀態(tài)內(nèi)部與狀態(tài)轉(zhuǎn)換之間不互相影響。
  如果一個主角有多個狀態(tài),例如有靜止、移動、攻擊、受傷等等,只需要將其全部拖到同一個物體上,如果直接拖到 Hierarchy 會產(chǎn)生多個狀態(tài)機。
共用狀態(tài)機:
  狀態(tài)機分為兩部分,動畫和控制。在實際中我們可能需要多個角色共用同一狀態(tài)機。例如,兩種不同的怪物,他們的動畫不同,但是處理狀態(tài)的邏輯是完全一樣的,這時候如果分別使用兩個狀態(tài)機就有點多余,所以需要共用。
  我們可以這么做,如果我們有了一個 Controller_1 想要重用,首先在同一文件夾下右鍵 -> create -> Animator Override Controller,命名為 Controller_2 ,點擊 Controller_2 會看到 Inspector 視圖下有一個 Controller 需要賦值,將 Controller_1 賦值到此處,再將新的動畫進行對應(yīng)賦值。這樣,Controller_1 與 Controller_2 就共用一套邏輯。
狀態(tài)切換:
  雙擊一個控制器,選中一個狀態(tài),右鍵 Make Transition,會出現(xiàn)一個箭頭,此時連接到需要轉(zhuǎn)換的狀態(tài)。
例如:

狀態(tài)機.png

連線代表能夠轉(zhuǎn)換,現(xiàn)在需要自定義轉(zhuǎn)換的條件。如下圖,添加兩個 Trigger
Trigger.png

選中連線,再在 Inspector 視圖下 Conditions 添加 所需Trigger,改變Has Exit Time 勾選,Has Exit Time表示播放完變換,當(dāng)我們攻擊時應(yīng)該是立刻做出反應(yīng),所以不需要勾選。而從攻擊狀態(tài)變?yōu)槠胀顟B(tài)只需要播放完即可,不需要Trigger。

主角移動:

添加 Rigidbody ,用 MovePosition 方法移動

myRigidbody = GetComponent<Rigidbody2D> ();
myRigidbody.MovePosition (Vector2.Lerp(transform.position, movePosition, moveSpeed * Time.deltaTime));
//(當(dāng)前位置,目標位置,移動速度)

碰撞檢測:
  這里采用射線的方式進行碰撞檢測,向目標位置發(fā)射射線,判斷所碰撞物體種類再進行相關(guān)處理。

myCollider.enabled = false; //去掉當(dāng)前碰撞器,防止檢測到自身
RaycastHit2D hit = Physics2D.Linecast (movePosition,movePosition + new Vector2(hor,ver));
myCollider.enabled = true; //重新啟用碰撞器

對 hit 進行判斷和相關(guān)處理即可。
例如:攻擊墻體,需要向其發(fā)送一個信息,以及播放攻擊動畫

private Animator myAnimator;
myAnimator = GetComponent<Animator> ();
myAnimator.SetTrigger ("Attack"); //改變狀態(tài)機

hit.collider.SendMessage ("Damager");//調(diào)用墻體的 Damager fangfa

怪物控制:
  怪物與主角的控制方式不同,主角是按鍵控制,而怪物是自己移動。
在一個單例 GameManager 中用一個 List 儲存所有敵人,當(dāng)主角移動時,調(diào)用 GameManager 中的 相應(yīng)方法,遍歷 List 通知所有敵人移動。

Text 顯示信息:
  我們需要幾個 UI Text 來顯示信息,需要顯示當(dāng)前食物的剩余、提示當(dāng)前關(guān)卡、游戲結(jié)束時顯示 Game Over?!?br> 例如顯示食物數(shù)量:

private Text foodText;  //
foodText = GameObject.Find ("FoodText").GetComponent<Text> ();//按名稱查找
foodText.text = "Food : " + Hp;

關(guān)卡變換:

關(guān)卡的變換首先要判斷是否到達這種,這里有一個細節(jié)。我們判斷是否到達終點需要知道主角的位置,所以在 GameManager 中要先獲得主角的引用。但若是在 Awake 中獲取,MapManager 可能并沒有把主角創(chuàng)建出來,此時會報錯。所以地圖的創(chuàng)建一定要在 MapMahager 中的 Awake,而主角的獲取需要在 GameManager 中的 Start。
  當(dāng)然,還有一種方式就是在 GameManage 中統(tǒng)一控制,先創(chuàng)建地圖再創(chuàng)建 UI。
  關(guān)卡變換涉及到一個場景的切換(新知識),關(guān)卡變換地圖需要重新生成,但血量,關(guān)卡數(shù)需要保留。
  為了保留血量和關(guān)卡,我們在進入新的關(guān)卡時不能銷毀當(dāng)前 GameManager 。

DontDestroyOnLoad (this.gameObject);//在 GameManager 中使用此方法,重新加載時不銷毀 GamaManager
void OnLevelWasLoaded(int scenesLevel) { 
//每次加載關(guān)卡時都會調(diào)用,可以在其中寫一些需要更新的信息,具體可以查看API
  level++;
  initGame (); //初始化場景
}

此時會發(fā)現(xiàn),雖然當(dāng)前 GameManager 沒有被銷毀,但是出現(xiàn)了兩個 GamaManager 。所以我們需要將 GameManager 做成 Prefabs ,不讓它存在場景中,而是用創(chuàng)建的方式。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,715評論 19 139
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,835評論 4 61
  • This article is a record of my journey to learn Game Deve...
    蔡子聰閱讀 4,129評論 0 9
  • 文/鴻運 雨后天邊掛彩虹,云托雁字輕。 高山流水賦真情,竹林簫響應(yīng)。 爬山虎,醉翁亭,層層碧綠蔥。 欲把花草化春雨...
    HONGYUNDANGTOU閱讀 595評論 6 12
  • 我很多時候都在想,自己內(nèi)心真正想做的事情到底是什么。雖然我的興趣愛好很廣泛,但是在所有興趣之中我最終還是得找一樣來...
    鈐魚擺擺閱讀 223評論 1 1

友情鏈接更多精彩內(nèi)容