【Unity】專案原始碼——簡單2D空戰遊戲
【摘要】往後的幾篇部落格,sunset會將以前自己學習過程中獨立開發的一些小遊戲或者小demo陸續做成幾篇小教程公佈出來,其中有十分簡單但有趣的小遊戲,也不乏比較深奧的一些demo程式碼。sunset會在疑難點進行比較仔細的註釋。這篇就先來個簡單的空戰遊戲。
首先,先介紹我們所需要的資原始檔:1)戰鬥機;2)背景圖;3)障礙物或者說敵人戰鬥機;4)子彈特效5)合適的音訊檔案(最好是ogg格式,稍後解釋),嗯,差不多就是這樣。
1.建立戰鬥場景
1)將戰機模型拖入Hierachy視窗中,讓其顯示在Scene檢視中,將其transform進行reset,新增MeshCollider元件(能不用最好不同這個元件,對效能消耗大,但是這個遊戲很小,效能問題可忽略所以可以用),然後製作預製物體(prefabs),之後將reset Camera的transform,將Camera的投影方式改為正交方式,然後使其位於戰鬥機上方,使戰鬥機能夠在game檢視中以合適的大小顯示。然後在Hierarchy檢視中建立一個Quad(四方面),將背景圖片直接拖放到Quad上面,改名為BackGround,修改背景圖的合適大小以符合Camera的檢視,再修改背景圖的位置,使其位於戰鬥機下方,然後製成預製物體。
2)之後在背景圖的四個方向邊緣製作幾個Cube,改名為Boundary(1,2,3,4)。修改合適大小,主要用於判定子彈或者敵人沒有受到碰撞的時候,撞擊到邊界就進行淘汰(destroy)。
3)使用光照,建立三個Direcitonal Light,分別為:主光照,輔助光照,邊緣光照。主光照用與整體的照明效果,輔助光照用於對主光照進行補充,邊緣光照用於照明邊緣,使邊緣更加明顯。
2.指令碼程式碼
1.首先是戰鬥機的移動程式碼:
[System.Serializable]
public class Bullets
{
public GameObject SimpleFireBullet;
}
[System.Serializable]
public class Boundary
{
public float yMin, yMax, xMin, xMax;
}
public class PlayerController : MonoBehaviour
{
private Rigidbody rigidbody;
public Boundary boundary;
public Bullets bullets;
private float NextFire;
public Transform SpawnPoint;
public float Speed;
public float RateTime;
public float Tilt;
public GameObject PlayerExplosion;
void Awake()
{
rigidbody = this.GetComponent<Rigidbody>();
}
void Update()
{
if(Input.GetKey(KeyCode.J) && (Time.time > NextFire))
{
NextFire = Time.time + RateTime;
GameObject CloneBullet = Instantiate(bullets.SimpleFireBullet, SpawnPoint.position, SpawnPoint.rotation) as GameObject;
}
if(GameController.LifeCount <= 0)
{
GameController.GameOver = true;
}
}
void FixedUpdate()
{
float H = Input.GetAxis("Horizontal");
float V = Input.GetAxis("Vertical");
Vector3 move = new Vector3(H, V , 0);
rigidbody.velocity = move * Speed;
rigidbody.position = new Vector3(Mathf.Clamp(rigidbody.position.x, boundary.xMin, boundary.xMax), Mathf.Clamp(rigidbody.position.y, boundary.yMin, boundary.yMax), 0.0f);
rigidbody.rotation = Quaternion.Euler(rigidbody.rotation.x,180.0f + -1 * rigidbody.velocity.x * Tilt, rigidbody.rotation.y);
}
void OnTriggerEnter(Collider _collider)
{
if(_collider.gameObject.tag == "Enemy")
{
Destroy(_collider.gameObject);
Destroy(this.gameObject);
GameObject CloneExplosion = Instantiate(PlayerExplosion, this.transform.position, Quaternion.identity) as GameObject;
if(CloneExplosion)
{
Destroy(CloneExplosion, 5);
}
GameController.LifeCount -= 1;
GameController.Dead = true;
}
}
}
簡單解釋一下指令碼,就是通過水平軸和垂直軸的量性變化修改剛體的向量(velocity )來進行移動,這裡使用Mathf.clamp()函式來限制移動的最大邊緣距離和最小邊緣距離,有關這個函式的使用方法可以在UnityAPI文件中進行查詢。然後希望在左移或者右移的時候戰機有一定的傾斜,所以使用Quaternion.Euler函式通過一個Parameter:Tilt來調整左右移動時的傾斜角度。具體程式碼如上。
然後設定按鍵用於發射導彈並限定每秒導彈的可發射量(設定RateTime為0.25時,每秒可發射4次導彈)其他的OnTriggerEnter(Collider _collider)函式是用於檢測機體是否碰撞敵人或者障礙物以及碰撞一定次數後遊戲結束。具體使用方法查詢API。
2.子彈的移動程式碼:
using UnityEngine;
using System.Collections;
public class BulletsMove : MonoBehaviour
{
private Rigidbody rigidbody;
public float BulletSpeed;
public GameObject BulletExplosion;
void Awake()
{
rigidbody = this.GetComponent<Rigidbody>();
}
void FixedUpdate ()
{
if(this)
{
rigidbody.velocity = new Vector3(0.0f, 1, 0.0f) * BulletSpeed;
}
}
void OnTriggerEnter(Collider _collider)
{
if(_collider.gameObject.tag == "Enemy")
{
GameObject CloneExplosion = Instantiate(BulletExplosion, _collider.gameObject.transform.position, Quaternion.identity) as GameObject;
if(CloneExplosion)
{
Destroy(CloneExplosion, 3);
}
Destroy(this.gameObject);
Destroy(_collider.gameObject);
GameController.Score += 10;
}
}
}
比起戰機,子彈移動程式碼較為簡單,同樣使用剛體,程式碼簡單,不一一贅述。OnTriggerEnter(Collider _collider)用於子彈碰撞敵人後,消滅敵人,消滅自己(注意:destroy是在該幀的結束時進行判定的,所以無需在乎程式碼先後問題。)
3.邊界的淘汰判定程式碼:
using UnityEngine;
using System.Collections;
public class BoundaryTrigger : MonoBehaviour
{
void OnTriggerEnter(Collider _collider)
{
Destroy(_collider.gameObject);
}
}
不解釋。。。
4.創造敵人以及實現無限迴圈的程式碼:
using UnityEngine;
using System.Collections;
[System.Serializable]
public class Ship
{
public GameObject Ship1;
public Transform SpawnShip;
}
public class GameController : MonoBehaviour
{
public Ship _ship;
public GameObject AST;
public Vector3 SpawnTransform;
public int WaveCount;
public float StartWaitTime;
public float WaveWaitTime;
public float SpawnWaitTime;
public static bool GameOver = false;
public static bool Dead = false;
public static int LifeCount = 5;
public static int Score;
private AudioSource _audio;
void Awake()
{
_audio = this.GetComponent<AudioSource>();
}
void Start()
{
Time.timeScale = 1;
StartCoroutine(SpawnWave());
}
void Update()
{
if(GameOver)
{
_audio.Stop();
}
if(Dead)
{
//new WaitForSeconds(2.0f);
GameObject CloneShip1 = Instantiate(_ship.Ship1, _ship.SpawnShip.position, _ship.SpawnShip.rotation) as GameObject;
Time.timeScale = 1;
Dead = false;
}
if(Time.timeScale == 0)
{
//_audio.Pause();
}
else if(Time.timeScale == 1)
{
//_audio.Play();
}
}
IEnumerator SpawnWave()
{
yield return new WaitForSeconds(StartWaitTime);
while(true)
{
for(int i = 0; i < WaveCount; i++)
{
Vector3 SpawnPosition = new Vector3(Random.Range(-SpawnTransform.x, SpawnTransform.x), SpawnTransform.y, SpawnTransform.z);
GameObject CloneAST = Instantiate(AST, SpawnPosition, Quaternion.identity) as GameObject;
yield return new WaitForSeconds(SpawnWaitTime);
}
yield return new WaitForSeconds(WaveWaitTime);
}
}
}
其實這個程式碼只能作為一種參考,畢竟真實去製作一款這樣的遊戲時,敵人的數量和種類以及出現方式,攻擊方式都是互不相同的。
這裡主要學習一下這種通過Start()函式運用協程來無限迴圈創造敵人的思路與實現方式就好。
5.最後是建立UI面板顯示分數,存活次數等等資訊,看個人興趣與能力了,美工好的可以做的十分華麗,普通的程式設計師只要能用就行了啦。然後新增音訊檔案,將音訊檔案拖放到子彈的預製物體上,勾選PlayOnAwake即可,然後新增主背景音效到GameController指令碼所附加的空物體上就可,設定Loop。