概述
太空大战算是比较经典的游戏了。这两天在跟着视频自学了一下。能做到的效果就是飞机发出子弹打爆陨石,如果被陨石碰到就死掉。简单的赤果果。界面如下:
现在做个总结:(模型声音之类的是导入的资源包。)
很明显这个游戏是一个2D游戏,但是我们是在3D环境下做的,其实没太大影响。
我们让这个背景和飞机都在X-Z平面上,飞机在(0,0,0)的位置,背景在(0,-10,10)的位置,如图:
这样我们的飞机和陨石就相当于只在X-Z这个平面运动,三维就降到了二维。很明显,相机要在飞机的Y轴上方才能出现游戏的界面效果。
这样我们的大体位置就摆好了。下面写代码控制飞机的运动:
void FixedUpdate(){
//水平移动
float h = Input.GetAxis ("Horizontal");
//垂直移动
float v = Input.GetAxis ("Vertical");
//移动方向
Vector3 move = new Vector3 (h, 0f, v);
//移动速度
_rigi.velocity = speed * move;
//限制飞机移动的范围,限制value的值在min和max之间, 如果value小于min,返回min。 如果value大于max,返回max,否则返回value
_rigi.transform.position = new Vector3(Mathf.Clamp(_rigi.transform.position.x,bound.xMin,bound.xMax),
0,
Mathf.Clamp(_rigi.transform.position.z,bound.zMin,bound.zMax)
);
}
简单说一下FixedUpdate()和Update()的区别:
pdate()是每渲染新的一帧就会调用;FixedUpdate()是固定的时间间隔调用,时间可以通过edit->Project Settings->time进行设置
接触了一个新函数:Mathf.Clamp。Mathf是常用数学函数的集合。
static function Clamp(value:float,min:float,max:float):float
限制value的值在min和max之间, 如果value小于min,返回min。 如果value大于max,返回max,否则返回value
控制飞机发出子弹:
void Update(){
//如果敲击空格键,生成子弹
if(Input.GetKeyDown(KeyCode.Space)){
_audio.PlayOneShot (fire,0.7f);
Instantiate(bolt,spawnPos.position,spawnPos.rotation);
}
}
bolt是一个预制体Prefab,spawnPos是一个空物体。Instantiate的意思就是在这个空物体的位置生成一个子弹。
怎么销毁子弹呢?这里用到了OnTriggerExit()
void OnTriggerExit(Collider other){
//print (other.name);
//销毁物体
Destroy (other.gameObject);
}
也就是在飞机和子弹的平面上有一个box collider,当然这个collider是触发模式。判断当子弹离开这个collider的时候,就销毁子弹。如图:
好了飞机能够飞能够发射子弹了。那么我们生成陨石吧。
我们把本身已经导入的模型拉入到Hierarchy中(附在一个空物体上),然后做成Prefab。现在控制单个陨石的旋转和降落以及碰到子弹就爆炸。
首先旋转:
public class RandowRotate : MonoBehaviour {
//陨石旋转速度
public float Tumble = 5;
private Rigidbody _rigi;
void Start(){
_rigi = GetComponent<Rigidbody> ();
//设置刚体的角速度????
_rigi.angularVelocity = Random.insideUnitSphere * Tumble;
}
void Update(){
}
}
Random.insideUnitSphere的意思就是返回半径为1的球体内的一二随机点。
然后运动:
public class Mover : MonoBehaviour {
private Rigidbody _rigi;
public float speed = 10;
void Start(){
_rigi = GetComponent<Rigidbody> ();
_rigi.velocity = speed * new Vector3 (0,0,1);
}
}
这个Mover.cs其实是控制飞机写的,但是照样能控制陨石,只需把Unity界面内的speed改成复数即可。
碰撞爆炸效果:
void OnCollisionEnter(Collision other){
//如果陨石碰到飞机,飞机爆炸,飞机销毁
if (other.gameObject.tag == "Player") {
Instantiate (playerExplosion, other.gameObject.transform.position, other.gameObject.transform.rotation);
Destroy (other.gameObject);
_gc.GameOver ();
}
//陨石爆炸,陨石销毁
Instantiate (explosion,transform.position,transform.rotation);
Destroy (this.gameObject);
_gc.AddScore (score);
}
playerExplosion和explosion都是公有变量,在Unity面板中拉入效果即可。如图:
如果要添加声音的话,也要在这些个预制体面板中添加AudioSource,这样每次生成爆炸效果的时候也会生成Audio。因为我发现调用audio 的时候只能在Update()这样的函数中调用,如果只是一个普通的函数,声音是不会响的。所以以陨石爆炸为例,简单记录一下声音的附载:
这就不用写代码控制。Unity已经帮你做好了。puls,通过上图我们可以看到一个cs文件,这个是根据时间销毁爆炸效果的(毕竟爆炸也是一个粒子系统),代码如下:
public class DestroyByTime : MonoBehaviour {
//过了一定时间就销毁
public float lifetime;
void Start(){
Destroy (this.gameObject,lifetime);
}
}
好了现在陨石可以降落了,飞机可以打陨石了。怎么控制陨石有规律的一波一波的降落呢?我们在Hierarchy面板中新建一个空物体,更名为GameController,GameController一般都是必不可少的。它的面板如下:
首先来看我们的GameController.cs文件:
public Vector3 spawnValues;
//创建三个物体
public GameObject[] hazard;
//一波10个小陨石
public int numPerWave = 10;
//出现小陨石之前的等待时间
public float startWait = 2f;
//小陨石间隔时间
public float spawnWait = 1f;
//每波之间的间隔时间
public float waveWait = 4f;
void Update(){
if (gameOver && Input.GetKeyDown (KeyCode.R)) {
//Application.LoadLevel (Application.loadedLevel);
SceneManager.LoadScene("spceshooter");
}
}
//有规律的随机产生小陨石
IEnumerator SpawnWaves(){
yield return new WaitForSeconds (startWait);
while(true){
for (int i = 0; i < numPerWave; i++) {
Spawn ();
//?????
yield return new WaitForSeconds (spawnWait);
}
yield return new WaitForSeconds(waveWait);
if (gameflag==false) {
break;
}
}
}
//随机创建小陨石
void Spawn(){
//取三个物体中的一个
GameObject o = hazard[Random.Range(0,hazard.Length)];
//产生随机位置,主要是x不同
Vector3 p = new Vector3 (Random.Range(-spawnValues.x,spawnValues.x),spawnValues.y,spawnValues.z);
//默认旋转
Quaternion q = Quaternion.identity;
//初始化小陨石
Instantiate (o, p, q);
}
需要了解的是yield,这个方法在代码中是经常使用的。这个比较复杂,自行百度。有空再写篇博客介绍。
现在可以有多波小陨石了。怎么计分呢,控制游戏结束,重新开始呢?
在Hierarchy面板中添加三个GUIText,如图:
分别对应得分、游戏结束、游戏重新开始的界面。控制代码如下,这些代码最好是写在GameController.cs:
//得分
public GUIText scoreText;
private int score = 0;
//游戏结束
public GUIText gameOver;
public bool gameflag = true;
//游戏重新开始
public GUIText gameRestart;
void Start(){
//????
spawnValues.x = 6;
StartCoroutine (SpawnWaves ());
scoreText.text = "Score: " + score;
//先为空,不显示
gameOver.text = "";
gameRestart.text = "";
}
得分以及游戏结束:
//分数增加
public void AddScore(int v){
score += v;
scoreText.text = "Score: " + score;
}
//游戏结束
public void GameOver(){
gameflag = false;
gameOver.text = "Game over";
gameRestart.text = "press R to restart";
}
得分及游戏结束的判断在DestroyByContact.cs文件内,只要是判断陨石碰到了飞机,就调用GameOver();只要是判断陨石碰到了子弹,就调用分数增加。那么怎么判断R键的按下呢。需要在GameController.cs的update()内进行判断:
void Update(){
if (gameOver && Input.GetKeyDown (KeyCode.R)) {
//Application.LoadLevel (Application.loadedLevel);
SceneManager.LoadScene("spceshooter");
}
}
ok大功告成!一个原型就这么做出来了。可以改进的地方很多,比如说:
判断飞机打到什么程度就换关卡,不同关卡的难度怎么设计?
怎么添加敌人这个角色,让敌人能够移动并发射子弹打飞机?
飞机有没有大招?
飞机能不能快速移动?
能不能让场景有移动的感觉?
---------------------------------------性感的分割线-------------------------------------------------------------
写项目的时候出现的错误以及解决办法:
说一下背景bg:其实很简单,就是一个Quad,然后把长图贴上去即可。
1.给飞机添加了一个mesh collider,添加了Rigibody之后,运行总是报错:
Non-convex MeshCollider with non-kinematic Rigidbody is no longer supported in Unity 5.
If you want to use a non-convex mesh either make the Rigidbody kinematic or remove the Rigidbody component. Scene hierarchy path "Player", Mesh asset path "Assets/SpaceShooter/Models/vehicle_playerShip_collider.FBX" Mesh name "player_ship_collider"
这个错误的意思就是:
碰撞检测时,如果想使用非凸网格,删除刚体 或者勾选 is kinematic 选项。但是不能删除刚体, is kinematic的意思是是否运动学的。如果勾选上了,这个对象只受transform影响不受force影响,所以就别想让飞机动弹了。解决办法是:
勾选Convex。勾选上了以后就是用非凸网格。报错就消失了。
2.刚开始collider之间的is trigger都填上了,陨石和子弹都在一个平面内的Collider内,所以判断不到陨石和子弹的碰撞,后来只有这个平面Boundary是触发的,其他的都变成了非触发的collider。就可以检测到碰撞了。
原型代码请看评论,评论会给出链接
最后
以上就是丰富冬日为你收集整理的初学者Unity项目--太空大战的全部内容,希望文章能够帮你解决初学者Unity项目--太空大战所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复