大家好我是Kaven,今天给大家带来的是一个Unity3D的打飞机的小项目。俗话说“眼看千变,不如手过一边”,学了差不多两星期Unity3D了,是时候找个小项目练练手了。于是就翻出了cocos2d-x的一个例子,模仿着写了一个飞机大战的游戏,虽然有一些功能没有实现,但总体上是完成了。闲话少说,下面开始吧。
由于这个用的是Unity3d自带的原生的2D插件native 2d,所以创建项目时左下角选择2d。
这个小游戏我分了三个场景,菜单场景,游戏场景,结束场景。由于菜单场景与结束场景都比较简单,所以主要就说说游戏主场景。源码在文章结尾处。
1.创建游戏场景
由于创建的是2d项目,则将图片拖入Scene中,该图片自动成为一个精灵,所以将图片信息拖入摆放即可。
下面创建一个GameManager文件,其绑定在摄像机中,主要负责飞机生命,玩家得分,背景播放等的显示功能。而生命,得分的显示需要我们创建GUIText来摆放。
代码如下:
using UnityEngine; using System.Collections; public class GameManager : MonoBehaviour { //显示控件位置 private Transform life; private Transform score; //游戏主角对象 private GameObject player; void Start () { //得到显示控件位置 life = transform.Find("Life"); score = transform.Find("Score"); //获取主角飞机对象 player = GameObject.FindGameObjectWithTag("Player"); } void Update () { if (player != null) { life.guiText.text = "生命:" + player.GetComponent<Player>().max_life.ToString(); score.guiText.text = "分数:" + player.GetComponent<Player>().grade.ToString(); } if (life.guiText.text == "生命:0") { //跳转到游戏结束场景 Application.LoadLevel(2); } } }
然后我们来实现背景的滚动。首先创建两个一样的背景图片上下摆放,如下图所示,这里切换到3d模式,更加形象
下面创建用于绑定在背景上的脚本BGControll.cs,代码如下
using UnityEngine; using System.Collections; public class BGControll : MonoBehaviour { //背景滚动速度 public float speed = 1.5f; void Update () { transform.Translate(Vector3.down * Time.deltaTime * speed); if (transform.position.y <= -5.6f) { transform.position = new Vector3(0, 5.7f, 0); } } }
然后将脚本绑定在两张背景图上即可。
2.创建主角飞机
主角创建与背景创建基本一样,也是可以用一张2d贴图,就不多说了。主角脚本主要处理移动,发射子弹,处理碰撞等,代码如下:
using UnityEngine; using System.Collections; public class Player : MonoBehaviour { //飞机生命值 public int max_life = 5; //子弹飞行速度 public float m_speed; //子弹对象 public GameObject bullet; //子弹发射位置 private Transform bulletLeft; private Transform bulletRight; //发射子弹频率 private float bulletRate = 0; private Transform m_transform; //声音资源 private AudioSource audio; [HideInInspector] //分数 public int grade = 0; //初始化变量 void Start () { bulletLeft = this.transform.Find("bulletL"); bulletRight = this.transform.Find("bulletR"); m_transform = this.transform; audio = GetComponent<AudioSource>(); } void Update () { //上方向键 if (Input.GetKey(KeyCode.UpArrow)) { m_transform.Translate(Vector3.up * Time.deltaTime * m_speed); } //左方向键 if (Input.GetKey(KeyCode.LeftArrow)) { m_transform.Translate(Vector3.left * Time.deltaTime * m_speed); } //下方向键 if (Input.GetKey(KeyCode.DownArrow)) { m_transform.Translate(Vector3.up * Time.deltaTime * (-m_speed)); } //右方向键 if (Input.GetKey(KeyCode.RightArrow)) { m_transform.Translate(Vector3.left * Time.deltaTime * (-m_speed)); } bulletRate -= Time.deltaTime; if (bulletRate <= 0) { bulletRate = 0.1f; //按下空格键,发射子弹 if (Input.GetKey(KeyCode.Space)) { Instantiate(bullet, bulletLeft.transform.position, Quaternion.Euler(new Vector3(0, 1, 0))); Instantiate(bullet, bulletRight.transform.position, Quaternion.identity); //播放射击声音 audio.Play(); } } check(); } //检测边界,使飞机不飞出摄像机 void check() { if (m_transform.position.x <= -1.3f) { m_transform.position = new Vector3(-1.3f, m_transform.position.y, 0); } if (m_transform.position.x >= 1.3f) { m_transform.position = new Vector3(1.3f, m_transform.position.y, 0); } if (m_transform.position.y >= 2.5f) { m_transform.position = new Vector3(m_transform.position.x, 2.5f, 0); } if (m_transform.position.y <= -2.5f) { m_transform.position = new Vector3(m_transform.position.x, -2.5f, 0); } } //碰撞时调用该方法,飞机减血 public void Hit(int Value) { if (max_life > 0) { max_life -= Value; } else { Destroy(this.gameObject); //Application.LoadLevel(2); } } //增加分数 public void Add(int score) { grade += score; } }
上面代码中我用了bulletLeft,bulletRight,这是我为主机添加的两个子对象,主要是用于发射子弹,相当于炮筒吧,而bullet则是定义的预设,其中绑定的脚本后面会说明。
下面是Bullet子弹预设绑定的脚本代码,子弹主要功能为与敌人发生碰撞,主角得分,敌人减血。
using UnityEngine; using System.Collections; public class Bullet : MonoBehaviour { //子弹的速度 public float m_speed = 2f; //子弹存在时间 public float lifeTime = 20f; //子弹碰撞到敌人伤害 public int power = 2; //玩家飞机 private GameObject player; void Start () { //根据Tag找到玩家飞机对象 player = GameObject.FindGameObjectWithTag("Player"); } void Update () { //移动子弹 transform.Translate(Vector3.up * Time.deltaTime * m_speed); } void OnTriggerEnter2D(Collider2D mCollider) { //如果碰撞的是敌人 if (mCollider.gameObject.tag == "Enemy") { //敌人减血 mCollider.gameObject.GetComponent<Enemy>().Hit(power); //得分 player.GetComponent<Player>().Add(100); //销毁子弹 Destroy(this.gameObject); } } //当离开摄像机范围时触发销毁事件 void OnBecameInvisible() { Destroy(this.gameObject); } }
期间犯了个非常2的错误就是将OnTriggerEnter2D写成了OnTriggerEnter导致一直没有碰撞,我竟然忘记我建的是2d项目了,函数名改了也不知道,查了些资料终于解决了,不仔细啊。
好了,通过以上的代码我们就可以按键盘的方向键移动飞机,按空格键发射子弹了,我已经等不及要打敌人了。
3.创建敌机
敌机也是先拖入敌机图片,然后绑定脚本,添加组件,然后保存为预设,我们以后还有个敌机生产器要生产敌机呢。
我创建了三种敌机预设
敌机主要是移动,碰撞。下面来看看敌机脚本:
using UnityEngine; using System.Collections; public class Enemy : MonoBehaviour { //敌机移动速度 public float m_speed = 3; //生命值 public int max_life = 5; //得到爆炸动画 private Animator animator; //爆炸声音 private AudioSource audio; void Start () { animator = GetComponent<Animator>(); audio = GetComponent<AudioSource>(); } void Update () { transform.Translate(Vector3.down * Time.deltaTime * m_speed); } void OnTriggerEnter2D(Collider2D mCollider) { //敌机与主机碰撞双方掉血 if (mCollider.gameObject.tag == "Player") { //敌机掉血 this.Hit(1); //主机掉血 mCollider.gameObject.GetComponent<Player>().Hit(1); } } //减血 public void Hit(int value) { //如果生命值大于0 if (max_life > 0) { //生命值降低 max_life -= value; } //如果等于0,则播放动画 else { audio.Play(); animator.SetBool("isLive", false); AnimatorStateInfo animatorState = animator.GetCurrentAnimatorStateInfo(0); //销毁敌机 if (animatorState.IsName("Base Layer.explosion")) { Destroy(this.gameObject); } } } //离开摄像机视野时销毁对象 void OnBecameInvisible() { Destroy(this.gameObject); } }
上面使用到了一个动画,就是敌机爆炸时的动画。那么如何创建动画呢?首先资源中可以拖动一组连续的爆炸图片到场景中,系统会自动提醒创建动画,命名为explosion即可。然后Project视图中就出现了一个animation和一个animator。在菜单栏找到Windows -> Animation和 Winodws -> Animator可以打开如下窗口。
具体的动画编辑可以看看雨松MOMO的关于动画的文章.
下面是敌机生产器,在主界面的左右两边的顶部分别放上两个空物体用来创建敌机。敌机创建时间为1~3秒不等,然后绑定创建脚本即可。
using UnityEngine; using System.Collections; public class SpawnEnemy : MonoBehaviour { //生成敌人速度 public float spawnTime = 1.0f; //敌人对象数组 public GameObject[] enemys; void Start () { StartCoroutine("spawn"); } void Update() { //生成敌人速度在1~3秒之间变化 spawnTime = Random.Range(1.0f, 3.0f); } IEnumerator spawn() { //等待 yield return new WaitForSeconds(spawnTime); //克隆对象 Instantiate(enemys[Random.Range(0, 3)], new Vector3(transform.position.x * Random.Range(-1.2f, 1.2f), transform.position.y, 0), Quaternion.Euler(0, 0, 0)); StartCoroutine("spawn"); } }
4.关于碰撞检测
子弹:
void OnTriggerEnter2D(Collider2D mCollider) { //如果碰撞的是敌人 if (mCollider.gameObject.tag == "Enemy") { //敌人减血 mCollider.gameObject.GetComponent<Enemy>().Hit(power); //得分 player.GetComponent<Player>().Add(100); //销毁子弹 Destroy(this.gameObject); } }
敌机:
void OnTriggerEnter2D(Collider2D mCollider) { //敌机与主机碰撞双方掉血 if (mCollider.gameObject.tag == "Player") { //敌机掉血 this.Hit(1); //主机掉血 mCollider.gameObject.GetComponent<Player>().Hit(1); } }
碰撞检测需要添加2d刚体组件和2d碰撞器组件,在Physics 2D中,不要选错了。关于碰撞检测的比较可以看看我的这篇文章【Unity3D游戏开发】—— 碰撞检测。
最后就运行一下感受一下打飞机的快感吧(遮面)
基本上这个一个小游戏也就完成了,关于其他的一些功能可以随便加嘛,多几个关卡就多创建几个场景,还能加上BOSS战什么的。
由于无法导出我就打包了,源代码:https://github.com/GeeKaven/MoonPlane
最后说下我的想法吧, 今天早上一大早起来就去图书馆了,然后就坐在电脑前一直做到下午晚饭时才搞定。虽然这对于一个大牛来说不难,可能一会儿就解决了。但对于我一个新手还是蛮有挑战性的(哈哈)。有些事是不做永远不知道难度有多大,有些事是做了才会明白会有这么多的问题,还有些事是做了会觉得也不过如此嘛,总之一点理论的基础上多实践,熟能生巧慢慢的也就会了。
最后附上一句话共勉:
每一个成功者都是一位苦行僧,只有他们自己才知道,通往成功的道路上,到底有多少寂寞与不解。
文章作者:wxk_bigkang(Kaven)
转帖注明:http://blog.csdn.net/wxk_bigworld/article/details/25565325
【Unity3D游戏开发】—— 太空大战打飞机游戏详解