1. 案例簡述
這個案例實現一個簡單的坦克對戰游戲,兩個玩家在一個地圖上PK。
2. 控制坦克移動
與案例一中小球的移動方式不同,坦克在橫向上不能是平移,因此橫向按鍵控制的應該是坦克旋轉。
public float speed = 5;//前進速度
public float angularSpeed = 5;//旋轉速度
private Rigidbody rd;
void Start () {
rd = this.GetComponent<Rigidbody> ();
}
void FixedUpdate(){
float v = Input.GetAxis ("VerticalPlayer" + number);//自定義虛擬軸
rd.velocity = transform.forward * v * speed;//根據情況需要在剛體組件Constraints凍結相應position或rotation
float h = Input.GetAxis ("HorizontalPlayer" + number);
rd.angularVelocity = transform.up * h * angularSpeed;
}
(1)與Update()不同,Update()方法是游戲每渲染一幀調用一次,調用的頻率會受機器影響,而FixedUpdate()是每隔一定時間間隔調用一次,調用的頻率不受機器影響。因此,為了得到更逼真的物理效果,在模擬物理運動時,一般選擇在FixedUpdate()中。
(2)由於游戲中有兩個玩家,asdw和方向鍵需要控制兩個不同角色,因此需要自定義虛擬軸,位置是:Edit->Project Setting->Input。
(3)根據實際情況,需要在剛體組件中的Constraints進行相應的Freeze操作。
3. 控制子彈發射
public class TankAttack : MonoBehaviour {
public GameObject shellPrefab;//子彈的預設
public KeyCode fireKey = KeyCode.Space;//發射子彈的按鍵
public float shellSpeed = 15;//子彈射出速度
private Transform firePosition;//發射子彈的位置
void Start () {
firePosition = transform.Find ("FirePosition");
}
void Update () {
if (Input.GetKeyDown(fireKey)) {
GameObject go = GameObject.Instantiate (shellPrefab, firePosition.position, firePosition.rotation) as GameObject;//生成子彈
go.GetComponent<Rigidbody> ().velocity = go.transform.forward * shellSpeed;//發射子彈
}
}
}
生成子彈的位置是坦克炮筒處,因此在該處新建一個空對象,調整其旋轉角度,這個對象的transform即可作為生成子彈的transform。
public class Shell : MonoBehaviour {
public GameObject shellExplosionPrefab;
...
void OnCollisionEnter(Collision collision){
GameObject.Instantiate (shellExplosionPrefab, transform.position, transform.rotation);
GameObject.Destroy (this.gameObject);//若傳入參數為this,則值銷毀當前腳本而非游戲對象
}
}
對子彈進行碰撞檢測(觸發檢測也可以,區別在於爆炸前有無撞擊效果),當子彈擊中物體時即在當前位置生成爆炸特效,同時銷毀子彈對象。
public class DestroyForTime : MonoBehaviour {
public float time;//在檢視面板傳入該特效的播放時長
void Start () {
Destroy (this.gameObject, time);//播放完畢后銷毀
}
}
給爆炸特效增加腳本,當特效播放完畢后銷毀對象。
4. 子彈擊中坦克產生傷害
在子彈擊中坦克后,主要處理在坦克的生命值上,因此在子彈的碰撞檢測中發送消息,而后在坦克中進行處理。
if (collision.collider.tag == "Tank") {
collision.collider.SendMessage ("TakeDamage");//若擊中坦克,則發送消息
}
給坦克增加一個單獨的腳本進行生命值的控制:
public class TankHealth : MonoBehaviour {
public GameObject tankExposionPrefab;
public int health = 100;
void TakeDamage(){
health -= Random.Range (10, 20);
if (health <= 0) {
GameObject.Instantiate (tankExposionPrefab, this.transform.position, this.transform.rotation);
GameObject.Destroy (this.gameObject);
}
}
}
5. 雙主角的情況下控制相機跟隨、視野縮放
public class FollowTarget : MonoBehaviour {
public Transform player1;
public Transform player2;
private Camera camera;
private Vector3 offset;
void Start () {
camera = this.GetComponent<Camera> ();
offset = transform.position - (player1.position + player2.position) / 2;
}
void Update () {
transform.position = (player1.position + player2.position) / 2 + offset;
float distance = Vector3.Distance (player1.position, player2.position);
float size = distance;
camera.orthographicSize = size;//讓正交相機視野實時改變
}
}
(1)雙角色的相機跟隨本質上與單角色沒太大區別,只是將視點定在兩個角色的中心點,通過中心點計算相機的偏移量,實時更新相機的position。
(2)視野的縮放則是利用了正交相機的size與兩個角色之間的距離之比進行更改,案例中兩角色之間初始距離為10,相機size為10,因此比例為1,所以直接讓size = distance。
6. 控制聲音播放
AudioSource.PlayClipAtPoint (tankExposionAudio, this.transform.position);
第一種方法,播放獲得的AudioClip對象,第一個參數為AudioClip對象,第二個參數為播放位置。
第二種方法,為游戲對象添加一個AudioSource組件,在腳本中通過GetComponent()方法獲得該組件,調用其play()方法進行播放。
案例下載 密碼:z79o