当前位置: 首页 > news >正文

【经典游戏】保姆级:Unity3D飞机大战(含资源包、完整项目)

目录

1 资源准备

2 场景搭建

2.1 调整窗口分辨率

2.1.1 在Player中设置屏幕宽高比

2.1.2 调整Unity 编辑器中的Game视图分辨率

2.2 调整相机

2.2.1 具体操作

2.2.2 Camera组件属性介绍

2.3 调整光照

2.3.1 具体操作

2.3.2 Light组件属性介绍

2.4 搭建背景

3 创建玩家飞船

3.1 模型拖入与解包

3.2 添加组件

3.3 添加尾焰

3.4 飞船移动

​编辑3.5 创建飞船子弹

3.5.1 创建子弹

3.5.2 子弹自动飞行

3.5.3 添加子弹音效

3.5.4 制作子弹预制体

3.6 飞船射击

4 制作物体飞行边界

4.1 创建边界

4.2 制作销毁脚本

4.3 添加边界标签

5 制作敌人

5.1 制作陨石

5.1.1 创建陨石物体

5.1.2 陨石自旋转

5.1.3 添加陨石标签

5.1.4 制作其余两种陨石

5.1.5 制作陨石预制体

5.1.6 修改PlayerBullet脚本

5.2 制作敌方飞船

5.1.1 创建敌方飞船物体

5.1.2 添加碰撞体和刚体

5.1.3 添加敌人飞船标签

5.1.4 制作敌人子弹

5.1.5 修改子弹贴图

5.1.6 敌方飞船移动和自动射击

5.1.7 修改PlayerBullet脚本

5.1.8 制作敌方飞船预制体

5.3 玩家接触陨石和敌人爆炸

6 爆炸特效的调整

6.1 延迟销毁特效

6.2 添加爆炸音效

7 随机批量生成敌人

8 场景管理

8.1 管理StartScene

8.2 制作点击事件

8.3 配置Build Setting

8.4 管理GameScene

9 打包设置

9.1 设置游戏图标和名字

9.2 游戏打包


成品游戏的.unitypackage包和完整可运行游戏在这里【成品游戏和完整项目文件包】有需要的可私信

本教程所需免费初始资源包:

https://pan.quark.cn/s/67a151f01beb?pwd=m5L8

提取码:m5L8

1 资源准备

下载好所需资源包,创建Unity3D项目,任意版本即可,将.unitypackage的资源包导入至Project视图,导入后,文件夹介绍如下,包含了本项目所需的音频、材质、模型、粒子特效、场景、纹理贴图资源。

2 场景搭建

2.1 调整窗口分辨率

相关设置在 Player Settings 中。

  1. 打开 Build Settings 窗口:主菜单File —> Build Settings。

  2. 点击 Player Settings... 按钮,或直接在 Project Settings 窗口中找到 Player 选项卡。

在 Player Settings 中,需要重点关注 Resolution and Presentation 面板。以下是一些关键设置:

设置项功能说明
Fullscreen Mode设置应用启动时的屏幕模式。

Default Is Native Resolution

当游戏以全屏模式启动时,是否自动使用显示器的原生(最高)分辨率

Mac Retina Support

专门针对配备 Retina(高DPI)显示屏 的 Apple Mac 电脑。 
Run in background应用失去焦点时(如切换窗口)不暂停,继续运行。

屏幕模式 (Fullscreen Mode) 

  • Fullscreen Window:无边框全屏窗口,渲染分辨率可设定,窗口会自动缩放填充显示器(可能带黑边)。这是现代游戏常见模式。

  • Exclusive Fullscreen:独占全屏,会改变显示器分辨率来匹配游戏设置。仅推荐在Windows平台用于追求极致性能。

  • Windowed:窗口模式。可结合 Default Screen Width/Height 设置初始窗口大小,并通过 Resizable Window 选项决定用户能否手动调整。

2.1.1 在Player中设置屏幕宽高比

本项目中,取消勾选Default Is Native Resolution,配置默认的屏幕宽高分别为600、900。

2.1.2 调整Unity 编辑器中的Game视图分辨率

Game视图是开发过程中预览游戏运行效果的主要界面,而顶部的Aspect下拉菜单是一个极其重要的工具,用于模拟游戏在不同屏幕比例和设备上的显示效果。Aspect(宽高比/显示比例)菜单允许固定 Game 视图的显示比例,模拟游戏在不同设备和屏幕分辨率下的视觉效果。

注意:

  • Game 视图的Aspect设置仅用于编辑器预览

  • 实际构建后的分辨率行为需要在 Player Settings > Resolution and Presentation 中配置

Aspect Ratio(宽高比):关注的是屏幕宽度和高度的比例关系,而不是具体的像素数量。

工作原理:

  • 保持比例不变:无论 Game 视图窗口如何调整大小,内容都会按照设定的宽高比进行显示

  • 自动添加黑边:如果窗口比例不匹配,Unity 会自动在两侧或上下添加黑边(称为"letterboxing")

  • 不改变渲染分辨率:实际渲染的分辨率仍然是窗口的物理像素数

