自制Unity小游戲TankHero-2D(3)開始玩起來
我在做這樣一個坦克游戲,是仿照(http://game.kid.qq.com/a/20140221/028931.htm)這個游戲制作的。僅為學習Unity之用。圖片大部分是自己畫的,少數是從網上搜來的。您可以到我的github頁面(https://github.com/bitzhuwei/TankHero-2D)上得到工程源碼。
本篇主要記錄金幣、按鈕、坦克工廠、小地圖等小部件,讓整個場景初步成為一個可玩的游戲。
在本篇在制作過程中,修改了前兩篇的很多東西,算是對Unity更加熟悉了。
金幣
玩家擊毀一個敵方坦克,會敵方坦克所在位置會出現1個金幣。金幣可以用來升級玩家坦克的速度、武器等,也可以用來恢復生命。
金幣有3個腳本。
Show Up控制金幣的出現是從透明到全不透明的。


1 public class ShowUp : MonoBehaviour { 2 3 public float showUpSpeed = 1; 4 private SpriteRenderer spriteRenderer; 5 6 void Awake() 7 { 8 this.spriteRenderer = this.GetComponent<SpriteRenderer>(); 9 var color = this.spriteRenderer.color; 10 this.spriteRenderer.color = new Color(color.r, color.g, color.b, 0); 11 } 12 13 // Update is called once per frame 14 void Update () { 15 if (this.spriteRenderer == null) { return; } 16 17 this.spriteRenderer.color = Color.Lerp(this.spriteRenderer.color, Color.white, this.showUpSpeed * Time.deltaTime); 18 19 //Debug.Log(string.Format("A: {0}", this.spriteRenderer.color.a)); 20 if (Mathf.Abs(Color.white.a - this.spriteRenderer.color.a) <= 0.02f) 21 { 22 this.spriteRenderer.color = Color.white; 23 this.spriteRenderer = null; 24 } 25 }
?
Coin Info保存金幣的價值。
注意:腳本中要保留一個Start或一個Update函數,否則在Inspector面板就不會顯示腳本組件前面的勾選框了。
1 public class CoinInfo : MonoBehaviour { 2 3 public int value; 4 5 void Start() 6 { 7 } 8 9 }
?
Picked Coin讓金幣碰到玩家坦克時銷毀自己。
1 public class PickedCoin : MonoBehaviour { 2 3 private bool picked; 4 5 void Awake() 6 { 7 this.picked = false; 8 } 9 10 void Start () { 11 12 } 13 14 void OnTriggerEnter2D(Collider2D other) 15 { 16 if (other.tag != Tags.hero) { return; } 17 18 if (!this.picked) 19 { 20 this.picked = true; 21 MonoBehaviour.Destroy(this.gameObject); 22 } 23 } 24 }
游戲暫停和繼續
用一個按鈕來控制游戲的暫停和繼續。
選擇UI-Button即可添加一個按鈕。
在按鈕的Button組件中,添加一個btnPause.cs腳本,添加一個On Click(),選擇這個btnPause.cs腳本組件,選擇對應的事件函數即可。(下圖是錯的,應該把btnPause.cs組件賦給On Click項。
那么事件函數怎么寫呢?
游戲暫停的原理很簡單,只需?Time.timeScale = 0;?,那么今后所有的?Time.deltaTime?都將是0。因此所有乘以?Time.deltaTime?的地方都不會再有進展。


1 private float originalTimeScale; 2 private UnityEngine.UI.Text buttonText; 3 4 void Awake() 5 { 6 this.originalTimeScale = Time.timeScale; 7 this.buttonText = this.GetComponentInChildren<UnityEngine.UI.Text>(); 8 } 9 10 public void btnPause_Click() 11 { 12 if (Time.timeScale > 0) 13 { 14 Time.timeScale = 0; 15 buttonText.text = "Continue"; 16 } 17 else 18 { 19 Time.timeScale = this.originalTimeScale; 20 buttonText.text = "Pause"; 21 } 22 }
在激烈的游戲過程中,把鼠標挪到屏幕某處點擊按鈕是很費勁的。所以,添加一個按下Space鍵就可以暫停或繼續游戲的功能很有必要。只需給剛剛的btnPause.cs腳本添加如下代碼。
1 void Update () { 2 if (Input.GetKeyDown(KeyCode.Space)) 3 { 4 btnPause_Click(); 5 } 6 }
坦克工廠
現在可以在界面上方三個點產生敵方坦克。后續我將此處改造為關卡控制器。此處暫時沒什么可說的。
?
小地圖
整個游戲地圖有的大,一屏顯示不完,所以給個能顯示全地圖的小地圖是很好的。
制作小地圖的原理是再添加一個攝像機smallMap,確保其Depth大于主攝像機。這樣小地圖就會顯示在主場景上層。調整smallMap的Viewport屬性,使其只在界面的某個角落顯示。這里我讓小地圖顯示在場景左下角,其長寬均為場景的五分之一即0.2。
注意,Viewport的X、Y、Width、Height屬性都是0~1的,表示的是百分比。
注意,上圖左上方紅色圍起來的白色框,其長寬比=下方Game視圖的長寬比,后面我就是根據這個調整小地圖的長寬的。
完成后,在Game視圖里是這樣的,小地圖并不是正方形。這不好。
不過這個問題我用腳本解決了,實際上是調整了攝像機的Viewport的長寬屬性,使之調整到相同的長度。
腳本如下。思路是,當場景的width大于height時,要縮小小地圖的width;當場景的width小于height時,要縮小小地圖的height。


1 public class AdjustViewPort : MonoBehaviour { 2 3 Camera cameraComponent; 4 private float screenWidth; 5 private float screenHeight; 6 private Rect originalCameraRect; 7 8 void Awake() 9 { 10 this.cameraComponent = this.GetComponent<Camera>(); 11 this.originalCameraRect = this.cameraComponent.rect; 12 } 13 14 void Update () { 15 var width = Screen.width; 16 var height = Screen.height; 17 if (width == this.screenWidth && height == this.screenHeight) { return; } 18 19 this.screenWidth = width; 20 this.screenHeight = height; 21 22 if (width > height) 23 { 24 var rect = this.cameraComponent.rect; 25 rect.width = this.originalCameraRect.width * ((float)height / (float)width); 26 this.cameraComponent.rect = rect; 27 } 28 else 29 { 30 var rect = this.cameraComponent.rect; 31 rect.height = this.originalCameraRect.height * ((float)width / (float)height); 32 this.cameraComponent.rect = rect; 33 } 34 } 35 }
?
只顯示小地圖的話,可能會跟場景混淆,所以給小地圖加個紅色的邊框,就區分得明顯了。我搜了很多加邊框的方法,發現都太繁瑣,還要依賴各種包、庫。還是直接畫一個Texture簡單。
為方便起見,就在剛剛的AdjustViewPort腳本中同時繪制邊框好了。
所需的邊框紋理就是一個內部透明四周為紅色的PNG圖片。
(下面的腳本忽略了調整長寬相關的部分。)
1 public class AdjustViewPort : MonoBehaviour { 2 3 Camera cameraComponent; 4 public Texture borderTexture; 5 6 void Awake() 7 { 8 this.cameraComponent = this.GetComponent<Camera>(); 9 } 10 11 void OnGUI() 12 { 13 var rect = this.cameraComponent.rect; 14 float left = 0; 15 float top = Screen.height - Screen.height * rect.height; 16 float width = Screen.width * rect.width; 17 float height = Screen.height * rect.height; 18 19 GUI.DrawTexture(new Rect(left, top, width, height), this.borderTexture, ScaleMode.StretchToFill); 20 } 21 }
總結
本篇添加了一些雖小但用起來很方便的小部件。現在這個TankHero就算是可以玩了。下面我將設計實現關卡,讓這個游戲具有多個關卡,并且可配置。
?
您可以到我的github頁面(https://github.com/bitzhuwei/TankHero-2D)上得到工程源碼。
請多多指教~