这段时间也是发生了不少事情,借疫情的机会我也杂糅着学了不少Unity的东西,越是保持着我之前的“用到不懂再查”的心态,就越是感受到知识缺乏体系的局限性。于是这里把最近的一些小笔记总结起来,然后我一方面是我要来搞论文的事情,另一方面也是希望自己尽量系统点学习这些东西,所以这篇以后可能又要安静一段吧。
由于是我的一些总结的小笔记,且我所说是杂糅着学到的,再加之略去了一些细节,再再加之我是从OneNote中大概整理出来的,所以这次可能会比以往更加杂乱无章。
用PlayerPrefs存档
- unity3d提供了一个用于本地持久化保存与读取的类——PlayerPrefs。工作原理非常简单,以键值对的形式将数据保存在注册表中,然后程序可以根据这个名称取出上次保存的数值。
- 不建议用,最好只用来保存用户设置之类的小东西
- PlayerPrefs类支持3中数据类型的保存和读取,浮点型,整形,和字符串型。
- SetInt();保存整型数据;
- GetInt();读取整形数据;
- SetFloat();保存浮点型数据;
- GetFlost();读取浮点型数据;
- SetString();保存字符串型数据;
- GetString();读取字符串型数据;
- HasKey();查看所需的数据键是否存在;
- Save();保存当前的数据。
用Serializable存档
- 更加推荐的存档方法
- 通常可以保存在Application.persistentDataPath里
- Application.persistentDataPath 则是在C:Users*AppDataLocalLow**
- 首先要准备一个自定义的存档元素类,一方面注意有些对象数组之类要进行类内初始化
- 另一方面注意自定义的类也必须是支持了[System.Serializable]才能被序列化保存
- 方法是在自定义的类最上方加上[System.Serializable]
- 然后使用二进制格式器和文件流将二进制序列化的类写到文件中如:
- BinaryFormatter bf = new BinaryFormatter();
- FileStream file = File.OpenWrite(Application.persistentDataPath "/save.dat");
- bf.Serialize(file, save);
- 这里的FileStream 来自System.IO,BinaryFormatter 来自System.Runtime.Serialization.Formatters.Binary
- 读取则类似于写入,使用Deserialize(file)
- 要注意通常来说这种做法是在运行中维护一个存档类来管理各种数据的自动保存和写入,然后先写入到内存的存档对象中,等到关键节点时才写入硬盘减少读写次数。
- 为了维护内存的存档类唯一且操作方便,可以用static来修饰
IEnumerator协程延时
- 触发协程函数用:StartCoroutine(function)
- 目标函数的类型为:IEnumerator
- 返回语句用:yield return new WaitForSeconds(waitTime)
- 必须要return,可以return多次,但似乎会导致重复触发
- Yield return 0可以达成类似通常程序的逐句执行效果
数据平滑改变SmoothDamp
- 分为Mathf.SmoothDamp和Vector3.SmoothDamp,两者效果类似 在周期性调用的函数中使用这个函数来让目标数据平滑变化
- 参数(now, target, ref speed, time),要注意这里的now是不断变动的实时数,speed是引用格式,开始的时候一般为0,时间有时不太准
- 如果使用SmoothDamp作为数据逼近,快到的时候用一个范围差的判断来结束逼近会比较好,范围比较小的时候不会看出来
触摸操作Input.Touch
- touchCount能返回当前有多少手指触摸着
- TouchPhase有几种触摸方式,其中drag是包含长按的
- 要通过deltaposition来得到变化的位置,然后进行差值变化
- GetTouch(0)相当于左键,Input.GetTouch(0).phase是类型
过场动画Timeline
- Timeline的特点是可以操作多个物体的动画,并且有非常方便的调度系统
- 配合Unity的插件Cinemachine可以做出非常专业的过场动画或一些多物体协作的动画
- 但是Timeline若不深一步写入脚本就只能纯粹调度多物体动画了
- 物体的脚本也可以作为一个clip像动画一样插入想要的地方调用
- Timeline中可以插入的脚本是比较特殊的脚本,插入后会显示在Playable Track中
- 一个可插入的包括两个CS文件,一个是继承了PlayableAsset的可序列化类,通过创建PlayableAsset类可自动生成一份
- 它是需要调用的主要部件,其所需的对象变量,若是内置类型则可直接使用,若是自定义类型则需要用ExposedReference<>声明
- 然后在使用时通过重写PlayableAsset的public override Playable CreatePlayable(PlayableGraph graph, GameObject go)工厂方法来操作
- Resolve(graph.GetResolver())是关键的从接下来要说到的脚本获取ExposedReference的对象的引用的方法
- 然后是另一个脚本,继承自PlayableBehaviour,这是表示这个脚本的属性可以在editor中直接更改并调用
- 这个脚本是用来被Timeline操作然后调用上一个脚本的,右键选择PlayableBehaviour可以自动生产
- 自动生成的脚本含有多个重写函数,通过函数名都可以大概明白其含义,如果是想要用来显示字幕,则一般用到里面的OnBehaviourPlay和OnBehaviourPause
- 最后写完这两个文件后,和动画一样按照提示插入组件即可,在监视器中改变dialogStr就可以改变字幕了
动画机Animator
- 动画机是一个控制动画Animation播放的状态机
- 是从Entry进入并按照transition切换的
- 根据有条件的transition改变当前播放的动画
- 可以调整动画切换时的条件state,这样代码中无需使用生硬的play来控制动画,而是可以托付一些属性变量来控制动画
- 可调整动画切换时的淡入淡出(结点变换型的动画则是在两帧中加入了合适的插值)
- Has Exit Time属性决定了动画切换时是否等到当前动画播放完成再切换到另一个动画,如若是需要可以时刻打断的动画则需要取消勾选
动画Animation
- 保存着单独一段的动画
- 动画的录制类似Flash,在时间轴操作属性增加想要的关键帧,帧与帧之间会由Unity自动补全
- 可以点击红点“录制”更加方便地改变属性
- 当前已经被加入录制的属性在监视器中会被标识为蓝色,录制中则会变成红色
- 动画可以加入动画事件在帧中,这可以调用符合下面需求的函数 1)最多只能接受一个参数 2)参数的类型必须是Int, Float,String, Object中的一种
- 自定义的动画事件会出现在可选的事件列表的最末
- 动画事件的文件需要绑定在动画物体上
- 动画多在脚本中用Play播放Rebind重播
- 要注意动画要勾选好是否loop
- 动画组件中有一项Apply Root Motion,这一项是影响动画的属性变化是否影响对象本身的真实情况,如当勾选此项时,人物动画中往前走对象坐标就会往前改变,若不勾选的话动画则不印象真实属性
- 通常把所需的声音输出到AudioMixer再输出给玩家
- AudioMixer中我们可以加入各种后期效果,对声音进行增益或削减
- 这样处理的一大好处是游戏中调整音效,音乐音量常常只是在调整混音器的增益
- 但是要注意混音器的音量并不是线性的而是以DB为单位的,要处理好其改变
Unity预编译器
- 类似C 也有一些预处理器,而Unity自带了如下的一些标识
- 这样我们使用如
来处理
- 要注意Editor和其他的属性是会重叠出现的,所以若是想判断当前是editor需要将此判断放在最后一个判断以覆盖其他
UI们
- UI必须需要有画布(Canvas)等组件才能绘制,建议直接创建一个内置的UI组件来得到所需的其他组件
- 建议Canvas之类的挂载在统一的父组件上
- Canvas需要选取渲染模式决定UI要渲染在什么地方,屏幕空间-相机中是常用的选项,这保证UI总在相机拍摄到的画面中
- CanvasScaler则决定了UI的比例,让UI在各种分辨率和不同的画面比例下尽可能显示的和想象的相近
- GraphicRaycaster则是由于UI是用射线检测来判断是否选中的,所以这个组件用于决定射线的遮挡
- 而对于UI组件本身,关键则是CanvasRenderer负责渲染,RectTransform负责定位
- 其中RectTransform是普通的Transform的进阶,其定位是相对位置模式,一切坐标以用父对象为基准设置的轴心点来设置,下图可以直观地看出各个轴心的位置,最后一个是四周拉伸,按Alt键还能看到轴心对齐模式的内容
- 还有一点是UI组件的响应依赖于EventSystem,需要场景中至少一个EventSystem才能正确响应UI事件
- UI也是可以且很需要用动画来增色的
文字TextMeshPro
- Unity自带的UGUI的文字渲染非常糟糕,文字常常是模糊的,需要通过调高字号再缩小文字的方式来得到清晰的文字渲染
- Unity后来自带了一个很流行的插件TextMeshPro可以自动做好文字渲染的问题,且带来了很多好用的特效如文字阴影
- 这个插件几乎是渲染文字必备的,但是这个插件原生并不支持中文
- 需要中文的话需要去网上找到可用的中文字体导入到插件中使用
ScrollRect滚动区域
- 可以很自然地用来显示超过画面比例的对象
- 尤其适合用来显示列表,道具库之类
- 设置好Viewport即显示区域
- Content是需要显示的内容
- Content的子物件会是显示的主要内容
- 通过给Content增加LayoutGroup和SizeFitter可以很自动地设置好滚动区域的大小
- 其中有很多对其选项行列数之类,熟悉后非常方便
- 也可以用这个组件来做滚动的文字显示区域,道理一样将物件大小调到比Viewport大就可以滚动了
导出工程到Android
- Unity导出到Android实际上很简单
- 首先打开Edit-Perference-ExternalTools加载所需的SDK之类
- 可以自定义想要的版本,也可以用UnityHub下载
- 然后在ProjectSettings-Player里设置好软件的公司名,项目名,版本号,图标等
- 最后Build即可,可能会遇到Gradle问题,我遇到的问题一个是无法下载需要去配置文件中更改下载源,另一个是当改变gradle版本时可能需要将手机上的旧版本游戏卸载再安装新打包的游戏