使用场景:

  • UI适配测试:确保界面在不同比例屏幕上都能正常显示

  • 跨平台开发:模拟目标设备的屏幕比例

  • 相机视野验证:检查游戏内容不会在极端比例下穿帮

Fixed Resolution(固定分辨率): 设定一个精确的像素尺寸,Game 视图会严格按照这个分辨率进行渲染。

工作原理:

  • 固定像素尺寸:无论窗口大小如何,渲染分辨率保持不变

  • 像素精确:每个像素都按照设定尺寸渲染

  • 缩放显示:在较大的窗口中会放大显示,在较小的窗口中会缩小显示(可能需滚动)

设置方法:

  1. 在 Aspect 下拉菜单中选择 "+" 添加自定义分辨率

  2. 输入具体的 Width 和 Height 像素值

  3. 选择横屏(Landscape)或竖屏(Portrait)方向

配置Game视图中的分辨率为Fixed Resolution:600*900,命名为MyView,并选择,如下图所示:

2.2 调整相机

2.2.1 具体操作

因为本项目是俯视角游戏,所以相机要在正上方向下俯视,本项目资源中拥有游戏背景贴图和特效,针对Main Camera游戏对象中的Transform、Camera组件的调整如下:


2.2.2 Camera组件属性介绍

相机(Camera)是 Unity 中最核心的组件之一,它决定了玩家在游戏中看到的画面。理解相机的各项属性对于创建出色的游戏体验至关重要。

2.2.2..1 Clear Flags(清除标志)

决定相机如何清除上一帧的内容,这里选择单色模式Solid Color

选项说明使用场景
Skybox用天空盒填充空白区域3D 游戏,需要背景环境
Solid Color用单一颜色填充2D 游戏,性能要求高的场景
Depth Only仅清除深度缓冲区多相机叠加渲染(UI相机、特效相机)
Don't Clear不清除,累积渲染特殊视觉效果(运动模糊、轨迹效果)

2.2.2.2 Background(背景)

背景颜色调整为黑色。

2.2.2.3 Projection(投影类型)

透视模式:Field of View (FOV):视野角度(垂直方向)

  • 常用值:第一人称 60-90°,赛车游戏 80-100°

  • Fov Axis:选择基于垂直还是水平方向计算 Fov

正交模式:

  • Size:相机视口高度的一半(世界单位),例如:Size = 5 表示相机能看到 10 个单位高度的区域

  • 常用于 2D 游戏、UI 渲染、策略游戏

本项目选择正交模式,Size调整为10,下面均为针对相机组件其他属性的介绍,不需要调整。

2.2.2.4 Clipping Planes(近/远裁剪平面)

  • Near:最近渲染距离(通常 0.01-0.3)
  • Far:最远渲染距离(根据场景大小调整)

2.2.2.5 Viewport Rect(视口矩形)

控制相机渲染画面在屏幕上的位置和大小:

  • X, Y:左下角起始位置(0-1 标准化坐标)

  • W, Width:宽度比例

  • H, Height:高度比例

2.2.2.6 Depth(深度)

  • 多个相机渲染时的优先级

  • 数值越大的相机越晚渲染(覆盖之前的画面)

  • 用于实现 UI 相机、特效相机等分层渲染

2.2.2.7 Culling Mask(剔除遮罩)

选择哪些层(Layer)的物体被此相机渲染:

  • 优化性能:不渲染不必要的层

  • 特殊效果:不同相机渲染不同内容

2.2.2.8 Rendering Path(渲染路径)

选项说明适用场景
Forward前向渲染移动平台,光源数量少
Deferred延迟渲染PC/主机,大量动态光源
Legacy旧版渲染兼容老项目

2.2.2.9 Target Texture(目标纹理)

  • 将相机渲染到 Render Texture 而非屏幕

  • 用途:安全摄像头、镜子、迷你地图、画中画

2.2.2.10 HDR(High Dynamic Range)

  • 启用高动态范围渲染

  • 优点:更好的光照效果,支持后期处理特效

  • 代价:更高的性能消耗

2.2.2.11 MSAA(Multi-Sample Anti-Aliasing)

  • 多重采样抗锯齿

  • 减少模型边缘的锯齿感

  • 可选:2x, 4x, 8x(数值越高效果越好,性能消耗越大)


2.3 调整光照

2.3.1 具体操作

将默认的Directional Light游戏对象删除,创建空物体,命名为:All Lights,创建两个Directional Light直向光,分别为主光Main Light和辅光Fill Light,调整如下:

经过调整后,在游戏中,飞船就会有阴影,更加具有立体感。


2.3.2 Light组件属性介绍

2.3.2.1 Type(灯光类型)

① Directional Light(方向光)

  • 特点:无限远光源,平行光线(类似太阳)

  • 属性

    • 没有位置概念,只有旋转方向

    • 影响整个场景

  • 用途:主光源(太阳、月亮)

② Point Light(点光源)

  • 特点:从一点向所有方向发射光线(类似灯泡)

  • 属性

    • Range:光照范围

      • 仅点光源和聚光灯
      • 定义灯光影响的最大距离
      • 超出范围的物体不受该灯光影响
    • 有衰减,距离越远光照越弱

  • 用途:灯泡、蜡烛、局部照明

