写在前面 #

本次 Space Shooter 实践通过实现以下功能达到加深对 U3D 游戏开发的认知.

  • 键盘控制飞船移动;
  • 发射子弹设计目标;
  • 随机生成大量障碍物;
  • 计分;
  • 实现游戏对象的生命周期管理;

同时进一步练习场景元素的编辑, 脚本文件的创建和 GUI 的处理, 以及音频文件的添加等方法.

最终效果:

1. 导入模型,贴图和材质 #

步骤要注意的几点 :

导入的资源包中有可以正确运行已做好的 Done_Main 场景, 将其删除, 创建一个全新的空场景文件 Main, 实践复原 Done_Main 的功能;

将 File>>Build Settings>>Player Settings>>Default Is Full Screen 取消勾选, 宽高设置为 400x600;

飞船模型拖至 Hierarchy 命名为 Player, Reset Transform 组件;

添加 Rigidbody, 不希望飞船受重力影响而下坠, 取消勾选 Use Gravity 选项;

添加碰撞体组件 Mesh Collider, 这是一个网格碰撞体, 使飞船能够与随机出现的障碍物发生碰撞, 并在碰撞后触发销毁飞船和障碍物的事件, Mesh Collider 的 Mesh 属性为模型 vehicle_playerShip 的网格, 该网格模型包含许多细小的三角形面片

为了提高游戏的执行效率, 飞船网格模型不应该过于复杂, 不必进行如此精确的碰撞检测, 应该建立一个简化的模型, 减少不必要的碰撞计算;

最后还要勾选 Convex 和 Is Trigger 选项框, 将 Mesh Collider 设置为触发器, 如图;

添加飞船尾部的火焰粒子效果, 要是 Player 的子对象;

使摄像机正对着飞船, Rotation(90,0,0). 使飞船处于 Viewport 视图窗口的下半部分, Position(0,10,4). 摄像机为正交投影;

添加背景图片, GameObject>>3D Object>>Quad 创建一个平面命名为 Background, 移除 Mesh Collider, 此时垂直于飞船;(Quad 默认情况下为背向剔除模式, 因此可能需要调整视角才能看到 Quad 平面) Quad 的 Position(90,0,0);

设置 Background 的纹理图片 Shader 模式为 Unlit/Texture;

为背景添加粒子效果繁星点点;

至此动图效果:

2. 编写脚本代码 #

2.1 控制飞船移动 ##

PlayerController.cs 实现方向键控制飞船移动的功能;

 using UnityEngine;using System.Collections;public class PlayerController : MonoBehaviour{// 想在 Inspector 视图显示, 就需要为 Boundary 类添加可序列化的属性 [System.Serializable][System.Serializable]public class Boundary{// 用于管理飞船活动的边界值, XZ 平面public float xMin, xMax, zMin, zMax;}// 速度控制变量public float speed;public Boundary boundary;// 飞船倾斜系数public float tilt = 4.0f;void FixedUpdate (){// 得到水平方向输入float moveHorizontal = Input.GetAxis ("Horizontal");// 得到垂直方向输入float moveVertical = Input.GetAxis ("Vertical");// 用上面的水平方向和垂直方向输入创建一个 Vector3 变量, 作为刚体速度, 是一个矢量Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);Rigidbody rb = GetComponent<Rigidbody> ();if (rb != null) {rb.velocity = movement * speed;// Mathf.Clamp 限定刚体的活动范围rb.position = new Vector3 (Mathf.Clamp (rb.position.x, boundary.xMin, boundary.xMax),0.0f,Mathf.Clamp (rb.position.z, boundary.zMin, boundary.zMax));// 飞船左右移动时有一定的倾斜效果,// 绕 Z 轴旋转, 往左运动 X 轴上速度为负值, 旋转的角度为逆时针正值, 所以要乘以一个负系数rb.rotation = Quaternion.Euler (0.0f, 0.0f, rb.velocity.x * -tilt);}}}

至此动图效果为

2.2 实现射击行为 ##

步骤需要注意的几点

新建立一个空的游戏对象 Bolt, 添加 Rigidbody 取消勾选 Use Gravity 选项框.

为 Bolt 新建一个子对象 Quad 命名为 VFX, Rotation(90,0,0), 移除 Mesh Collider, 添加材质 fx_bolt_orange.

为 Bolt 添加一个胶囊碰撞体, 勾选 Is Trigger 设为触发器, 设置 Capsule Collider 的 Direction 属性值为 Z-Axis, 设置半径和高度.

为 Bolt 添加一个脚本 Mover.cs. 此段代码放在 Start() 函数里, 因为在脚本的生命周期中只需要调用一次, 不需要每一帧都调用.

将 Bolt 拖至 Prefabs 文件夹成为预制体, 预制体做好后将原本的 Bolt 删除.

using UnityEngine;
using System.Collections;public class Mover : MonoBehaviour
{// 子弹的速度public float speed;void Start (){GetComponent<Rigidbody> ().velocity = transform.forward * speed;}}

脚本控制发射子弹, 为 Player 新建空的子对象 Shot Spawn, Position(0,0,0.7), 在此位置发射子弹

管理光电子弹的生命周期, 子弹在飞出有效区域之后自行销毁, 为游戏区域添加触发器, 当电光子弹飞出区域时触发事件, 在实践响应函数中调用 Destroy.

设置 Boundary 为触发器, 由于不需要在场景中显示 Boundary 对象, 移除 Mesh Renderer 组件.

为 Boundary 添加脚本 DestoryByBoundary.cs

using UnityEngine;
using System.Collections;public class DestoryByBoundary : MonoBehaviour {void OnTriggerExit(Collider other){Destroy (other.gameObject);}
}

注意的 :

  • 若要处理游戏对象移出触发器时的事件, 应该重载事件函数 OnTriggerExit;
  • OnTriggerExit 的参数 Collider 表示移出触发器的对象, 这里就是飞出边界的子弹对象上的碰撞体;

2.3 添加小行星障碍物 ##

要注意的几点

小行星随机生成, 随机的角度旋转;

射击击中小行星时, 小行星爆炸并销毁;

飞船碰上小行星, 飞船爆炸, 游戏结束;

新建空对象 Asteroid Position(0,0,9) Rigidbody 取消 Use Gravity 添加 Capsule Collider 勾选 Is Trigger.

模型 prop_asteroid_01 添加为 Asteroid 的子对象.

Capsule Collider 属性 Radius = 0.5, Height = 1.6, Direction 为 Z-Axis

为 Asteroid 添加脚本 RandomRotator.cs;

using UnityEngine;
using System.Collections;public class RandomRotator : MonoBehaviour
{// tumble 是旋转系数public float tumble;void Start (){// angularVelocity 表示刚体的角速度;  insideUnitSphere 表示单位长度半径球体内的一个随机点(向量)// 乘积结果描述了在半径长度为 tumble 的球体中的随机点// 由此就可以实现刚体以一个随机的角速度旋转GetComponent<Rigidbody> ().angularVelocity = Random.insideUnitSphere * tumble;}
}

设定 Asteroid 对象的角阻力为0;

添加控制射击小行星的功能, 为小行星 Asteroid 添加一个脚本来控制碰撞事件 DestroyByContact.cs

using UnityEngine;
using System.Collections;public class DestoryByContact : MonoBehaviour
{// 小行星爆炸时的粒子对象public GameObject explosion;// 飞船与小行星碰撞飞船爆炸的粒子对象public GameObject playerExplosion;void OnTriggerEnter (Collider other){if (other.tag == "Boundary" || other.tag == "Enemy") {return;}if (explosion != null) {// 在小行星销毁的位置生成一个爆炸效果, explosion 是小行星的位置Instantiate (explosion, transform.position, transform.rotation);  }if (other.tag == "Player") {// 在玩家飞机销毁的位置生成一个爆炸效果, playerExplosion 是飞船的位置Instantiate (playerExplosion, other.transform.position, other.transform.rotation);  }// 销毁跟小行星碰撞的物体Destroy (other.gameObject);  // 销毁小行星Destroy (this.gameObject);   }
}

Boundary 的 Tag 设为 Boundary; Player 的 Tag 设为 Player

至此动图效果为

2.4 控制小行星运动和随机生成 ##

让小行星以一定的速度飞向飞船, 为 Asteroid 添加脚本 Mover.cs 设置 speed 属性值为 -5; 速度设为负值, 因为小行星与子弹的运动方向相反

需要先制作 Asteroid 预制体, 创建 Project>>GameController 空游戏对象, Tag 为 GameController, 并为之创建脚本 GameController.cs

using UnityEngine;
using System.Collections;public class GameController : MonoBehaviour
{// 小行星数组public GameObject[] hazards;// 随机生成小行星的位置public Vector3 spawnValues;// 每一波小行星生成的数量public int hazardCount;// 每次生成小行星对象后延迟的时间, 单位秒public float spawnWait;// 表示开始生成小行星对象前等待的时间public float startWait;// 表示两批小行星阵列间的时间间隔public float waveWait;void Start (){StartCoroutine (SpawnWave ());}// 一波一波地生成小行星IEnumerator SpawnWave (){yield return new WaitForSeconds (startWait);while (true) {for (int i = 0; i < hazardCount; i++) {GameObject hazard = hazards [Random.Range (0, hazards.Length)];Vector3 spawnPosition = new Vector3 (Random.Range (-spawnValues.x, spawnValues.x), spawnValues.y, spawnValues.z);Instantiate (hazard, spawnPosition, Quaternion.identity);  // 生成随机的小行星yield return new WaitForSeconds (spawnWait);}yield return new WaitForSeconds (waveWait);}}
}

有一个要注意的地方, 对数组 Hazards 的内容不能拖成 model ,要是预制体, 否则生成的小行星无效导致不会运动, 如图

防止小行星数量太多, 距离近以致小行星之间相互碰撞销毁, 需要使用 协程类 WaitForSeconds

让爆炸后的粒子实例 explosion_asteroid 自动销毁, 建立脚本 DestroyByTime.cs 绑定到 explosion_asteroid 和 explosion_player 上

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class DestroyByTime : MonoBehaviour
{public float lifeTime = 2.0f;void Start (){Destroy (gameObject, lifeTime);}
}

3. 添加音频 #

将音频文件添加至预制体
是否勾选 Play On Awake 表明音频文件在唤醒时自动播放;

4. 添加积分文本 #

新版 Text 组件的使用方法, GameObject>>UI>>Text 生成 Canvas>>Text 和 EventSystem. 调整 Text 位置, Anchor Presets 选择 top-left.

积分功能包括以下作用 :

飞船发射子弹击中小行星后分值增加;
分值增加后更新 Text 组件的显示;

在 GameController.cs 脚本添加变量 scoreText 和 score

// 更新计分 Text 的组件
public Text scoreText;
// 保存当前分值
private int score;void Start ()
{score = 0;UpdateScore ();StartCoroutine (SpawnWave ());
}
void UpdateScore ()
{scoreText.text = "Get Score : " + score;
}public void AddScore (int newScoreValue)
{score += newScoreValue;UpdateScore ();
}

脚本 DestoryByContact.cs 可以调用 AddScore 函数.

// 表示小行星被击中后玩家分值增加的数量
public int scoreValue;
// 表示在游戏对象 GameController 上绑定的脚本 GameController.cs
private GameController gameController;void Start ()
{GameObject go = GameObject.FindWithTag ("GameController");if (go != null) {gameController = go.GetComponent<GameController> ();} else {Debug.Log ("Cannot Find a tag of GameController");}if (gameController == null) {Debug.Log ("Cannot Find the Script of GameController.cs");}
}
if (explosion != null) {// 在小行星销毁的位置生成一个爆炸效果, explosion 是小行星的位置Instantiate (explosion, transform.position, transform.rotation);  gameController.AddScore (scoreValue);}

5. 游戏结束与重新开始 #

添加游戏结束的 Text 组件

添加游戏结束的脚本

GameController 添加变量

// 更新 Text 组件的显示
public Text gameOverText;
// 游戏是否结束
private bool gameOver;
public void GameOver ()
{gameOver = true;gameOverText.text = "游戏结束";
}
while (true) {if (gameOver) {break;}// ... ...
}

在 DestroyByContact.cs 脚本加入对 GameOver() 函数的调用.

if (other.tag == "Player") {// 在玩家飞机销毁的位置生成一个爆炸效果, playerExplosion 是飞船的位置Instantiate (playerExplosion, other.transform.position, other.transform.rotation);  gameController.GameOver ();
}

添加重新开始的 Text 组件, 按[R]键重新开始.

// 更新添加的 Text 组件
public Text restartText;
// 是否重新开始游戏, 只有游戏结束时重新开始
private bool restart;void Start ()
{score = 0;UpdateScore ();gameOverText.text = "";gameOver = false;restartText.text = "";restart = false;StartCoroutine (SpawnWave ());
}void Update ()
{if (restart) {if (Input.GetKeyDown (KeyCode.R)) {Application.LoadLevel (Application.loadedLevel);}}
}

Application.LoadLevel(Application.loadedLevel) 是 Unity 中重新加载场景的常用方法.

三个文本

至此完毕.

End.

学习自 Book《Unity 官方案例精讲》

导出包 →GitHub

转载于:https://www.cnblogs.com/isayes/p/6567043.html

对 Unity 太空射击游戏的实践相关推荐

  1. Unity空间射击游戏开发教程

    描述 在本课程中,您将学习如何在unity中制作一款太空射击游戏.本课程使用全新的特性和编码实践,并且兼容所有较新版本的unity. 了解如何使用世界领先的免费游戏开发工具Unity创建太空射击游戏. ...

  2. iOS游戏开发之使用 Spritekit 框架和 Swift 的 iOS 2D 太空射击游戏(教程含源码)

    实战需求 使用 Spritekit 框架和 Swift 的 iOS 2D 太空射击游戏 本文价值与收获 看完本文后,您将能够作出下面的界面 实战代码 1.主界面 import SpriteKit im ...

  3. 【githubshare】基于 C 语言编写的一款 2D 太空射击游戏,已在 Windows 10 和 Ubuntu Linux 16.04 系统上跑通测试

    基于 C 语言编写的一款 2D 太空射击游戏:space-shooter.c,已在 Windows 10 和 Ubuntu Linux 16.04 系统上跑通测试. GitHub:github.com ...

  4. mac太空射击游戏:Nova Drift (新星漂移)中文版

    Nova Drift是一款激动人心的太空射击游戏. Nova Drift Mac整合了现代独立游戏风格和游戏历史上最深的根源.它不仅具有时尚和性感的外观,而且具有平稳的控制功能.玩家控制着一艘不断开发 ...

  5. 将Unity官方射击游戏 Space Shooter 改为实时对战小游戏,使用天梯实时对战服务(NanoLink)

    将Unity官方射击游戏(Space Shooter)改为实时对战小游戏,使用天梯实时对战服务(NanoLink) io 类型游戏如此热门,有没有蠢蠢欲动? 如何让自己的游戏快速实现可实时联机对战? ...

  6. 发个2D太空射击游戏代码

    很久前写的一个 2D 太空射击游戏,使用的是 DirectX 库和 C++ 开发. 现在看来程序结构虽不算合理,但是里面基本包括了一个 2D 太空射击游戏的基本元素:卷屏,碰撞检测,不同类型的敌人和 ...

  7. unity太空射击源码_引擎入门 | 创建双杆射击游戏(入门 2)

    点击上方"蓝字"关注我们吧! 本期我们继续为大家进行双杆射击游戏的后续教程 学习内容 3.整理资产 4.导入资产 5.安装 Blender 6.导入包 文章末尾可免费获取教程源代码 ...

  8. unity 开发射击打靶vr_暑假VR集训+unity自制射击游戏+李明

    Unity完全自制游戏<射击>项目记录 不知不觉利用暑假的生活来学校参加VR培训已经有三个星期了,回顾这么多日子既忙碌又充实的生活.制作时间为期三周,老师为了更好的磨练我们,给我们布置了这 ...

  9. [游戏开发][Unity] TPS射击游戏相机实现

    TPS射击游戏要实现的功能有: 滑屏控制 角色的横向旋转 相机的纵向旋转(区别于横向旋转) 相机贴墙拉近(不能穿墙) 相机观察旋转(角色不转相机转用于观察四周) 开火按钮和旋转屏幕功能共存(边开枪边转 ...

最新文章

  1. grape动态PHP结构(三)——API接口
  2. 北京小伙用AI修复100年前的京城老视频爆火网络,作者:7天完成,颜色还有不足...
  3. [csdn markdown]使用摘记一源码高亮及图片上传和链接
  4. 牛客题霸 SQL3 查找当前薪水详情以及部门编号dept_no
  5. 智能家居行业的数据传输保护
  6. c语言二维数组应该注意,第08天C语言(02):二维数组-注意点
  7. 公开标准不赚钱,认证赚大钱
  8. 机试学习笔记07 -- 斐波那契数列、素数判定、素数筛选、二分快速幂、分解素因数、常见数学公式总结、规律神器OEIS、高精度问题
  9. 对称矩阵 c语言,对称矩阵的判定 C语言 SDUT
  10. 主流手机分辨率与尺寸
  11. 如何用Hexo搭建个人博客网站
  12. word2007目录排版问题
  13. 【转】Java-满天繁星案例
  14. 适合练习听力的英文电影推荐
  15. 视音频编解码技术零基础学习方法(向雷神致敬)
  16. 在计算机英语中 memory的中文意思是,Memory是什么意思,memory什么意思中文
  17. Win11系统怎么开启平板模式
  18. 51单片机控制步进电机启停,正反转速度——入门
  19. Windows错误代码全表
  20. 计算机教案在幻灯片中插入影片,小学信息技术《在幻灯片中插入艺术字》说课稿...

热门文章

  1. Unity3D_WebGL_手机和其他浏览器警告处理
  2. 像科学家一样思考python_像计算机科学家一样思考Python(第2版)
  3. ROS2之机器人辅助医疗 (医护服务机器人)
  4. matlab求重心几种方法,怎么用matlab找图像的重心
  5. “从视频中学习”——Facebook启动新AI项目,IBM早早探索出AI视频解析新方法?| 硅谷速递...
  6. 实用的 iPhone 解锁:4Easysoft iPhone Unlocker中文
  7. PyQt5图形界面播放音乐
  8. 量子计算机叠加态的确定,用量子叠加态坍缩理论描述认知决策的过程
  9. MATLAB使用hough变换函数输出[H,theta,rho]的具体含义
  10. iOS自动化测试(一)-技术方案、环境配置与疯狂踩坑