How to make a Video Game in Unity 的課程筆記冒窍。
1. 基礎(chǔ)
- Scene 視圖递沪,滾動(dòng)鼠標(biāo)中鍵縮放,opt+左鍵以視圖中心為軸心旋轉(zhuǎn)综液。
- Hierarchy 視圖中的元素
- Inspector 放 components款慨,使對象做不同的事
- Assets 資源,拖放到視圖中谬莹,會在 Hierarchy 中顯示
- 左上角 5 個(gè) icon 對應(yīng) q, w, e, r, t 快捷鍵檩奠,可以移動(dòng)畫幅约素,移動(dòng)對象,旋轉(zhuǎn)對象笆凌,變形對象圣猎,縮放對象
- Game 視圖,按 shift+space 切換全屏與小窗口
- Command+P 運(yùn)行游戲
創(chuàng)建項(xiàng)目
- 創(chuàng)建 cube乞而,Scene 中按 F 會聚焦到所選擇的對象送悔。
- Inspector > Transform 中點(diǎn)右鍵 reset,會把該對象以原始大小重置到視圖中央爪模。
- Game 視圖中以 Camera 的角度觀察欠啤。
- 設(shè)置地面:修改 cube 的 scale,移動(dòng)到 camera 前一點(diǎn)的位置屋灌。改名為 Ground
- 創(chuàng)建 Player:再創(chuàng)建一個(gè) cube洁段,reset,拖到 ground 之上共郭,改名 Player.
- 給 Player 上色:Assets 中新建 Material祠丝,名為 PlayerMat,Albede 改為紅色除嘹,拖到 Player 上写半。
- 使 Player 有物理特性:Add Component > Physics > Rigidbody。
- 是什么使對象有不同的特性呢尉咕?答案是 components叠蝇。Transform 每個(gè)對象都有的屬性;Mesh Renderer 渲染對象到視圖年缎;Box Collider 碰撞屬性悔捶。每個(gè)物理對象都需要 Box Collider 和 Rigidbody。Cube(Mesh Filter) 選擇不同的形狀单芜。
- 如果改成球體蜕该,box collider 右鍵 remove component,然后 add component > Sphere Collider缓溅。
- 改變背景色:選擇 mainc camera > Inspector > Camera > Clear Flag > Solid Color, background 選擇淺灰色
- 保存 scene蛇损,在 unity 中赁温,scene 就是 level坛怪。
2. 編程
選擇 Player,add component > script股囊,輸入 PlayerMovement
可以拖放 script 到某個(gè)對象上袜匿,使它產(chǎn)生作用。
-
Unity 5.5.2 會自動(dòng)產(chǎn)生這兩行稚疹,刪除掉:
using System.Collections; using System.Collections.Generic;
-
Start () 在開始執(zhí)行居灯,Update () 每一幀執(zhí)行祭务。我們要訪問 rigidbody
public Rigidbody rb;
然后在 inspector 面板中,把 Rigidbody 這個(gè) component 拖到 rb 變量中怪嫌,以便在代碼中引用义锥。
-
加驅(qū)動(dòng)力給 Player,為了避免計(jì)算快的計(jì)算機(jī)比慢的運(yùn)動(dòng)速度不一致岩灭,將參數(shù)乘以 Time.deltaTime
rb.AddForce(0, 0, 2000 * Time.deltaTime)
放在 FixedUpdate() 中拌倍,當(dāng)對象和別的物體碰撞的時(shí)候會更順滑一些。
3. 移動(dòng)
不讓 Player 滾動(dòng)噪径,只需要滑動(dòng)柱恤,可以勾選 Constraints > Freeze Rotation > x,不過我們希望碰撞的時(shí)候可以滾動(dòng)找爱,所以不要這樣設(shè)置梗顺。
導(dǎo)致 Player 滾動(dòng)的是摩擦力,Assets > 右鍵 > Create > Physic Material车摄,命名為 Slippery寺谤,Inspector 中 Dynamic Friction 和 Static Friction 都設(shè)為 0,拖放到 Ground 上吮播。
-
要在 inspector 中修改速度矗漾,創(chuàng)建一個(gè)速度變量:
public float forwardForce = 2000f;
修改
rb.AddForce (0, 0, forwardForce * Time.deltaTime);
-
判斷用戶輸入,左右移動(dòng) 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. 攝像頭
Camera 跟隨 Player: 可以把 Main Camera 拖到 Player 下薄料,使它成為 Player 的子對象敞贡,不過當(dāng) Player 碰撞滾動(dòng)的時(shí)候 Camera 也跟著滾,太詭異摄职,所以我們將用代碼來實(shí)現(xiàn)誊役。
-
給 Main Camera 添加 script —— FollowPlayer
using UnityEngine; public class FollowPlayer : MonoBehaviour { //只需要用到 transform,所以不需要引用到 GameObject public Transform player; //使得在 Inspector 中可以設(shè)置三個(gè)參數(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 分別計(jì)算迫悠,兩個(gè)屬性都有這 3 個(gè)參數(shù)鹏漆,所以可以直接相加 transform.position = player.position + offset; } }
這樣當(dāng)碰撞的時(shí)候 Player 在滾動(dòng),Camera 仍然在它后方穩(wěn)定觀察创泄。
5. 碰撞
-
為 Player 創(chuàng)建 PlayerCollision.cs
using UnityEngine; public class PlayerCollision : MonoBehaviour { //引用另外一個(gè) script public PlayerMovement movement; //碰撞的時(shí)候會自動(dòng)呼叫這個(gè)方法 void OnCollisionEnter (Collision collisonInfo) { if (collisonInfo.collider.tag == "Obstacle") { //發(fā)生碰撞時(shí)艺玲,使驅(qū)動(dòng) Player 滑動(dòng)的 script 失效 movement.enabled = false } } }
在 inspector 中把 PlayerMovement 拖到 PlayerCollision 的接口中。
6. 游戲設(shè)置
把 hierachy 中的 Obstacle 拖到 Assets 面板中鞠抑,這個(gè)對象就變成一個(gè) prefab饭聚,這個(gè)預(yù)制件可以在游戲中重復(fù)使用,拖放多個(gè) prefab 到 Scene 中搁拙,修改 prefab 會使所有 prefab 都發(fā)生改變秒梳,也可以單獨(dú)修改某個(gè) Obstacle法绵,修改某個(gè)對象后點(diǎn)擊 inspector 中的 apply 會使當(dāng)前修改應(yīng)用到所有 prefab 對象。
通常我們會讓 obstacle 向 player 移動(dòng)酪碘,造成前進(jìn)的視覺朋譬,但是這個(gè) demo 中我們讓 player 移動(dòng)。
延長 Ground:Inspector 中設(shè)置 Transform.Position.z: 4980, Scale.z: 10000
Scene 右上角兴垦,點(diǎn)擊 y 軸此熬,這樣視角就改成從頂部往下看,點(diǎn)擊中心的方塊滑进,會取消掉透視效果犀忱,這樣我們可以在 2d 效果中設(shè)置游戲障礙物。
Inspector > Layers > Edit Layers, 添加 Environment Layer扶关;選擇 Ground阴汇,Inspector > Layer > Environment;下拉 Layers节槐,點(diǎn)擊 Environment 右側(cè)鎖頭鎖住搀庶。這樣我們再也不能選中視圖中的 Ground 了。這樣便于設(shè)置 ground 上的障礙物铜异。
選擇障礙物哥倔,如果點(diǎn)擊綠色方框,那么只會沿著 z 和 x 軸移動(dòng)揍庄。
設(shè)置吸附:菜單 Edit > Snap Settings...咆蒿,設(shè)置 2, 2, 2, 按住 Command 再拖動(dòng)的障礙物的時(shí)候,它會 2 個(gè)單位移動(dòng)每一步蚂子。
復(fù)制多個(gè)障礙物沃测,布滿 ground。
-
Player 響應(yīng)方向改變有點(diǎn)遲鈍食茎,rb.AddForce 方法的幾個(gè)參數(shù)重蒂破,首先給 x 加力度,然后是 y别渔, 然后是 z附迷,最后是 Force Mode,F(xiàn)orceMode 默認(rèn)是 forced哎媚,它根據(jù)重量添加一個(gè)持續(xù)的壓力給 rigidbody喇伯,我們想要的是當(dāng)速率改變時(shí),完全忽略這個(gè)物體的重量抄伍。所以添加 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); }
看起來響應(yīng)比較及時(shí)了,為了讓運(yùn)動(dòng)看起來更有逼真截珍,設(shè)置 drag 屬性攀甚,drag 意味著空氣阻力,drag 越大岗喉,我們的 Player 越容易被空氣攔住停止秋度,此外我們還要增加推力,以便保持運(yùn)動(dòng)速度钱床。drag:1, forwardForce: 4000
障礙物看起來好像突然冒出來一樣荚斯,我們要讓它們漸漸出現(xiàn)。菜單 window > lighting > 勾選 Fog > Fog Color 吸附背景色 > Density: 0.02
有時(shí)候 Player 會穿越障礙物查牌,為了增加更精確的碰撞感知事期,Player 和 Obstacle 的 Rigidbody > Collision Detection 都設(shè)置為 continuous
Edit > Project Settings > Time > Fixed Timestep : 0.02,這樣 unity 會更頻繁地檢查物理狀況纸颜,減少錯(cuò)過的碰撞兽泣。
提高 Player 的推力 8000
7. UI
Hierachy 面板,右鍵 > UI > Text
Scene 點(diǎn)擊頂部 2d胁孙,點(diǎn)擊 cavas唠倦,點(diǎn)擊 scene,敲F涮较,聚焦到 UI 視圖
設(shè)置 text 位置稠鼻,字體大小,外框大小狂票,按 option 鍵從中間縮放候齿,Horizontal Overflow 設(shè)為 overflow 意味著如果文字超出也能顯示。
選擇 canvas闺属,設(shè)置 UI Scale Mode: Scale With Screen Size毛肋, Match Height
下載 roboto 字體(select后點(diǎn)小窗點(diǎn)download)。解壓屋剑。拖到 assets 中润匙。選擇 text,選擇字體唉匾。
-
給 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"); } }
選擇 canvas,Inspector 勾選 Pixel Perfet巍膘,這樣字體會渲染得更銳利厂财。
8. 游戲結(jié)束
創(chuàng)建 GameObject,reset transform峡懈。重命名為 GameManager璃饱。給它添加 script: GameManager,它將負(fù)責(zé)管理游戲狀態(tài)肪康。比如更新游戲分?jǐn)?shù)荚恶,切換菜單撩穿,切換游戲?qū)蛹壍鹊取N覀円龅氖鞘『笾刂糜螒颉?/p>
Player 碰撞的時(shí)候要呼叫 GameManager谒撼,如果直接引用它食寡,有時(shí)我們需要讓 Player 死掉,這時(shí) 它所綁定的 GameManager 也就不存在了廓潜。因此我們不用引用變量的方法抵皱。
把 Player 拖到 Assets 面板,變成 Prefab辩蛋。 Main Camera 和 text 所引用的 Player 都要重新設(shè)置呻畸。
-
當(dāng)需要的時(shí)候我們搜索這個(gè) GameManager。GetComponent 和 FindObjectOfType 這兩個(gè)方法都類似悼院。
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í)行伤为,第一個(gè)參數(shù)是呼叫的方法名,第二個(gè)參數(shù)是延遲的秒數(shù) Invoke ("Restart", restartDelay); } } void Restart(){ //重載當(dāng)前 scene SceneManager.LoadScene (SceneManager.GetActiveScene ().name); } }
-
修改 PlayerCollison.cs
//movement.enabled = false; GetComponent<PlayerMovement>().enabled = false; //找到 GameManager FindObjectOfType<GameManager> ().EndGame();
-
當(dāng) Player 掉下 Gound 時(shí)呼叫 EndGame樱蛤。修改 PlayerMovement.cs
if (rb.position.y < -1f){ FindObjectOfType<GameManager> ().EndGame (); }
修正 lighting:Window > Lighting钮呀,去掉底部 auto 選項(xiàng)。auto 表示 unity 自動(dòng)檢查光線昨凡,當(dāng)重載 scene 的時(shí)候爽醋,unity 時(shí)間去計(jì)算光線,它會使畫面非常亮便脊,所以要去掉蚂四。點(diǎn) build。
如果多于一個(gè) scene哪痰,我們還要 File > Build settings遂赠,把 Scene 拖進(jìn)去。build and run