③ Spot Light(聚光灯)

  • 特点:锥形光照区域(类似手电筒、舞台灯)

  • 属性

    • Range:照射距离

      • 仅点光源和聚光灯
      • 定义灯光影响的最大距离
      • 超出范围的物体不受该灯光影响
  • Spot Angle:锥形角度(1-179度)

    • 仅聚光灯

    • 控制锥形光的宽度角度

    • 常用范围:30°(窄束)到 120°(宽束)

  • 用途:手电筒、车灯、舞台灯光

④ 区域光(Area Light)

  • 特点:矩形区域发射光线,产生柔和的阴影

  • 属性

    • Width/Height:区域尺寸

    • 仅用于烘焙光照(Baked GI)

  • 用途:柔和的室内照明、灯带、广告牌

2.3.2.2 Color & Intensity(颜色和强度)

  • Color:灯光颜色(RGB)

  • Intensity:光照强度

    • 方向光:通常 0-2(1.0 相当于晴天太阳)

    • 点光源/聚光灯:根据场景调整,可能达到 10-100

    • 区域光:根据面积和需求调整

2.3.2.3 Mode(光照模式)

① 实时光照(Realtime)

  • 每帧动态计算

  • 可移动、可改变属性

  • 性能消耗较高

② 烘焙光照(Baked)

  • 预先计算并存储到光照贴图

  • 运行时无性能消耗

  • 静态物体专用

③ 混合光照(Mixed)

  • 结合实时和烘焙的特性

  • 静态物体使用烘焙光照,动态物体使用实时光照

  • 平衡性能和质量

2.3.2.4 Shadow Type(阴影类型)

  • No Shadows:不产生阴影

  • Hard Shadows:硬阴影,边缘锐利

  • Soft Shadows:软阴影,边缘柔和(更真实)

    • 阴影强度(Strength)

      • 控制阴影的黑暗程度(0-1)

      • 0 = 无阴影,1 = 完全黑暗的阴影

    • 阴影分辨率(Resolution)

      • 控制阴影贴图的质量

      • 选项:Low, Medium, High, Very High, Ultra

    • 阴影偏置(Bias)

      • Bias:解决阴影 acne(自阴影瑕疵)

      • Normal Bias:沿法线方向偏移,进一步解决 acne 问题

2.3.2.5 Cookie

  • 在灯光前放置纹理来创建图案效果

  • 方向光:任意纹理

  • 点光源:立方体贴图(Cubemap)

  • 聚光灯:2D 纹理

2.3.2.6 Flare

  • 镜头光晕效果

  • 模拟相机镜头对强光的反射

  • 可自定义或使用内置光晕


2.4 搭建背景

创建空物体命名为Environment,重置Transform,以它作为父物体去创建子物体,在Hierarchy中右键—>3D Object—>Quad,重命名为Background,重置Transform。

Position的Y设置为-10,Rotation的X设置为90,然后移除 Mesh Collider,将Scale的X设置为15,Y设置为30。修改Mesh Renderer的Materialstile_nebula_green_dff。

将星空特效StarField拖入Environment中,修改其Position为(0,-5,16)

运行后如图所示:

3 创建玩家飞船

3.1 模型拖入与解包

找到Project—>Assets—>Models—>PlayerShip模型,拖入场景中,Reset重置下Transform组件,将Position、Rotation、Scale均为默认状态即(000,000,111)。

右击场景中的PlayerShip,选择Prefab—>Unpack进行断开与预制体的链接。

  • Unpack:只解包当前层级的 Prefab

  • Unpack Completely:递归解包所有嵌套的 Prefab

3.2 添加组件

创建一个空物体命名为Player,Reset重置Transform组建后,把PlayerShip作为它的子物体,并给Player添加RigidbodyMesh Collider组件。

注意:修改其标签Tag为Player

注意取消勾选Rigidbody组件中的使用重力属性,同时勾选Mesh Collider的Convex和Is Trigger,作为触发器使用,并且选择指定的Mesh,playership_collider网格体。

3.3 添加尾焰

找到Explosion_Player,作为子物体拖入Player中,设置Position的Z为-0.75即可,运行后粒子特效会显示出来。

到此,有关飞船的设置完成,接下来就是让飞船通过键盘操作移动起来。

3.4 飞船移动

在Assets中创建Scripts文件夹存储新建的Unity脚本,创新新的Unity脚本命名为PlayerController

代码内容:

[System.Serializable]
// 飞船能够位移的前后左右的最远边界
public class Boundary
{public float xMin, xMax, zMin, zMax;
}
public class PlayerController : MonoBehaviour
{private float speed = 6f; // 飞船移动的速度private float tilt = -4; // 飞船左右飞行的倾斜率private Rigidbody rig; // 飞船的刚体组件public Boundary boundary; // 边界类void Start(){rig = GetComponent<Rigidbody>(); // 获取刚体组件}void Update(){BasicMove();}public void BasicMove(){// 获取水平轴的输入float moveH = Input.GetAxis("Horizontal");// 获取垂直轴的输入float moveV = Input.GetAxis("Vertical");// 位移方向Vector3 movement = new Vector3(moveH, 0.0f, moveV);// 添加移动的速度rig.velocity = movement * speed;// 限制其在X轴以及Z轴的运动范围rig.position = new Vector3(Mathf.Clamp(rig.position.x, boundary.xMin, boundary.xMax),0.0f, (Mathf.Clamp(rig.position.z, boundary.zMin, boundary.zMax)));// 限制飞船飞行时左右倾斜度rig.rotation = Quaternion.Euler(0.0f, 0.0f, rig.velocity.x * tilt);}
}

