unity3d 太空大战之飞机游戏

2015年01月23日 13:16 0 点赞 0 评论 更新于 2025-11-21 15:13

很多人都喜欢玩Unity3D太空大战之飞机游戏,在学习了Unity3D之后,就会想要自己开发这个游戏。本文将基于网上找到的详细解说,带大家一步步实现这个游戏。源码在文章结尾处。

游戏场景划分

这个小游戏分为三个场景:菜单场景、游戏场景和结束场景。由于菜单场景与结束场景相对简单,本文主要聚焦于游戏主场景的实现。

1. 创建游戏场景

场景图片布置

由于创建的是2D项目,将图片拖入Scene中,该图片会自动成为一个精灵,只需将图片信息拖入并摆放即可。

创建GameManager脚本

创建一个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;
}
}

上述代码中使用的bulletLeftbulletRight是为主机添加的两个子对象,用于发射子弹,类似于炮筒。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);
}
}

这里需要注意的是,在2D项目中,碰撞检测需要使用OnTriggerEnter2D函数,而不是OnTriggerEnter。作者在开发过程中就因为将OnTriggerEnter2D写成了OnTriggerEnter,导致一直没有碰撞效果,后来查阅资料才解决了这个问题。

通过以上代码,我们就可以使用键盘的方向键移动飞机,按空格键发射子弹了。

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 -> AnimationWindows -> 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战,只需要创建新的场景即可。

源码可在文章结尾处获取。

作者信息

feifeila

feifeila

共发布了 3994 篇文章