初学者Unity项目--太空大战

太空大战算是比较经典的游戏了。这两天在跟着视频自学了一下。能做到的效果就是飞机发出子弹打爆陨石,如果被陨石碰到就死掉。简单的赤果果。界面如下:


现在做个总结:(模型声音之类的是导入的资源包。)

很明显这个游戏是一个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。就可以检测到碰撞了。

原型代码请看评论,评论会给出链接

  • 8
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

keneyr

老爷~给小的赏点盘缠吧555~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值