PlayerController赋给Player,并在Unity编辑器中修改限制飞行的最远边界如图:

至此,完成了飞船的基础位移。

3.5 创建飞船子弹

3.5.1 创建子弹

在Player下创建空子物体命名为PlayerBullet,在PlayerBullet下创建子物体3D Object —>Quad,调整Rotation为(90,0,0),移除Mesh Collider组件,修改其材质为fx_bolt_orange

然后在PlayerBullet中,添加Rigidbody组件,取消勾选使用重力属性(Use Gravity),添加Capsule Collider组件,修改其朝向(Direction)和半径(Radius)、高度(Height),如下图所示。

3.5.2 子弹自动飞行

创建脚本命名为PlayerBullet,首先制作其自动移动的脚本,并将该脚本赋给PlayerBullet游戏物体。

public class PlayerBullet : MonoBehaviour
{public float bullet_speed; // 子弹飞行速度private Rigidbody rig; // 子弹刚体组件void Start(){rig = GetComponent<Rigidbody>();rig.velocity = transform.forward * bullet_speed; // 给子弹刚体添加一个初速度}
}

在编辑器中,为PlayerBullet的bullet_speed赋初值为20。

3.5.3 添加子弹音效

为了让子弹射出时有音效,为PlayerBullet添加Audio Source组件,将AudioClip设置为Weapon_Player,记得要勾选Play On Awake,这样在子弹被调出时就会自动播放射击音效。

3.5.4 制作子弹预制体

预制体是一个存储在项目资源文件夹中的文件(通常以.prefab为扩展名),它包含一个或多个游戏对象的完整配置。这包括对象的Transform、组件、子对象和属性设置。在游戏开发中,许多游戏物体需要重复出现。如果每次手动创建,会浪费大量时间,且修改时容易出错。预制体解决了这个问题:修改预制体源文件后,所有实例会自动更新,确保一致性。

本项目中的子弹就需要制作为预制体。

(1)在Assets下创建Prefabs文件夹,用于存储项目中所有的预制体。然后将PlayerBullet游戏物体拖到该文件夹下,当PlayerBullet变成了蓝色图标,即表示其成为了预制体。

(2)将Player下的PlayerBullet子物体删除,后续要调用PlayerBullet将以预制体的方式调用其副本。

3.6 飞船射击

(1)首先需要添加子弹在飞船上的生成点,给Player添加空物体,并命名:ShootPosition,修改其Z轴的位置为0.7。

(2)给PlayerController.cs脚本,增添在ShootPosition位置生成子弹的功能。

注意:凡是新增的脚本均在注释出标出新增二字,新增的方法也在其上方注释标出新增

[System.Serializable]
// 飞船能够位移的前后左右的最远边界
public class Boundary
{public float xMin, xMax, zMin, zMax;
}
public class PlayerController : MonoBehaviour
{private float speed = 6f; // 飞船移动的速度private float tilt = -4; // 飞船左右飞行的倾斜率private Rigidbody rig; // 飞船的刚体组件public Boundary boundary; // 边界类public Transform shootPosition;// 新增 飞船子弹射击点public GameObject playerBullet;// 新增 飞船子弹预制体void Start(){rig = GetComponent<Rigidbody>(); // 获取刚体组件}void Update(){BasicMove();// 调用控制飞船移动方法ShootBullet();//新增 调用射击子弹方法}public void BasicMove(){// 获取水平轴的输入float moveH = Input.GetAxis("Horizontal");// 获取垂直轴的输入float moveV = Input.GetAxis("Vertical");// 位移方向Vector3 movement = new Vector3(moveH, 0.0f, moveV);// 添加移动的速度rig.velocity = movement * speed;// 限制其在X轴以及Z轴的运动范围rig.position = new Vector3(Mathf.Clamp(rig.position.x, boundary.xMin, boundary.xMax),0.0f, (Mathf.Clamp(rig.position.z, boundary.zMin, boundary.zMax)));// 限制飞船飞行时左右倾斜度rig.rotation = Quaternion.Euler(0.0f, 0.0f, rig.velocity.x * tilt);}//新增 射击子弹的方法public void ShootBullet(){//如果摁下了空格键if (Input.GetKeyDown(KeyCode.Space)){//实例化子弹,位置在ShootPosition,无旋转Instantiate(playerBullet, shootPosition.position, Quaternion.identity);}}
}

(3)在编辑器中,给新增公开的变量shootPositionplayerBullet指定赋值。

这时候运行就可以通过点击空格键,射击子弹了,子弹生成出来后会自动向前方飞行并且自动播放音效。

但是存在一个问题,就是实例化出的子弹会一直存在于场景中,并且持续飞行,就这会导致子弹不停生成,也在不停的消耗性能,所以需要在子弹离开指定区域后,自动销毁掉。

