Unity3D游戲開發初探—4.開發一個“瘋狂擊箱子”游戲


一、預備知識—對象的”生“與”死“

  (1)如何在游戲腳本程序中創建對象而不是一開始就創建好對象?->使用GameObject的靜態方法:CreatePrimitive()

  以上一篇的博文中的“指哪打哪”例子為基礎,在AddForce腳本寫入以下代碼:

 1     void Update()
 2     {
 3         // Demo3:點擊鼠標左鍵自動創建Cube對象
 4         if (Input.GetMouseButtonDown(0))
 5         {
 6             CreateCube();
 7         }
 8     }
 9 
10     void CreateCube()
11     {
12         GameObject goCube = GameObject.CreatePrimitive(PrimitiveType.Cube);
13         goCube.transform.position = new Vector3(0, 0, 0);
14         goCube.AddComponent<Rigidbody>();
15     }
View Code

  其中在CreateCube方法中,使用GameObject.CreatePrimitive方法來創建Cube類型的游戲對象實例,設置了它出現的坐標並為它增加剛體組件。這里可以看下AddComponent方法,它的參數是一個泛型,也就是說我們在屬性面板中看到的那些組件,例如剛體、音頻源甚至腳本等組件對象都可以通過AddComponet方法來動態地添加。現在來看看在游戲中點擊鼠標左鍵創建Cube對象的效果:

  (2)細心的讀者會發現,當我們創建了無數個Cube對象之后,計算機的內存占用率會逐步上升。機智的你肯定會想到,適時銷毀創建的游戲對象,釋放內存資源。不要擔心,Unity3D為我們提供了一個非常方便的方法:Destroy()。這個函數提供了兩個重載:第一個你可以直接傳遞一個游戲對象的ID(比如我們在上個例子中創建了一個Plane,它的ID也為Plane);第二個你可以傳遞兩個參數,一個是剛剛提到的游戲對象的ID,另一個是延遲銷毀的秒數(也就是說可以在規定的秒數之后再從屏幕中消失,從內存中銷毀);

  下面我們重新修改一下剛剛的AddForce腳本為如下代碼:

 1     void Update()
 2     {
 3 
 4         // Demo4:點擊鼠標左鍵自動銷毀Plane對象
 5         if(Input.GetMouseButtonDown(0))
 6         {
 7             DestroyGameObject("Plane");
 8         }
 9     }
10 
11     void DestroyGameObject(string objectName)
12     {
13         GameObject goCube = GameObject.Find(objectName);
14         // 延時2秒之后才銷毀該對象
15         Destroy(goCube, 2);
16     }
View Code

  這里我們將銷毀游戲對象的代碼封裝成了一個方法:DestroyGameObject(),它首先通過GameObject.Find方法找到指定ID的游戲對象,然后調用銷毀游戲對象的方法Destroy將其銷毀掉,這里使用了第二個重載,為其傳遞了一個2秒的延遲時間。也就是說,當我們點擊鼠標左鍵后2秒,Plane對象才會被銷毀,我們的Sphere球體對象便會跌落深淵!現在我們來看看效果如何:

  在預覽效果的同時,你可以觀察左側Hierarchy中的對象列表,Plane在什么時刻消失了?

  好了,預備知識到此結束,現在我們真正開始CrazySphere(簡稱:CS,聽起來高大上吧,么么嗒!)—“瘋狂擊箱子”游戲的開發之旅!

