unity案例入门(二)(坦克大战)
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
本文作学习交流用,如有错误,欢迎指正!