How to make a Video Game in Unity

How to make a Video Game in Unity 的課程筆記。

1. 基礎(chǔ)

  • Scene 視圖,滾動鼠標(biāo)中鍵縮放,opt+左鍵以視圖中心為軸心旋轉(zhuǎn)。
  • Hierarchy 視圖中的元素
  • Inspector 放 components,使對象做不同的事
  • Assets 資源,拖放到視圖中,會在 Hierarchy 中顯示
  • 左上角 5 個 icon 對應(yīng) q, w, e, r, t 快捷鍵,可以移動畫幅,移動對象,旋轉(zhuǎn)對象,變形對象,縮放對象
  • Game 視圖,按 shift+space 切換全屏與小窗口
  • Command+P 運(yùn)行游戲

創(chuàng)建項(xiàng)目

  1. 創(chuàng)建 cube,Scene 中按 F 會聚焦到所選擇的對象。
  2. Inspector > Transform 中點(diǎn)右鍵 reset,會把該對象以原始大小重置到視圖中央。
  3. Game 視圖中以 Camera 的角度觀察。
  4. 設(shè)置地面:修改 cube 的 scale,移動到 camera 前一點(diǎn)的位置。改名為 Ground
  5. 創(chuàng)建 Player:再創(chuàng)建一個 cube,reset,拖到 ground 之上,改名 Player.
  6. 給 Player 上色:Assets 中新建 Material,名為 PlayerMat,Albede 改為紅色,拖到 Player 上。
  7. 使 Player 有物理特性:Add Component > Physics > Rigidbody。
  8. 是什么使對象有不同的特性呢?答案是 components。Transform 每個對象都有的屬性;Mesh Renderer 渲染對象到視圖;Box Collider 碰撞屬性。每個物理對象都需要 Box Collider 和 Rigidbody。Cube(Mesh Filter) 選擇不同的形狀。
  9. 如果改成球體,box collider 右鍵 remove component,然后 add component > Sphere Collider。
  10. 改變背景色:選擇 mainc camera > Inspector > Camera > Clear Flag > Solid Color, background 選擇淺灰色
  11. 保存 scene,在 unity 中,scene 就是 level。

2. 編程

  1. 選擇 Player,add component > script,輸入 PlayerMovement

  2. 可以拖放 script 到某個對象上,使它產(chǎn)生作用。

  3. Unity 5.5.2 會自動產(chǎn)生這兩行,刪除掉:

     using System.Collections;
     using System.Collections.Generic;
    
  4. Start () 在開始執(zhí)行,Update () 每一幀執(zhí)行。我們要訪問 rigidbody

     public Rigidbody rb;
    

    然后在 inspector 面板中,把 Rigidbody 這個 component 拖到 rb 變量中,以便在代碼中引用。

  5. 加驅(qū)動力給 Player,為了避免計算快的計算機(jī)比慢的運(yùn)動速度不一致,將參數(shù)乘以 Time.deltaTime

     rb.AddForce(0, 0, 2000 * Time.deltaTime)
    
  6. 放在 FixedUpdate() 中,當(dāng)對象和別的物體碰撞的時候會更順滑一些。

3. 移動

  1. 不讓 Player 滾動,只需要滑動,可以勾選 Constraints > Freeze Rotation > x,不過我們希望碰撞的時候可以滾動,所以不要這樣設(shè)置。

  2. 導(dǎo)致 Player 滾動的是摩擦力,Assets > 右鍵 > Create > Physic Material,命名為 Slippery,Inspector 中 Dynamic Friction 和 Static Friction 都設(shè)為 0,拖放到 Ground 上。

  3. 要在 inspector 中修改速度,創(chuàng)建一個速度變量:

     public float forwardForce = 2000f;
    

    修改

     rb.AddForce (0, 0, forwardForce * Time.deltaTime);
    
  4. 判斷用戶輸入,左右移動 Player

     public float sidewaysForce = 500f;
     
     if ( Input.GetKey("d") ) {
             rb.AddForce (sidewaysForce * Time.deltaTime, 0, 0);
         }
         if ( Input.GetKey("a") ) {
             rb.AddForce (-sidewaysForce * Time.deltaTime, 0, 0);
         }   
    