二、瘋狂擊箱子—CrazySphere的實現之路

  既然我們的“CS”是擊箱子,木有箱子怎么能行呢!現在,我們就來創建一些箱子,作為我們擊打的對象。

  首先,考慮到要初始化的箱子足足有16個,我們需要在程序中來創建這些箱子,並將它們放在Plane中,組成箱子牆,讓我們的小球來擊打。

  (1)在Hierarchy中Create以下對象:一個Direction Light,一個Plane;將Plane的Position設置為(0,1,-6),這樣看起來清楚一點;

  (2)准備工作:

  ①在Assets中Create以下文件夾(Folder):一個Images文件夾用來存放貼圖文件,一個Musics文件夾用來存放背景音樂和音效MP3,一個Scripts文件夾用來存放C#腳本文件,見下圖所示:

  ②往Images里邊導入一些貼圖,我這里在網上找了幾張憤怒的小鳥的圖片,用來給Plane、Sphere以及Cube對象做渲染材質貼圖,這樣游戲對象看起來好看一點。(具體的文件請下載附件中的源碼,找到Assets/Images/)

  ③往Musics里邊導入一首背景音樂和一首音效文件,背景音樂作為游戲背景音樂默認且循環播放,音效音樂作為小球沖擊箱子的音效在小球發出時播放。這里背景音樂我選擇的是薩克斯經典—回家,是不是很文藝?音效呢,我就上網隨便找了個炮彈發射的音效。(具體的文件請下載附件中的源碼,找到Assets/Musics/)

  然后,選中Hierarchy中的Main Camera,選擇主菜單欄中的Component->Audio->Audio Source,在屬性中的Audio Source塊中選擇導入的背景音樂(這里是GoHome-Sax),並勾選Play On Awake(是否默認播放)以及Loop(是否循環播放)復選框,我們在游戲一開始時就會播放GoHome-Sax.mp3文件。

  最后,按照上面的步湊為Plane增加Audio Source,將其選擇為Bomb作為初始化音效。

  ④在Scripts中Create兩個C# Script,一個命名為InitScene,另一個命名為AutoDestroy。InitScene腳本用於初始化游戲場景,也就是4*4的箱子矩陣。而AutoDestroy腳本則用於銷毀超出主攝像機可視范圍的游戲對象,也就是當我們的小球或被擊中的箱子超出Plane的地面范圍或跌落后就將其自動銷毀。

  (3)首先來編寫AutoDestroy腳本,利用我們在 預備知識 里邊學到的自動銷毀對象的方法。這個AutoDestroy腳本是需要附加到需要自動銷毀的游戲對象上才會有意義,所以后邊會在初始化場景的主腳本中為自動創建的對象附加此腳本(利用AddComponent提供的泛型方法)。

 1 using UnityEngine;
 2 using System.Collections;
 3 
 4 public class AutoDestroy : MonoBehaviour
 5 {
 6 
 7     // Use this for initialization
 8     void Start()
 9     {
10 
11     }
12 
13     // Update is called once per frame
14     void Update()
15     {
16 
17     }
18 
19     // 當離開攝像頭可視范圍時觸發的事件
20     void OnBecameInvisible()
21     {
22         // 銷毀當前游戲對象
23         Destroy(this.gameObject);
24     }
25 }
View Code

PS:OnBecameInvisible()方法是Unity3D中自帶的方法,它在具體的游戲對象在游戲屏幕上不可見時觸發。你可以理解它就類似於ASP.NET WebForm中Global文件中的Application_End()事件。這里,我們在游戲對象不可見時,銷毀具體的游戲對象。注意,這里銷毀的方法參數是this.GameObject而不是this!

  (4)現在我們來編寫InitScene腳本,這個是重點!編寫完成后,把此腳本附加到Main Camera對象中!

 1 using UnityEngine;
 2 using System.Collections;
 3 
 4 public class InitScene : MonoBehaviour
 5 {
 6     private GameObject goPlane;
 7 
 8     // Use this for initialization
 9     void Start()
10     {
11         // 獲取Plane對象
12         goPlane = GameObject.Find("Plane");
13         // 初始化4*4個箱子群
14         CreateCubes();
15     }
16 
17     void CreateCubes()
18     {
19         // 創建4*4個Cube立方體作為箱子
20         for (int i = 0; i < 4; i++)
21         {
22             for (int j = 0; j < 4; j++)
23             {
24                 GameObject goCube = GameObject.CreatePrimitive(PrimitiveType.Cube);
25                 goCube.transform.position = new Vector3(i - 1, j, -1);
26                 // 增加剛體組件使其具有重力
27                 goCube.AddComponent<Rigidbody>();
28                 // 增加腳本使對象自動銷毀
29                 goCube.AddComponent<AutoDestroy>();
30                 // 增加渲染貼圖
31                 goCube.renderer.material.mainTexture =
32                     Resources.LoadAssetAtPath("Assets/Images/CubeImage.jpg", typeof(Texture)) as Texture;
33             }
34         }
35     }
36 
37     // Update is called once per frame
38     void Update()
39     {
40         // 控制Sphere朝着鼠標指定的坐標發起沖擊
41         if (Input.GetMouseButtonDown(0))
42         {
43             // 創建要發出的小球Sphere
44             GameObject goBullet = GameObject.CreatePrimitive(PrimitiveType.Sphere);
45             goBullet.transform.position = Camera.main.transform.position;
46             goBullet.AddComponent<Rigidbody>();
47             goBullet.AddComponent<AutoDestroy>();
48             goBullet.renderer.material.mainTexture =
49                 Resources.LoadAssetAtPath("Assets/Images/AngryBird.jpg", typeof(Texture)) as Texture;
50 
51             // 獲取目標位置的世界坐標
52             Vector3 targetPos = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x,
53                 Input.mousePosition.y, 3));
54             Vector3 dirPos = targetPos - Camera.main.transform.position;
55 
56             // 進擊吧!瘋狂的小球!
57             goBullet.rigidbody.AddForce(dirPos * 10, ForceMode.Impulse);
58 
59             // 播放爆炸音效
60             goPlane.GetComponent<AudioSource>().Play();
61         }
62     }
63 
64 }
View Code

  現在我們一一來分析這段腳本代碼:

  ①CreateCubes()方法定義了初始化4*4個箱子的實現過程,每循環一次通過CreatePrimitive創建Cube類型的立方體,然后為每個立方體設置position坐標、增加剛體組件、增加腳本使其能夠自動銷毀以及為其渲染貼圖。

  ②在Update()方法中控制小球朝着鼠標指定的坐標發起沖擊:當用戶點擊鼠標左鍵時即刻創建一個Sphere小球,仍然是設置坐標、增加剛體組件、渲染貼圖、增加腳本使其能夠自動銷毀。這里需要注意的是,小球的坐標應該為攝像頭的位置,因為小球是從攝像頭飛出去的。然后,通過屏幕坐標向世界坐標的轉換獲取目標向量,再通過目標所在向量-攝像頭所在向量=方向向量(這里涉及到向量減法,不明白的讀者可以看看本文第二篇3D模型基礎,或者去復習下高中向量減法的幾何意義)。最后,為小球添加一個往鼠標點擊的方向的多大的力,它就會往那個方向去走(這里是“飛“)。為了突出效果,這里還為小球添加了音效效果,在發出時播放。

  (5)到這里,一個基本的CrazySphere就可以實現了,現在我們來看下效果:可以讓小球按照我們制定的坐標發射,發射時還會有炮彈的音效,而且背景音樂一直在循環播放着,一個demo就差不多完成了,是不是很快!

  

  (6)但是大家是否覺得我們的游戲背景太單調了,沒關系,Unity3D為我們提供了Skyboxes-天空盒子,讓我們的背景一秒變為燦爛的藍天!(有關天空盒子的詳細內容請參閱參考文獻中關於天空盒子的介紹,這里不再闡述)這里我們向場景中添加一個Sunny的天空盒子:

  ①在Assets處單擊鼠標右鍵,選擇Import Package->Skyboxes,在彈出的選擇框中選擇Sunny1的mat、與Sunny1有關的tif資源。這里注意不要將全部的天空盒子都導進來,那樣文件會很大!

  ②點擊主菜單欄Edit->Render Settings,在右側的屬性欄中找到Skybox Material:

  單機右側的選擇按鈕,在彈出的選擇框中即可看到我們剛剛導入的Sunny1這個天空盒子,雙機選中它,這樣我們就讓游戲背景一秒變為陽光燦爛的藍天,是不是心曠神怡啊!

  (6)現在,我們再來看看游戲效果:是不是變為藍天啦?這樣,我們的CrazySphere v1.0就開發好了!

  

