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

posted @ 2017-06-04 00:07  jyau  阅读(7218)  评论(1编辑  收藏  举报