4 制作物体飞行边界

4.1 创建边界

(1)在场景中创建Cube,命名为:Boundary,因为作为透明边界,无需渲染其模型所以,移除掉Mesh Filter和Mesh Renderer组件,仅保留Transform和Box Collider。

(2)修改Boundary的大小,并且勾选Box Collider的Is Trigger作为触发器使用。

4.2 制作销毁脚本

所有的游戏物体一旦离开边界范围,即销毁。创建脚本 ExitDestroy,作为组件赋给Boundary游戏物体。

public class ExitDestroy : MonoBehaviour
{//凡是离开边界的物体,通通毁灭private void OnTriggerExit(Collider other){Destroy(other.gameObject);}
}

4.3 添加边界标签

点击Tag—>Add Tag…添加Boundary标签,并给Boundary游戏物体指定该标签。

5 制作敌人

敌人大致包括以下几种:

陨石:自身旋转,向下固定移动,不会攻击,碰到玩家会爆炸

敌方飞船:向下移动,会发射子弹攻击,子弹和飞船碰到玩家都会爆炸

5.1 制作陨石

5.1.1 创建陨石物体

(1)将Models下的Asteroid_01模型拖入场景,右击,选择Prefab—>Unpack解包,方便后续制作。

(2)给陨石添加RigidBody组件,取消勾选Use Gravity,以防止陨石掉落地。Angular Drag设置为0,用于忽略空气阻力。

(3)添加Sphere Collider组件,勾选,IsTrigger,用于产生触发操作,修改其Radius为0.7。

5.1.2 陨石自旋转

创建控制陨石移动的脚本,命名为:AsteroidController ,书写自身随机旋转和移动的代码

public class AsteroidController : MonoBehaviour
{private float rotationSpeed = 60.0f; // 随机旋转的速度系数private float moveSpeed = 3.0f; // 向后移动的速度private Vector3 randomRotationAxis; // 随机旋转轴void Start(){// 初始化一个随机旋转轴randomRotationAxis = Random.insideUnitSphere.normalized;}void Update(){// 物体自身随机旋转transform.Rotate(randomRotationAxis, rotationSpeed * Time.deltaTime);// 物体向后移动(沿世界坐标Z轴负方向)transform.Translate(0, 0, -moveSpeed * Time.deltaTime, Space.World);}
}

5.1.3 添加陨石标签

点击Tag—>Add Tag…添加Asteroid标签,并给Asteroid_01游戏物体指定该标签,方便后期做触发检测。

5.1.4 制作其余两种陨石

复制Asteroid_01,粘贴两个,分别命名为Asteroid_02、Asteroid_03,依次修改其Mesh模型和Materials材质,如下图:

5.1.5 制作陨石预制体

将制作好的三个陨石,分别拖入Prefabs文件夹中,制作为预制体,随后就可以把场景中的三个陨石删除,后续需要生成陨石,只需要调用预制体即可。

5.1.6 修改PlayerBullet脚本

(1)修改脚本使玩家子弹击中陨石后,可以爆炸并销毁。

public class PlayerBullet : MonoBehaviour
{public float bullet_speed; // 子弹飞行速度private Rigidbody rig; // 子弹刚体组件public GameObject explosionAsteroid; // 新增 陨石爆炸特效void Start(){rig = GetComponent<Rigidbody>();rig.velocity = transform.forward * bullet_speed; // 给子弹刚体添加一个初速度}//新增 触发事件 private void OnTriggerEnter(Collider other){//如果碰到了陨石if (other.tag == "Asteroid"){// 实例化爆炸特效,并销毁自身和陨石Instantiate(explosionAsteroid, transform.position, Quaternion.identity);Destroy(other.gameObject);Destroy(gameObject);}}
}

(2)指定爆炸特效为Explosion_Asteroid预制体,这样后续玩家射击子弹,触碰到陨石就会爆炸并销毁。

5.2 制作敌方飞船

5.1.1 创建敌方飞船物体

(1)在场景中创建空物体命名为Enemy,将EnemyShip模型作为子物体放置其下,修改EnemyShip的Y轴旋转为180,使其面向玩家。

(2)将Engines_Enemy粒子特效作为子物体放置在Enemy下。

5.1.2 添加碰撞体和刚体

给Enemy游戏物体添加Capsule Collider碰撞体和刚体组件,取消刚体的重力,修改碰撞体的范围和位置,做到基本贴合即可,勾选Is Trigger,作为触发器使用。

5.1.3 添加敌人飞船标签

创建新标签:EnemyShip,并指定Enemy游戏物体为此标签,用于后续触发检测。

5.1.4 制作敌人子弹

(1)创建新的脚本:EnemyBullet,书写移动和击中玩家时的代码。

public class EnemyBullet : MonoBehaviour
{public float bullet_speed; // 子弹飞行速度private Rigidbody rig; // 子弹刚体组件public GameObject explosionPlayer;//玩家爆炸特效void Start(){rig = GetComponent<Rigidbody>();rig.velocity = transform.forward * bullet_speed; // 给子弹刚体添加一个初速度}private void OnTriggerEnter(Collider other){if (other.tag == "Player"){Instantiate(explosionPlayer, transform.position, Quaternion.identity);Destroy(other.gameObject);Destroy(gameObject);}}
}

