Unity3D獨立遊戲開發日記(二):擺放建築物

王傳煒發表於2015-11-27

在沙盒遊戲裡,能自由建造是很重要的特點,比如說風靡全球的《我的世界》,用一個個方塊就能搭建出規模巨集大的世界。甚至有偏激的人說,沒有自由建造,就不是一個真正的沙盒遊戲。的確,沙盒遊戲的魅力有很大一部分是能自由構建一個遊戲世界。看著自己一磚一瓦搭建起一個城堡世界會很有成就感的。

現如今的手遊,大多數就是一個爭鬥和炫耀的世界。不管是傳奇類的狂霸拽酷,還是連連看,消消樂等好友排名,就是消費國人的虛榮心。其實,遊戲是第九藝術,要上升到藝術的角度。在遊戲裡,玩家需要一種情感的宣洩和寄託以及體驗。

說了這麼多,還是回到正題。我是如何在自己編寫的獨立遊戲《中世紀之路》裡實現建築物的擺放呢?

在實現這個功能的時候,我首先考慮的不是程式碼。而是考慮其他遊戲是如何實現這樣功能的,有那些可以借鑑的地方。我首先想到了《魔獸爭霸》裡建築物的擺放,可以自由的拖放。然後想到了《部落衝突》(簡稱COC)裡的建築放置方式,在COC裡建築是按格子擺放的,在一個平面上。

在我的遊戲《中世紀之路》裡,我既不想讓玩家一磚一瓦的搭建建築,又想讓玩家一下就把建築整體放置到地上了。我覺得像搭積木那樣,既可以節省玩家時間,又有建造的樂趣。選定了這種方式後,我就要考慮建築模組的資料儲存方式了:我需要儲存單個模組的三維空間裡的座標值(x,y,z的值),同時為了讓模型選擇,我還需要儲存模型的旋轉角度數。

然後,我還需要考慮如何用滑鼠去執行這個操作。我構想的方案是:點選揹包裡的物品後,一個模型就動態產生,然後跟隨滑鼠在地面移動。然後按"E"鍵就放置到地面上滑鼠所指的位置(E鍵放置,是我學《獸人必須死》得來的)。而元件的旋轉呢?我考慮的是讓滑鼠滾輪(也就是中鍵)滾動時,就繞著Y軸旋轉。當然如果更近一步,可以做到繞三個軸都能自由旋轉。具體操作見下圖:

建築擺放動畫

使用滑鼠放置篝火

通過上面的操作,我們可以看到程式碼的實現效果很好,完美達到了我們的需求。不過想通了上面的操作原理後,還需要我們動腦筋來構思,如何用程式碼來實現這些操作功能。這對新手來說可能過難了點,但對於有經驗的開發者就能比較快的找到近似的解決方案,然後加以改進。

我首先想到的是我曾經在手機上做過2D積木的搭建功能。把我們的操作動作拆解開來,無非就是三個步驟:

1.第一次按下手指或者滑鼠,找到初始座標,讓物體動態出現在座標位置上。

2.然後判斷移動情況,讓物體跟隨滑鼠或者手指的移動。

3.最後抬起手指或者滑鼠,讓物體固定在最後的座標位置,把座標資料寫入到文字或者資料庫裡。

想清楚了這三個步驟,我們就心裡底了,我們只要實現了這三步操作程式碼,基本上物體擺放功能就可以實現了。

在我實現第一個步驟的時候,我就遇到了個問題。我之前在寫搭積木遊戲的時候是2D的,座標很好獲取。但是在《中世紀之路》裡,我可是要獲取的是滑鼠在地面上的座標點啊。我開始用的是兩行程式碼:

Vector3 mousePosition= Input.mousePosition;    //獲取滑鼠所在的座標

Vector3 mouseWorldPosition =Camera.main.ScreenToWorldPoint(mousePosition) ; //把滑鼠的座標變成3D遊戲世界裡的空間座標

 

我以為我的思路是沒問題的,結果執行程式碼一看。哈哈,建築物完全不是擺在地面上的啊,是在空中的啊。後來查了相關文件才知道,這個滑鼠位置是滑鼠在螢幕這個立體面上的位置(你可以想象螢幕是一個透明的立體牆,這個牆是樹立在地面上的)。再說得專業點,是從主攝像機為起點,滑鼠所指為終點的一個射線,與螢幕所在立體面相交的點。對於這個立體面的直觀感覺,大家可以看看在3D空間裡2D UI介面所在的那個面。

所以,上面兩行程式碼是不能夠解決問題的。不過這麼一分析,我就接觸到了射線的概念。我轉念一想,如果我找到這個射線和地面相交的焦點不就行了嘛!我們的思路就變成了以下的虛擬碼:

1.建立一個從主攝像機為起點,滑鼠所指為終點的一個射線Ray。

2.找到Ray和地面Terrain的交點position。

3.把物體的座標動態建立於position。

核心程式碼如下:

if (Input.GetMouseButton(0))
 {
     Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

       RaycastHit hit;

       if(Physics.Raycast(ray, out hit))
       {

               if(hit.transform.name=="Terrain")
               {
                           position = hit.point;//得到與地面碰撞點的座標
               } 
        }
}

 

解決這個核心難題後,移動的程式碼就很好寫了。只要在手指或者滑鼠移動的時候,動態更新物體的座標為新的position就可以了。旋轉物體的程式碼也可以寫到一起,動態更新物體的旋轉度就可以了。這段程式碼很容易寫了,我就不貼出來了,新手可以鍛鍊自我動手能力。老手早就不用看在眼裡了。當然需要提醒的是這段程式碼是需要在update函式裡去執行的。

最後的固定物體座標的程式碼,也就演變成了把最後的position記錄於文字或者寫入資料庫了。這些程式碼都不是有多難寫的。

最後回顧下,我們整個解決問題的思路:

構思操作步驟和方式->分解操作步驟->用程式碼實現分解後的操作步驟->完善和修正程式碼

如果大家問我要整個程式碼,坦白的說:我覺得"授人於魚,不如授於漁"。大家能獲取正確解決問題的思路就夠了,然後記住核心程式碼就可以了。做程式設計師到一個“手中無劍,心中有劍”的境界就夠了。當然新手還是多練練劍,比劃比劃下招式。

 

PS:遊戲DEMO試玩群:198035671  Unity3d技術交流群:308185833  鬥魚遊戲開發直播地址:www.douyutv.com/unity3d

相關文章