4. 攝像頭

  1. Camera 跟隨 Player: 可以把 Main Camera 拖到 Player 下,使它成為 Player 的子對象,不過當(dāng) Player 碰撞滾動的時候 Camera 也跟著滾,太詭異,所以我們將用代碼來實(shí)現(xiàn)。

  2. 給 Main Camera 添加 script —— FollowPlayer

     using UnityEngine;
     
     public class FollowPlayer : MonoBehaviour {
     
         //只需要用到 transform,所以不需要引用到 GameObject
         public Transform player;
         //使得在 Inspector 中可以設(shè)置三個參數(shù) x = 0, y = 1, z = -5
         //橫向x不變,縱向 y 向上一點(diǎn),沿著 z 軸跑的,放后面一點(diǎn)
         public Vector3 offset;
         
         // Update is called once per frame
         void Update () {
             //使 Camera 在 Player 的后上方
             //不必 x, y, z 分別計算,兩個屬性都有這 3 個參數(shù),所以可以直接相加
             transform.position = player.position + offset;
         }
     }
    
  3. 這樣當(dāng)碰撞的時候 Player 在滾動,Camera 仍然在它后方穩(wěn)定觀察。

5. 碰撞

  1. 為 Player 創(chuàng)建 PlayerCollision.cs

     using UnityEngine;
     
     public class PlayerCollision : MonoBehaviour {
     
         //引用另外一個 script
         public PlayerMovement movement;
         
         //碰撞的時候會自動呼叫這個方法
         void OnCollisionEnter (Collision collisonInfo) {
             if (collisonInfo.collider.tag == "Obstacle") {
                 //發(fā)生碰撞時,使驅(qū)動 Player 滑動的 script 失效
                 movement.enabled = false
             }
         }
     }
    
  2. 在 inspector 中把 PlayerMovement 拖到 PlayerCollision 的接口中。

6. 游戲設(shè)置

  1. 把 hierachy 中的 Obstacle 拖到 Assets 面板中,這個對象就變成一個 prefab,這個預(yù)制件可以在游戲中重復(fù)使用,拖放多個 prefab 到 Scene 中,修改 prefab 會使所有 prefab 都發(fā)生改變,也可以單獨(dú)修改某個 Obstacle,修改某個對象后點(diǎn)擊 inspector 中的 apply 會使當(dāng)前修改應(yīng)用到所有 prefab 對象。

  2. 通常我們會讓 obstacle 向 player 移動,造成前進(jìn)的視覺,但是這個 demo 中我們讓 player 移動。

  3. 延長 Ground:Inspector 中設(shè)置 Transform.Position.z: 4980, Scale.z: 10000

  4. Scene 右上角,點(diǎn)擊 y 軸,這樣視角就改成從頂部往下看,點(diǎn)擊中心的方塊,會取消掉透視效果,這樣我們可以在 2d 效果中設(shè)置游戲障礙物。

  5. Inspector > Layers > Edit Layers, 添加 Environment Layer;選擇 Ground,Inspector > Layer > Environment;下拉 Layers,點(diǎn)擊 Environment 右側(cè)鎖頭鎖住。這樣我們再也不能選中視圖中的 Ground 了。這樣便于設(shè)置 ground 上的障礙物。

  6. 選擇障礙物,如果點(diǎn)擊綠色方框,那么只會沿著 z 和 x 軸移動。

  7. 設(shè)置吸附:菜單 Edit > Snap Settings...,設(shè)置 2, 2, 2, 按住 Command 再拖動的障礙物的時候,它會 2 個單位移動每一步。

  8. 復(fù)制多個障礙物,布滿 ground。

  9. Player 響應(yīng)方向改變有點(diǎn)遲鈍,rb.AddForce 方法的幾個參數(shù)重,首先給 x 加力度,然后是 y, 然后是 z,最后是 Force Mode,F(xiàn)orceMode 默認(rèn)是 forced,它根據(jù)重量添加一個持續(xù)的壓力給 rigidbody,我們想要的是當(dāng)速率改變時,完全忽略這個物體的重量。所以添加 ForceMode.VelocityChange 參數(shù)。

     if ( Input.GetKey("d") ) {
                 rb.AddForce (sidewaysForce * Time.deltaTime, 0, 0, ForceMode.VelocityChange);
             }
             if ( Input.GetKey("a") ) {
                 rb.AddForce (-sidewaysForce * Time.deltaTime, 0, 0, ForceMode.VelocityChange);
             }   
    
  10. 看起來響應(yīng)比較及時了,為了讓運(yùn)動看起來更有逼真,設(shè)置 drag 屬性,drag 意味著空氣阻力,drag 越大,我們的 Player 越容易被空氣攔住停止,此外我們還要增加推力,以便保持運(yùn)動速度。drag:1, forwardForce: 4000

  11. 障礙物看起來好像突然冒出來一樣,我們要讓它們漸漸出現(xiàn)。菜單 window > lighting > 勾選 Fog > Fog Color 吸附背景色 > Density: 0.02

  12. 有時候 Player 會穿越障礙物,為了增加更精確的碰撞感知,Player 和 Obstacle 的 Rigidbody > Collision Detection 都設(shè)置為 continuous

  13. Edit > Project Settings > Time > Fixed Timestep : 0.02,這樣 unity 會更頻繁地檢查物理狀況,減少錯過的碰撞。

  14. 提高 Player 的推力 8000