(2)在Prefabs文件夹中,复制粘贴一份预制体PlayerBullet,命名为EnemyBullet,移除其身上的PlayerBullet的组件,将上述写好的EnemyBullet赋上。

  • 给速度赋值-10,给玩家爆炸特效指定Explosion_Player预制体
  • 修改其音效为敌人武器Weapon_Player音效

5.1.5 修改子弹贴图

(1)复制粘贴fx_bolt_orange,命名新的为:fx_bolt_blue,修改其贴图为Texture—>fx_lazer_cyan_dff,即蓝色光线。

(2)双击EnemyBullet预制体,进入预制体修改界面,修改子物体QuadMaterialsfx_bolt_blue即可。

5.1.6 敌方飞船移动和自动射击

(1)创建EnemyController脚本,控制敌方飞船的向前移动、自动射击、碰到玩家爆炸。

public class EnemyController : MonoBehaviour
{private float moveSpeed = -3.0f;//移动速度private Rigidbody rig; // 刚体组件public Transform shootPos; // 子弹生成位置public GameObject enemyBullet;//敌人子弹预制体[Header("射击间隔时间")]public float fireRate; // 两次射击间隔时间private float nextFireTime; //下次射击时间void Start(){rig = GetComponent<Rigidbody>();rig.velocity = transform.forward * moveSpeed;// 初始化下次射击时间 nextFireTime = Time.time + fireRate;}void Update(){HandleShooting();}public void HandleShooting(){// 检查是否到达射击时间if (Time.time >= nextFireTime){// 发射子弹Shoot();// 更新下次射击时间nextFireTime = Time.time + fireRate;}}//射击事件public void Shoot(){// 实例化敌人子弹在指定位置Instantiate(enemyBullet, shootPos.position, Quaternion.identity);}
}

(2)给Enemy游戏物体创建空物体命名为ShootPosition,作为子弹生成位置,修改其Z轴位置为-1.3。

(3)将EnemyController.cs脚本赋给Enemy游戏物体,并将公开的变量赋值。

这里的射击间隔时间,越大射击很慢,越小射击越快

5.1.7 修改PlayerBullet脚本

(1)修改PlayerBullet脚本,使玩家射击的子弹也可以击中敌人。

public class PlayerBullet : MonoBehaviour
{public float bullet_speed; // 子弹飞行速度private Rigidbody rig; // 子弹刚体组件public GameObject explosionAsteroid; // 陨石爆炸特效public GameObject explosionEnemy; //新增 敌方飞船爆炸特效void Start(){rig = GetComponent<Rigidbody>();rig.velocity = transform.forward * bullet_speed; // 给子弹刚体添加一个初速度}private void OnTriggerEnter(Collider other){if (other.tag == "Asteroid"){Instantiate(explosionAsteroid, transform.position, Quaternion.identity);Destroy(other.gameObject);Destroy(gameObject);}// 新增 如果触碰到了敌方飞船if (other.tag == "EnemyShip"){Instantiate(explosionEnemy, transform.position, Quaternion.identity);Destroy(other.gameObject);Destroy(gameObject);}}
}

(2)给PlayerBullet预制体的ExplosionEnemy添加指定爆炸特效Explosion_Enemy

5.1.8 制作敌方飞船预制体

至此,敌方飞船的基本功能已完备,将敌方飞船Enemy拖入Prefabs文件夹中,作为预制体。

随后删除场景内的Enemy即可。

5.3 玩家接触陨石和敌人爆炸

(1)玩家接触到陨石或者敌方飞船均会爆炸,修改PlayerController.cs脚本。

[System.Serializable]
// 飞船能够位移的前后左右的最远边界
public class Boundary
{public float xMin, xMax, zMin, zMax;
}
public class PlayerController : MonoBehaviour
{private float speed = 6f; // 飞船移动的速度private float tilt = -4; // 飞船左右飞行的倾斜率private Rigidbody rig; // 飞船的刚体组件public Boundary boundary; // 边界类public Transform shootPosition;// 飞船子弹射击点public GameObject playerBullet;// 飞船子弹预制体public GameObject explosionPlayer; //新增 玩家爆炸特效void Start(){rig = GetComponent<Rigidbody>(); // 获取刚体组件}void Update(){BasicMove();// 调用控制飞船移动方法ShootBullet();//调用射击子弹方法}public void BasicMove(){// 获取水平轴的输入float moveH = Input.GetAxis("Horizontal");// 获取垂直轴的输入float moveV = Input.GetAxis("Vertical");// 位移方向Vector3 movement = new Vector3(moveH, 0.0f, moveV);// 添加移动的速度rig.velocity = movement * speed;// 限制其在X轴以及Z轴的运动范围rig.position = new Vector3(Mathf.Clamp(rig.position.x, boundary.xMin, boundary.xMax),0.0f, (Mathf.Clamp(rig.position.z, boundary.zMin, boundary.zMax)));// 限制飞船飞行时左右倾斜度rig.rotation = Quaternion.Euler(0.0f, 0.0f, rig.velocity.x * tilt);}//射击子弹的方法public void ShootBullet(){//如果摁下了空格键if (Input.GetKeyDown(KeyCode.Space)){//实例化子弹,位置在ShootPosition,无旋转Instantiate(playerBullet, shootPosition.position, Quaternion.identity);}}//新增 玩家和陨石或者地方飞船接触时,均会爆炸private void OnTriggerEnter(Collider other){if(other.tag== "Asteroid" || other.tag == "EnemyShip"){Instantiate(explosionPlayer, transform.position, Quaternion.identity);Destroy(other.gameObject);Destroy(gameObject);}}
}