三、總結

  通過幾天的Unity3D初探學習,我們學習了Unity3D的基本知識、3D模型基礎、物理引擎基礎,並綜合這些知識做了一個小游戲:CrazySphere-瘋狂擊箱子的游戲,還實現了背景音樂、音效效果的播放,加入天空盒子讓游戲背景好看。當然,本系列作為初探,不可能學的很深入,但至少我們可以入門,可以初步領略到Unity3D的強大魅力以及我們.NET程序員的學習優勢。

  不知不覺之間,已經寫了四篇關於Unity3D的學習筆記了,同時這也是我的第一個系列的博文,對我的博客生涯具有重要的意義,再次感謝給我鼓勵的園友們,讓我作為一個新人倍感榮幸。另外,本文是基於傳智播客的Unity3D的兩次公開課為基礎,整理而成的,衷心感謝傳智播客以及楊中科的分享,還有老楊的鼓勵。馬上就要開學了,又要回成都了,苦逼的研究生生涯還得繼續,好想早點畢業啊!被學校派到外邊實習,老師(實驗室指導老師,非我的導師,我的導師還是蠻不錯的)也不准時發工資,每天還干的累死累活的。但是,還是想在此祝願各位園友碼年吉祥,2014越碼越健康

  明天就是我外婆70歲的生日了,在此也祝願她老人家生日快樂,身體健康!

  本文最后會附上本次小游戲案例的Demo文件供下載,里面有本次用到的所有素材。另外,該Demo中還使用了GUI自定義了鼠標顯示,將鼠標顯示替換為一張瞄准星的貼圖,如下圖所示:

參考文獻與資料

  (1)傳智播客Unity3D公開課:http://net.itcast.cn/subject/Unity3D/index.html

  (2)XieXuan2007,《Unity3D天空盒》:http://blog.csdn.net/xiexuan2007/article/details/18401075

  (3)丁小未,《Unity3D開發類似保齡球游戲》:http://blog.csdn.net/dingxiaowei2013/article/details/9734935

附件 

  Demo文件下載:https://github.com/EdisonChou/CrazySphere

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM