案例预备
针对后面的游戏开发案例做些准备
声音
声音资源
声音是游戏重要组成部分之一,Unity中支持的声音有AIFF、WAV、MP3、OGG等
可以直接将声音资源拖拽到文件夹Assets下,如果点击可以播放声音,意味着在游戏中可以使用
声音资源在代码中的类型是AduioClip,可以使用AduioClip的类型变量使用赋值面板或Resources.Load动态加载得到
Aduio Source-面板设置
声音来源组件也就是声音的来源,在3D游戏中,声音是有距离变化的
- AduioClip:要播放的声音
- Mute:静音
- Play On Awake:游戏启动马上播放
- Loop:循环播放
- Priority:播放优先级,0为最优先,一般BGM为0
- Volume:音量
- Spatial Blend:空间混合,也就是音效为2D、3D还是混合,一般背景音乐才用2D
Aduio Source-常用属性和方法
面板中掺用的属性都是可以直接获取到的,补充几个面板中没有的常用属性和方法:
audioSource.Play():开始播放
audioSource.Stop():停止播放
audioSource.Pause():暂停播放
audio.Source.isPlaying():是否处于播放状态
audioSource.PlayOnShot(audioCilp):播放一个指定的片段且只有一次,主要特点是不会打断当前aduioSource正在播放的音乐,会叠加在一起,并且不会修改,如果重复调用也可以同时播放
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SoundSetting : MonoBehaviour
{
//一般给声音播放器使用的
public AudioClip audioClip;
private AudioSource audioSource;
void Start()
{
audioClip = Resources.Load<AudioClip>("Music/music1");
audioSource = GetComponent<AudioSource>();
//修改clip打断了播放
audioSource.clip = audioClip;
//播放当前clip,从头播放
audioSource.Play();
}
void Update()
{
if(Input.GetKeyDown(KeyCode.P)&&audioSource.isPlaying)
{
//暂停
audioSource.Pause();
}
else if (Input.GetKeyDown(KeyCode.P) && !audioSource.isPlaying)
{
//继续播放
audioSource.UnPause();
}
if(Input.GetKeyDown(KeyCode.C))
{
//切换音乐
audioSource.clip = Resources.Load<AudioClip>("Music/music2");
audioSource.Play();
}
}
}
Audio Listener
AudioSource只是可以发出声音,但是我们可以听到声音是因为有Audio Listener,创建场景时Main Camera游戏物体除了摄像机组件,还有一个Audio Listener组件,多数情况下摄像机的位置也就是玩家的位置,所以声音监听放在摄像机上是多数情况下的选择
这个组件在面板中可以发现它没有任何参数可以设置,还是单纯的作为监听者,但是音乐的3D感,主要取决于AudioSource和Audio Listener的位置关系
导航系统
导航系统介绍
首先来看两个情况:
- 很多网络游戏中都有一个功能,点击地图上的某个位置,角色会自动跑到这个位置
- RTS和Moba类游戏中鼠标右键点击一个位置,角色自动走向这个位置,而且还具备规避障碍物的能力
以上使用的功能就是导航,或者叫做寻路,主要具备两个特点:
- 以最短路径(最小代价)前往目标
- 规避障碍物
导航烘培
导航的前提是需要一张地图,确定玩家什么地方可以去,什么地方不可以去
Navigation导航面板
- 功能:导航面板的主要功能就是规划场景中哪里可以去,哪里不可以去
- 面板:Window->AI->Navigation
导航前需要简单烘培一下地图
1、选择场景中,将地形、场景相关的游戏物体设置为Static模式,这是烘培的前提
2、直接选择子栏目Bake
3、点击Bake按钮
(代理高度和代理半径即表示玩家模型的大小,另外,地图烘培成功后,角色无法移动到地图外)
4、场景中部分区域呈现成蓝色,意味着烘培成功,蓝色就是角色可以前往的地方(Plane上的蓝色区域和Plane的红色材质混合显示成紫色了)
NavMeshAgent组件
场景烘培好后便确定了哪些地方角色可以去,如何进行导航就需要用到游戏物体身上具备NavMeshAgent这个组件,导航代理组件承担具体如何导航的计算
添加这个导航代理组件的游戏物体嘛,身上会增加一个圆柱体形状的碰撞体
- Agent Type:代理类型,在Navigation中添加类型,主要是设置这个角色的尺寸
- Base Offset:碰撞体和角色的高度偏移
- Speed:导航时的最大移动速度
- Angular Speed:导航时的最大旋转速度
- Acceleration:导航刚开始时加速到Speed需要的程度,越大越快
- Stopping Distance:距离终点多远停止
- Auto Braking:勾选后表示到达目标点或距离目标点的距离满足Stopping Distance时自动停止,如果不勾选,即使到达终点,角色也会围着重点转来转去
NavMeshAgent-Obstacle AvoidAnce
障碍回避设置
Radius:碰撞体半径
Height:碰撞体高度
Quality:躲避障碍物的行为质量,质量越高躲避行为越好、越智能(消耗性能越多)
Priority:优先级,范围0~99,0的优先级最高,高优先级的Agent不会与低优先级的Agent进行碰撞
NavMeshAgent常用属性和方法
导航系统的代码相关操作都要先using UnityEngine.AI命名空间
常用方法:
navMeshAgent.SetDestination(vector3):设置导航,填写目标位置
常用属性:
navMeshAgent.isStopped:获取和修改,是否停止导航
Navigation面板
Agent代理设置
对需要进行导航的角色进行分类,默认有一个Humanoid,也就是人类
主要设置:
- name:名称
- Radius:半径
- Height:高度
- Step Height:能上多高的台阶
- Max Slope:能上多陡的坡度
Areas区域设置
在游戏场景中,不同区域的行走代价是不同的,比如陆地肯定比沼泽地走起来快,所谓代价就是移动成本,代价越高的地方,导航系统会尽可能绕过去
Areas面板主要用来设置不同区域的不同成本,但是这里只有预先设计好不同区域类型的成本,并不同直接设置场景中具体“这个游戏物体属于什么区域”
Bake烘培
这个面板中有很多Agent相关的设置,实际上是在设置一个最极限的情况,可以理解成需要导航的最小单位,设置等同于Agent面板
点击Bake生成导航网络
Object物体设置
Scene Filter:场景过滤,主要影响层级面板中的显示
选中一个游戏物体后,Object面板中会出现一定的变化,只有静态物体可以进行Navigation Areas(导航区域)的设置,这也意味着只有静态物体可以烘培到导航网络中
Navigation Areas:设置所选游戏物体的区域设置,可以多选游戏物体
NavMeshObstacle组件
导航障碍物
目前我们的导航网络,是通过将地形游戏物体设置为静态模式,然后导航烘培实现的,但是游戏中可能存在这种情况:RTS或Moba类游戏中,可能因为玩家的建造、角色的技能,出现了一个障碍物,我们移动角色的时候,需要避开这些障碍物
NavMeshObstacle
这个组件比较方便,直接给游戏物体添加即可
参数:
- Shape:形状,类似碰撞体的蓝色外框,但是实际上并不具备碰撞体的特性,可以穿模,仅仅用于导航计算上
- Center:中心点
- Size:尺寸
- Carve:勾选了就会实时计算最优路径并导航前进;不勾选的情况,该障碍物只是阻挡了物体前进路线,并没有改变物体导航网格的路径(导航只会不断的计算最短路径,依旧认为此条路径是最短的,不会重新计算路径),物体不会绕过该障碍物进行导航
粒子特效
在大多数游戏中,粒子是游戏特效使用最多的部分,比如:
- 刀光
- 火焰
- 下雨
- 下雪
笔记内容为如何使用Unity提供的粒子,而不是制作粒子(当然,Unity也提供制作粒子的操作)
粒子系统
在层级面板中右键Create->Effects->Particle System,可以创建一个例子游戏物体
这个游戏物体身上也有一个Particle System组件,基于这个组件可以完成粒子的创作;有几个重要参数关注一下:
- Duration:持续时间,指多少秒后不再发射粒子,但是不会导致已经发射的粒子消失
- Looping:是否循环
- Start Lifetime:粒子发射出去后的存活时间
- Play On Awake:是否立刻播放粒子
- Stop Action:结束事件,选择Destroy则播放完毕立刻销毁
粒子资源
粒子资源本质上就是一个游戏物体,这个游戏上存在粒子组件而已,而且在绝大多数情况下,都是游戏物体实例化后立刻播放粒子效果,播放完毕再利用Stop Action立刻销毁
地形系统
游戏地形
在3D游戏中,大多数情况下角色都是站在地面上的,这些地面大致可以分为两种制作方法,一种是建模软件(如3DMAX、MAYA、Blender等)制作的模型导入Unity中来使用过,另一种是使用Unity得地形系统制作而成
作为一个缺乏艺术细胞的宅男,本人主要研究的是第二种方法,使用Unity地形系统:
- 绘制地形起伏形成山脉
- 点缀花草树木
绘制地形
创建地形
层级面板中右键->3D Object->Terrain 创建地形游戏物体
地形游戏物体:
- Terrain:地形组件,基于这个组件制作、形成地形
- Terrain Collider:地形碰撞体,类似其他的碰撞体组件,让角色可以站在上方,并且不需要去设置,自动根据地形外观生成
地形流程
- 设置地形基础高度、大小
- 设置地形细节高度
- 设置地形材质,如草地、沙漠等
- 设置树木
- 设置花草
- 设置风
地形基础设置
Terrain组件中有五个板块:
- 地形扩容
- 绘制地形
-
- Set Height:将地形刷到指定高度
-
- Smooth Height:让地形高度变化更平滑
-
- Stamp Terrain:刻章
-
-
- Subtract:勾选则嵌入刻章,否则凸起
-
-
- Paint Holes:挖洞
-
- Raise or Lower Terrain:提升或降低地形高度,选择后需要在下方Brushes中选择一个笔刷,然后直接在场景点击提升高度、Shift+点击则是降低高度
-
- Paint Texture:绘制纹理贴图
-
-
- 在Terrain Lyaers中添加贴图层,然后使用画面进行绘制即可
-
- 绘制树木
- 绘制细节
-
- 花草的绘制
- 设置地形基础高度、大小(设置面板中的网格分辨率Mesh Resolution)
-
- Terrain Width:地形宽度
-
- Terrain Length:地形长度
-
- Terrain Height:地形高度(Y轴方向地形高度限制)
- Terrain Height:地形高度(Y轴方向地形高度限制)
花草树木
添加花草
地形组件中第四项,添加花草
- 在Details中添加花草模版
- 选择画笔,设置画笔属性:
-
- BrushSize:画笔大小
-
- Opacity:透明度
-
- Target Strength:强度
- 点击刷草,Shfit+点击移出草
- 如果距离花草太远,会看不到草,不方便操作,可以在地形组件中设置模块->Tree&Details Object->Detail Distance调整
添加树木
地形组件中第三项,添加树木
和添加花草非常接近,在Trees中先添加好树的模版,然后设置画板刷即可
- Tree Density:树的密度
- Tree Height:树的高度,可以随机一个范围
- Lock Width to Height:保持比例
- Random Tree Rotation:随机树的旋转
- Color Variation:颜色变化幅度,不可能一片树林中的树都一个颜色
风场组件
游戏里的风
很多游戏中都可以感受到风的存在,但是我们是通过摇摆的树、移动的云等等细节来感受到风的存在的,即使是真的看到一些类似龙卷风的存在,也是通过粒子效果来产生的
Unity中我们是通过让花草树木进行摇摆(可以加上风的音效)来达到风的效果
- 层级面板中右键->3D Object-> WindZone
-
- Directional:基于方向,也是全局的,没有位置问题,但是旋转有效
-
- Spherical:球形,边缘地区风力会衰减
- Main:主要的风力,轻微变化的风压
- Turbulence:湍流的风力,产生快速变化的风压
- Pulse Magnitude:脉冲幅度,随着时间变化的风量
- Pulse Frequency:脉冲频率,风向改变的频率
场景加载
游戏场景切换
很多时候我们并不在一个场景里面完成所有的事情,需要根据需要来划分场景,比如登录场景、游戏大厅,战斗场景、副本场景等
场景就是Unity中的Scene,需要控制的是:
- 场景切换
- 数据保留
场景加载
场景切换的前提:该场景必须被打包,也就是File->Build Setting 这种将场景拖拽进Scenes in Building,排序第一的场景就会作为游戏开始的场景
完成场景的切换:
- 命名空间:using unityEngine.SceneManagement;
- 加载场景:SceneManager.LoadScene(),多个重载方式
-
- int:场景编号
-
- string:场景名称
数据保留
场景切换,会导致前面一个场景的全部游戏物体都销毁,但是实际开发中,我们的角色属性等信息都需要保留且代入到新的场景
- GameObject.DontDestroyOnLoad(object):加载场景不销毁
-
- object:一般直接使用gameObject,即可将整个游戏物体以及数据代入到下一个场景
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class SceneSwitch : MonoBehaviour
{
public string name = "Test";
public bool life = true;
void Start() {}
void Update()
{
if(Input.GetKeyDown(KeyCode.Z))
{
GameObject.DontDestroyOnLoad(gameObject);
SceneManager.LoadScene("MountainGroup");
}
}
}