(2)给Player游戏物体的ExplosionPlayer赋玩家爆炸特效。

6 爆炸特效的调整

6.1 延迟销毁特效

所有的爆炸特效调用后,会一直存在在场景中,但它们只会在实例化后播放一次,所以当播放完毕后,需要销毁实例化出的特效。

创建DelayDestroy脚本,控制延迟销毁物体。

public class DelayDestroy : MonoBehaviour
{private float delayTime = 2.0f;// 延迟销毁的时间void Start(){Destroy(gameObject, delayTime);}
}

将该脚本赋给所有的爆炸特效。

6.2 添加爆炸音效

给三个爆炸特效分别添加Audio Source组件,并指定对应的音效。

7 随机批量生成敌人

(1)指定在位置区间,随机分批次生成敌人,创建脚本命名为:SpawnEnemy

public class SpawnEnemy : MonoBehaviour
{[Header("敌人设置")]public GameObject[] enemyPrefab; // 敌方飞船和陨石的预制体数组public int initialEnemiesPerWave = 5;// 第一波敌人生成的数量public int enemiesIncrement = 1; // 每波增加的敌人数public int maxEnemiesAtOnce = 10; // 场景中最多同时存在的敌人数[Header("生成位置")]public Vector3 spawnValues = new Vector3(5f, 0f, 10f);[Header("时间设置")]public float startDelay = 2f; // 初始生成延迟public float spawnInterval = 1f;// 单个敌人生成间隔public float waveInterval = 5f;// 波次间隔时间public float enemyCheckInterval = 0.5f; // 检查敌人数量的间隔private int currentWave = 1; //记录当前波次private bool isWaitingForEnemiesClear = false;private int enemiesSpawnedThisWave = 0; // 当前波次已生成的敌人数private int totalEnemiesThisWave = 0; // 当前波次总共需要生成的敌人数void Start(){if (enemyPrefab == null){Debug.LogError("请分配敌人预制体!");return;}StartCoroutine(SpawnWaves());}IEnumerator SpawnWaves(){// 开始等待yield return new WaitForSeconds(startDelay);while (true){// 重置波次计数器enemiesSpawnedThisWave = 0;// 计算当前波次的敌人数totalEnemiesThisWave = initialEnemiesPerWave + (currentWave - 1) * enemiesIncrement;//限定最大生成数量为maxEnemiesAtOnceif (totalEnemiesThisWave >= maxEnemiesAtOnce){totalEnemiesThisWave = maxEnemiesAtOnce;}Debug.Log($"开始第 {currentWave} 波,生成 {totalEnemiesThisWave} 个敌人");// 生成一波敌人while (enemiesSpawnedThisWave < totalEnemiesThisWave){// 等待直到场景中敌人数量少于最大值yield return StartCoroutine(WaitForEnemySlot());// 计算生成位置Vector3 spawnPosition = new Vector3(Random.Range(-spawnValues.x, spawnValues.x),spawnValues.y,spawnValues.z);// 生成敌人Instantiate(enemyPrefab[Random.Range(0, enemyPrefab.Length)], spawnPosition, Quaternion.identity);enemiesSpawnedThisWave++; //当前波次敌人自加1// 等待生成间隔yield return new WaitForSeconds(spawnInterval);}// 等待所有敌人被消灭yield return StartCoroutine(WaitForAllEnemiesDefeated());// 波次完成Debug.Log($"第 {currentWave} 波完成!");// 等待波次间隔yield return new WaitForSeconds(waveInterval);// 增加波次currentWave++;}}IEnumerator WaitForEnemySlot(){// 等待直到场景中敌人数量少于最大值while (GetEnemyCount() >= maxEnemiesAtOnce){yield return new WaitForSeconds(enemyCheckInterval);}}IEnumerator WaitForAllEnemiesDefeated(){isWaitingForEnemiesClear = true;// 等待直到场景中没有敌人while (GetEnemyCount() > 0){yield return new WaitForSeconds(enemyCheckInterval);}isWaitingForEnemiesClear = false;}int GetEnemyCount(){// 查找场景中所有带有EnemyShip、Asteroid标签的物体GameObject[] enemies = GameObject.FindGameObjectsWithTag("EnemyShip");GameObject[] Asteroid = GameObject.FindGameObjectsWithTag("Asteroid");//返回所有敌人数量return enemies.Length + Asteroid.Length;}// 在Scene视图中可视化生成区域void OnDrawGizmosSelected(){Gizmos.color = Color.green;// 绘制生成线Vector3 startPoint = new Vector3(-spawnValues.x, spawnValues.y, spawnValues.z);Vector3 endPoint = new Vector3(spawnValues.x, spawnValues.y, spawnValues.z);Gizmos.DrawLine(startPoint, endPoint);// 绘制起点和终点标记Gizmos.DrawSphere(startPoint, 0.2f);Gizmos.DrawSphere(endPoint, 0.2f);}
}