7. UI

  1. Hierachy 面板,右鍵 > UI > Text

  2. Scene 點(diǎn)擊頂部 2d,點(diǎn)擊 cavas,點(diǎn)擊 scene,敲F,聚焦到 UI 視圖

  3. 設(shè)置 text 位置,字體大小,外框大小,按 option 鍵從中間縮放,Horizontal Overflow 設(shè)為 overflow 意味著如果文字超出也能顯示。

  4. 選擇 canvas,設(shè)置 UI Scale Mode: Scale With Screen Size, Match Height

  5. 下載 roboto 字體(select后點(diǎn)小窗點(diǎn)download)。解壓。拖到 assets 中。選擇 text,選擇字體。

  6. 給 text 添加 script

     using UnityEngine;
     using UnityEngine.UI; //設(shè)置 text 需要引入 UI
     
     public class Score : MonoBehaviour {
         //只需要位置信息,所以不引用 GameObject 
         public Transform player;
         //引用 Label
         public Text scoreText;
     
         // Update is called once per frame
         void Update () {
             //轉(zhuǎn)換浮點(diǎn)數(shù)為 string  并且只保留整數(shù)
             scoreText.text = player.position.z.ToString("0");
         }
     }
    
  7. 選擇 canvas,Inspector 勾選 Pixel Perfet,這樣字體會渲染得更銳利。

8. 游戲結(jié)束

  1. 創(chuàng)建 GameObject,reset transform。重命名為 GameManager。給它添加 script: GameManager,它將負(fù)責(zé)管理游戲狀態(tài)。比如更新游戲分?jǐn)?shù),切換菜單,切換游戲?qū)蛹壍鹊取N覀円龅氖鞘『笾刂糜螒颉?/p>

  2. Player 碰撞的時候要呼叫 GameManager,如果直接引用它,有時我們需要讓 Player 死掉,這時 它所綁定的 GameManager 也就不存在了。因此我們不用引用變量的方法。

  3. 把 Player 拖到 Assets 面板,變成 Prefab。 Main Camera 和 text 所引用的 Player 都要重新設(shè)置。

  4. 當(dāng)需要的時候我們搜索這個 GameManager。GetComponent 和 FindObjectOfType 這兩個方法都類似。

     using UnityEngine;
     using UnityEngine.SceneManagement;
     
     public class GameManager : MonoBehaviour {
         //避免重復(fù)呼叫 EndGame()
         bool gameHasEnded = false;
     
         public float restartDelay = 1f;
     
         public void EndGame(){
             if(gameHasEnded == false){
                 gameHasEnded = true;
                 //延遲執(zhí)行,第一個參數(shù)是呼叫的方法名,第二個參數(shù)是延遲的秒數(shù)
                 Invoke ("Restart", restartDelay);
             }
         }
     
         void Restart(){
             //重載當(dāng)前 scene
             SceneManager.LoadScene (SceneManager.GetActiveScene ().name);
         }
     }
    
  5. 修改 PlayerCollison.cs

     //movement.enabled = false;
                 GetComponent<PlayerMovement>().enabled = false;
                 //找到 GameManager
                 FindObjectOfType<GameManager> ().EndGame();
    
  6. 當(dāng) Player 掉下 Gound 時呼叫 EndGame。修改 PlayerMovement.cs

     if (rb.position.y < -1f){
                 FindObjectOfType<GameManager> ().EndGame ();
             }
    
  7. 修正 lighting:Window > Lighting,去掉底部 auto 選項(xiàng)。auto 表示 unity 自動檢查光線,當(dāng)重載 scene 的時候,unity 時間去計算光線,它會使畫面非常亮,所以要去掉。點(diǎn) build。

  8. 如果多于一個 scene,我們還要 File > Build settings,把 Scene 拖進(jìn)去。build and run

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,702評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,143評論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,553評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,620評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,416評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,940評論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,024評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,170評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,709評論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,597評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,291評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,029評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,407評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,663評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,403評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,746評論 2 370

推薦閱讀更多精彩內(nèi)容