(2)创建一个空物体命名为:GameController,把SpawnEnemy.cs脚本赋给它,并对变量赋值。

运行如下:

8 场景管理

将游戏场景命名为:GameScene,复制粘贴一份,将新的场景命名为:StartScene,删除StartScene中的物体,保留如下:

8.1 管理StartScene

(1)创建Text文本,调整如下:

  • 修改位置 Y为300
  • 修改宽和高600*200
  • 修改Text文本:游戏名字
  • 文本上下居中
  • 勾选BestFit,将MaxSize改为60

(2)添加一个Button按钮,命名为:Button开始,修改宽高为200*50,修改Button文本为:Start Game,字体大小Fond Size为25。

(3)将Button开始复制粘贴一份,命名为Button退出,并修改Button文本为:Quit。

布局如下:

(4)添加背景音效

给Canvas添加一个Audio Source组件,选定音乐为:Music_Background

8.2 制作点击事件

(1)新建脚本命名为:SceneManage ,主要实现跳转场景和退出游戏。

using UnityEngine.SceneManagement;
public class SceneManage : MonoBehaviour
{public string nextSceneName;//要跳转的场景的名字public void LoadNextScene(){SceneManager.LoadScene(nextSceneName);}public void QuitGame(){
#if UNITY_EDITORUnityEditor.EditorApplication.isPlaying = false;
#elseApplication.Quit();
#endif}
}

(2)将脚本赋给Canvas,将下个场景的名字GameScene填到框里。

(3)给两个按钮添加点击事件。

8.3 配置Build Setting

打开File中的Build Setting,将两个场景拖进去,注意StartScene在前。

完成后,就可以实现场景跳转和退出游戏了。

8.4 管理GameScene

(1)设置失败的Panel面板,内置Text显示结果,两个Button,进行场景加载和结束游戏。

(2)将上述的SceneManage.cs脚本赋给Canvas,将场景的名字GameScene填到框里。

(3)给两个按钮添加点击事件。

(3)在GameScene场景中,创建GameController脚本,赋给GameController游戏物体。

代码如下:

using UnityEngine.UI;public class GameController : MonoBehaviour
{public GameObject endPanel;public Text endText;void Start(){endPanel.SetActive(false);}void Update(){PanleManage();}public void PanleManage(){if (GameObject.Find("Player")==null){endPanel.SetActive(true);endText.text = "YOU LOSE";}}
}

(4)给两个变量赋值。

目前效果如下

9 打包设置

9.1 设置游戏图标和名字

打开Project Settings—>Player,修改游戏名字Product Name为Space Shooter,修改Default Icon为icon_space_shooter纹理贴图即可。 

9.2 游戏打包

(1)打开File中的Build Setting,点击Build。

(2)选择指定文件夹,点击选择文件夹即可。

(3)点击.exe文件即可游玩

http://www.dtcms.com/a/574036.html

相关文章:

  • Guava Cache淘汰算法
  • 门户网站类是什么意思怎么给自己做个网站吗
  • 小朋友做安全教育的网站慈溪做网站什么价
  • 设计一个网站的步骤深汕特别合作区包括哪些地方
  • 2.5 HuggingFace Transformers 库实战
  • 宿州建设企业网站公司做网站的有哪些学校
  • 网络通信的奥秘:HTTP详解 (七)
  • 福建网站建设科技有限公司那些网站做的非常好看的
  • 网站建设老李教学网站商务贸易网站建设
  • 11.5 脚本 本地网站收藏(解封归来)
  • Web APIs 学习第四天:DOM事件进阶
  • 后台网站设计织梦 蓝色 个人网站博客网站源码
  • 余姚网站建设公司wordpress 支付宝免签
  • 仓颉编程语言基础集合类型详解:从Array到HashMap的实战指南(一)
  • 网站负责人姓名wordpress 阿里百秀主题
  • 【C++学习】deque容器
  • 网站程序代码更加精准高效的措施
  • 宁波网站建设h5哪个做网站平台好
  • Apache IoTDB 技术深度解析:存储引擎、查询优化与分布式架构在工业物联网、智慧能源和车联网场景的应用指南
  • rap2部署
  • IOT-VIP——STM32F031K6U6+RS485+显示屏
  • 工业互联网 “云 - 边 - 端” 架构
  • c#网站开发框架深圳网站建设收费
  • MAC电脑上拉取Git仓库的方法
  • 怎样在网做旅游网站顺企网浙江网站建设
  • 时序数据库系列(四):InfluxQL查询语言详解
  • 如何建设专业化的网站全球搜索网站排名
  • Android WebView - loadUrl 方法的长度限制
  • 温州网站推广公司wordpress万能
  • 开题报告之基于SpringBoot框架的在线答题网站的设计与实现