|
【超长预警,万字警告】
Junior Programmer 是 Unity 的官方学习网站(不是中国特供的那个)里,由官方提供的免费教程之一。属于初始教程系列的第二个。
其实之前也用过这个网站,当时学的是 Unity Essential,是初始系列的第一个。
话不多说,直接开始学。
4/29 随笔:靠,本来以为一篇文章就能结束,结果发现比想象中多的多好多
4/30 随笔:好像勉强也可以写进一篇文章里
5/1 随笔:不行,一篇文章还是不够。Junior 这么猛的吗。
1. Create with Code 1
比较简单,随便看看即可。都是以前学过的很基础的代码。
2. Create with Code 2
2.1 声音和效果
2.1.1 跳跃力
先导入素材,动画部分会有位置报错,无视。删掉 sample scene。进入素材提供的 scene。
2.1.1.1 Sprite Renderer
进入后可以看到一个背景图片,点一下图片,可以看到有一个 sprite renderer 组件。
作用:
以前虽然也用过,但是没有仔细介绍过,都是稀里糊涂的加上就完事了。
Sprite Renderer 主要是让图片能够在场景上显示出来,能够被看见。对 2D 游戏尤其重要。3D 偶尔用到图片(诸如这次)的时候才会用到。
2.1.1.2 加上跳跃力
很简单,就简单说一遍流程:
- 拖动人物到 hierarchy。设置 rotation y 为 90,使得人物面向右方。
- 人物命名为 Player,加上 rigidbody 和 box collider。
- 在 Scripts 文件夹里创建脚本名为 PlayerController,拖到人物上。(如果直接在人物里添加组件,脚本文件会放到最外层文件夹,不利于文件位置管理)
- 创建一个 RigidBody 类型的私有变量,起名 playerRb。在 start 里赋值。
- 加上根据空格判断是否跳跃。
中间遇到一个 bug,unity editor 一直 hold on busy,原因是项目路径上有中文。 2.1.1.3 AddForce
跳跃这里使用 AddForce。
- 第一个 Vector 参数可以用 Vector3.up 语法糖,相当于 Vector3(0,1,0)。
- 其实 AddForce 还可以接受一个 ForceMode 参数,这里我们选用比较适合跳跃的 ForceMode.Impluse。
2.1.1.4 改进跳跃力和重力
先把跳跃力变成变量暴露出来,方便调整,这个没什么好说的以前讲过。
然后重点是重力,重力调整也很简单,rigidbody 有一个 gravity 属性,调整即可。
- public 一个 float 变量,作为重力修改系数。
- 在 start 里,调用 Phsics.gravity 乘上这个修改系数来改变重力。这样可以方便调整重力了。(注意 inspector 里的那个是质量不是重力,别眼花了)。并且重力也不是属于某个 rigidBody 的属性,而是一个作用于该 scene 上所有 rigidbody 的值。
选用系数而不是绝对值可以比较直观的感觉到变化,毕竟你也不知道多少值算重多少算轻。
然后在游戏模式下调整到比较合适的参数即可。
2.1.1.5 防止无限跳
简单,略过。判断一下是否在地面上即可。
2.1.1.6 障碍物
- 使用素材里的一个 prefab 障碍物到场景中,修改一下。拖动到自己的 Prefabs 文件夹里,变成一个新的自己的 prefab。
- 加上一个脚本起名为 MoveLeft。
- 在脚本里使用 transform.translate 来进行移动,其中也可以用到 Vector3.left 语法糖。
- 把 MoveLeft 也赋给背景,造成人物在移动的假象。
2.1.1.7 Spawn Manager
接下来我们用 Spawn Manager 来实例化 Prefab。和其他 Manager 一样,新建一个空物体,挂载一个叫脚本。脚本代码如下:
在游戏开始的时候,在 SpawnPosition 上实例化一个障碍物。旋转角度和 prefab 里的一致。
2.1.1.8 间隔安置 prefab
修改 SapwnManager 代码如下:
- 把安置功能单独拎出来。再在 Start 里生成一个 InvokeRepeating。
- 参数作用顾名思义即可。
然后去 rigidbody 限制一下人物的旋转和移动,免得人物乱跌倒。
2.1.2 让世界更真实
2.1.2.1 无限背景图
背景图复制可以做到一样的事,但是并不合理,很冗余。 只需要有一个前后对接并复制一次的背景图。待到进行到第一个和第二个背景图交接处,重置背景图位置到最开始的位置即可。
- 先给背景图加一个 boxCollider,以便我们读取背景图大小。
- 代码如下:
要点:
- 生成变量的时候是 boxCollider 不是 collider,不然没有 size 属性。
- _startPosition 是一个 Vector3 而不是 float,因为没法给 transform.position.x 单独赋值。储存一开始的整个 position 方便之后赋值。
- _repeatWidth 是背景图的一半长度。
- 判断重置背景的时候用的是 < 而不是 == ,因为用 == 几乎不可能那么巧刚好那一帧就一起重合了。(因此理论上这还不够完美,如果是两个背景 Object,在走到第二个背景的时候把第一个背景拼接到后面才是完美解)
2.1.2.2 游戏结束
很简单,都是以前学过的东西,当撞到障碍物后,停止人物,障碍物,背景的移动。并停止放置障碍物。
此外,障碍物调出视野外的时候,也需要销毁。
2.1.3 动画
可以去人物自带的 controller 里看一下。 双击动画可以看到实例动画,或者点击 transition 可以看到动画之间的转变。
2.1.3.1 设置默认动画
我们想让人物一开始就跑。因此直接在动画参数里设置 speed_f 为 1。因为 transition 里写的是超过 0.25 就会跑。
但是实际游玩会发现,人物一开始还是会有一瞬间的闲置动画。因此我们要把跑动的动画设置为默认状态。
不过人物跑动速度似乎还是慢了一点,和背景比起来的话。其实我们可以去 inspector 里,改变动画的速度。
2.1.3.2 跳跃动画
看一下 animator 可以看到控制跳跃的是 Jump_trig,因此我们在代码里调用一下 SetTrigger 即可。
关于 trigger 的机制,之前有讲过,但不是特别清晰。这里有一个文章举的例子很浅显易懂。
2.1.3.3 死亡动画
简单。先看一下条件是哪些,然后代码里触发即可。
2.1.4 粒子和音效
在导入素材中有一些粒子,可以拖到 scene 里看一下,会发现场景右下角有一个工具框用来调试粒子效果。inspector 里也有很多巨多设置来控制粒子效果。 这里就把粒子速度调快一些 Velocity over Lifetime -> Speed Modifier。
然后把粒子拖到人物上,成为其子物体。
2.1.4.1 播放粒子动画
和 Animator 一样,在代码里引用 ParticleSystem 类型后,调用 Play 方法。
这里先导入一个爆炸粒子,当人物碰撞后播放。
2.1.4.2 人物奔跑粒子动画
添加一个人物跑动的粒子。选中 Play On Awake 因为我们确实要一开始就播放。 想改动粒子的方向的话,直接改粒子的 transform 就行。。。
在跳跃的时候停止动画,落地的时候播放动画。游戏结束的时候停止动画。
- 有时候游戏结束人物依然有奔跑粒子。因为人物可能在空中死亡然后落地,落地后播放了动画。因此要加个判断。
2.1.4.3 给摄像机添加音乐
简单,依旧是之前学过的内容,添加一个 Audio Source,拖动一个音乐进 audio clip。调整 volume 小一点以防盖住了之后要添加的音效。选上 loop 以循环播放。
2.1.4.4 音效
重点,这里和之前 M_Studio 那里学的不一样。
- M_Studio 的做法是用一个 SoundManager 来管理,里面只有一个 AudioSource 组件,播放的时候会切换 AudioSource 的 AudioClip。
- 本教程则是把 AudioSource 当做播放器来用,而不是 M_Studio 那样把 AudioSource 当做音乐本身来用。
具体表现在本教程我们不给 AudioSource 绑定任何 AudioClip。具体流程如下:
- 直接给 Player 添加一个 AudioSource 组件,不加任何 AudioClip。
- 去到脚本里,创建两个属性,类型为 AudioClip,用于跳跃和死亡,记得在 editor 里绑上文件。
- 新建一个属性存储 AudioSource 组件,直接 GetComponent 获取即可。
- 接下来使用 AudioSource 的一个新的方法,PlayOneShot。和之前的 Play 只能播放 AudioSource 上绑定的声音不同,PlayOneShot 可以接受一个参数指定播放哪个 AudioClip,也就是说和自身绑定啥无关,当一个播放器来用,只要你能够获取到 AudioClip。
- 当然我们第 3 步已经获取好了,这里直接放进去即可。此外还可以接受第二个参数,是一个浮点数,表示播放音量。这里使用 1.0f 代表正常音量。(不加这个参数就是默认正常音量)
注意:两个教程的区别,重点在于 AudioSource 是作为和声音深度绑定还是只是作为一个播放器来用。和新建到一个 SoundManager 还是直接放在 Player 上没有关系。本教程这个方式完全可以用 SoundManager 的形式弄。
2.1.5 小练习和测验
略过(但做了)
2.2 玩法机制
新建一个新的项目,导入素材。
2.2.1 熟悉场景
可以看到这次的摄像头有点不一样,因为这次的摄像头采用的不是透视投影而是正交投影。因此我们在 scene 里也调成几何视角保持和游戏界面一致。
- 新建一个球体,放到场景中央。
- 放大一下 scale。
- 添加一个 texture,直接拖到场景中的球上即可。
2.2.1.1 添加聚焦点
我们希望我们的摄像头围绕着中央旋转来看这个平台。
- 为了实现这个目的,我们需要对摄像头进行操控,为了方便操作,我们新建一个空物体命名为 Focal Point,然后把摄像机成为其子物体。(如果你学过 AE,这是一个很常见的手段)
- 这个时候你可以改变一下 Focal Point 的 y 轴旋转度,这正是我们要的效果。
2.2.1.2 旋转
绑定一个脚本,里面通过键盘的左右控制旋转。
2.2.1.3 移动
给 Player 添加脚本,用上下控制移动。
2.2.1.4 移动跟随旋转角度
现在移动只会朝着某一个方向移动,因为 Vector3.forward 指向的永远是同一个方向,而我们需要移动随着镜头旋转而改变。
之前有提到过 global 和 local,会影响工具的角度。但当时以为 transform 会跟着改变。其实不会,transform 反映的是 global 的位置,角度和缩放。当你把物体换成 local 后再斜方向移动,会看到 transform 会同时改变两个轴的值。
- 注意:虽然是 global,但是并不是 3D 空间的绝对位置,而是相对于 parent 物体的 transform 的相对位置。只有最外层的物体才是真实绝对位置
- 此外,面板里和代码里是不一样的,代码里的 transform.position 是绝对位置,想要取得相对位置有专门的 localPosition
换句话说,global 和 local 只影响工具的角度,其他不变。
代码里通过如下方式获取信息:
- 首先获取 focal point 的 transform。
- 通过 transform.forward 获取蓝轴信息。
2.2.2 跟随 Player
2.2.2.1 物理材质
再来看一遍这个 inspector:
属性很少:
- 动态和静态摩擦力。表示物体静止和移动时候的摩擦力。
- 弹力,碰撞的时候弹回的力。
- Friction combine 和 Bounce Combine 是用于当两个同样具有物理材质的物体相撞的时候采用的计算方式。average 就是加起来除以 2,minumum 和 maximum 是取两者最小或最大,multiply 就是相乘。
可以发现这些属性都和碰撞有关,只有碰撞的时候需要用到。因此物理材质是绑在 collider 上的。
这里我们新建一个球体敌人,给其和 Player 都套上一个新建的物理材质。改变一下弹力以及 combine 方式。看看效果。
2.2.2.2 敌人跟随玩家
直接看代码:
这是挂载到敌人身上的代码:
- 获取自身 rb 和玩家的 object。
- 这里看一下 AddForce 的参数,主要是前面这句 (this.Player.transform.position - transform.position).normalized,括号内的部分是玩家的位置减去敌人的位置,这是什么意思呢?其实仔细想想,位置是一个 Vector3 向量,玩家的位置向量减去敌人的位置向量,实际上就是一个从敌人指向玩家的向量。
- 不过如果直接这么使用的话,玩家离敌人越远,敌人的攻击欲望就越强,因为距离变大了,方向向量也变大了。如果不想要这种效果的话,那就需要把方向向量 normalize,让其只用作为方向的功能。这里 Vector3.normalized 返回一个长度为 1 的同方向的向量。
2.2.2.3 spawn manager
依然是用 spawn manager 来生成敌人,过程不再赘述。
可以把生成随机位置的代码拿出来做一个方法,这一操作在 VS 里有简便操作(选中想要提取的代码行,按 alt+enter 或者左边的灯泡图标,选择提取方法即可):
2.2.3 Powerup 和 Countdown
2.2.3.1 Powerup
生成一个 powerup 道具,捡起的时候 player 变厉害。
- trigger 检测 powerup 道具,trigger 后销毁道具,player 改变状态。
- 碰撞检测敌人,在有 powerup 的情况下,与敌人碰撞后将其击飞。
击飞代码逻辑其实用之前讲过的内容即可做到,可以试一下。
答案其实就是用敌人的位置减去自己的位置,得到方向,然后给敌人一个 Impluse 的 AddForce。
2.2.3.2 Countdown
我们想要做一个倒计时,独立于 update 之外能够自己定时更新。先看代码:
- 这里用到了接口,接口一般命名以 I 开头。这里用到的接口经常用于类似于倒计时这样的场景。
- 该接口用到了 yield 关键字。会让代码等待在这一行,直到该行运行完毕再进行下一行。
- 刚刚提到了运行完毕,因此 yield 后面返回的得是一个异步过程。而这里我们使用了 WaitForSeconds,这是一个异步过程,作用顾名思义,等待 x 秒。
- 等待这 x 秒过去后,yield 返回值,并继续下一行,把 _isPowerup 返回 false。
- 上面可以看到在 trigger 里使用 StartCoroutine(PowerupCountdownRoutine()) ,注意括号里是接口的调用,而不是接口本身。毕竟我们 StartCoroutine 是要接受一个协程作为参数的,而不是 IEumerator。
- StartCoroutine 会起一个协程,而这个协程是独立于 update 之外的。这样就达到了我们的目的。
实际上刚刚所做的,用 Invoke 很简单就达到了。Invoke 就是一个可以简单使用的 coroutine。
2.2.3.3 Powerup Indicator
一个 powerup 指示器。用 setactive 即可实现。
不过也有坑,就是如果只是单纯把 indicator 作为 player 的子物体。会发现 indicator 会跟着一起旋转。这不是我们想要的。
解决方法有很多种,教程里干脆直接不用子物体,而是在 update 里实时更新 indicator 的位置为 player 的位置。
2.3 UI
说是 UI,其实还是一个小游戏项目。大概就是做一个点击的小游戏,有些物体点了加分,有些点了扣分这种。
2.3.1 鼠标点击
Unity 提供了很多鼠标点击相关功能。现在我们就来尝试一下。
2.3.1.1 批量添加组件
一开始需要给之后用到的好物体和坏物体加上 rigidbody,collider 和脚本。一个一个加显然低效。其实 inspector 是可以显示批量物体的详情的。选中多个物体,会显示这些物体中重复的组件。也可以批量添加新组件。
2.3.1.2 随机上抛
我们要随机向上抛出物体。除了之前用到的 AddForce,我们还会用到 AddTorque,用于让物体物理式旋转。
2.3.1.2.1 测试小 tip
因为我们还没写 spwanManager,但是想测试一下上抛的效果怎么样。一种是先拖一个物体到场景中,但这样有些笨重,测试多个效果的时候,测完了还要一个一个删除。
还有种方式是运行游戏后,再往场景里拖物体,拖进去后代码立刻生效。(换句话说你就是 SpawnManager)而且因为是游戏模式,退出后这些物体也会一并消失,很方便。
2.3.1.3 Game Manager
这次逻辑比较多,因此 spwan manager 被整合进 game manager 里,这里就直接建一个 game manager 来代替 spwan manager 以及后面会用于管理各种状态了。
- 这里用 IEnumerator 其实也就是实现了一个 InvokeRepeating 而已。
- 使用了列表,列表的长度是 Count 不是 Length 噢。
2.3.1.4 鼠标点击
Unity 对于鼠标点击事件有专门的函数,会在鼠标点击到这个物体的时候触发,所以我们代码如下即可:
这里是 OnMouseDown,当然同理还有 OnMouseUp,OnMouseOver,OnMouseExit 等等。
2.3.2 显示分数
这里开始终于讲 UI 了,不过用的依旧是老版的 UI 系统,因此不会进行过多阐释。但是做还是要跟着做的。无论如何,学习一个系统的历史也能够有更开阔的视角去看待新系统的一些功能。
2.3.2.1 销毁粒子效果
当鼠标点击的时候,在物体位置上 Instantiate 一个粒子。勾选 Play on Awake。并给粒子的 stop action 换成 Destroy,这样动画播完粒子就会自动销毁了。(或者也可以在代码里使用 Destroy 第二个参数,可以延迟销毁)
2.3.3 Game Over
不细讲,照做一遍即可。顺带一提 TextMeshPro -button 其实是一个旧的 button 里面套着一个 TextMeshPro -text。因此引用的时候这么写:
其实所谓的 TextMeshProUGUI 就是这个组件↓:
能不能引用其实就看有没有带这个组件。
2.3.4 难度选择
依旧不细讲。不过有一些额外知识:
2.3.4.1 UnityEvents相关:addListener 其实就是相当于在 Inspector 里点加号。
以下两个是相等的。
这也解释了为什么在自定义事件 UnityEvents 的文档里写着,Invoke 会执行所有的 AddListener,这样就很容易理解了。毕竟你全都绑在 OnClick 上了,自然当 Click 的时候就会执行所有的绑定事件。
而 Invoke 的作用自然也清晰了,当你自定义事件的时候,不是你起个名字叫做 MouseClick 就能识别鼠标点击了,自然需要你写一个抓取鼠标点击的函数,然后在里面调用 Invoke,以此来实现事件。
2.3.5 练习
没什么好讲的,一些小 tips
2.3.5.1 更换素材
有时候我们想用新素材替换掉旧素材,但是原素材上已经有很多组件了并不好操作。
有一个方法是把新素材作为原素材的子物体,然后取消原物体的 mesh renderer。如果想改变 collider 也可以取消原物体的 collider,以此类推。
2.4 用户反馈和测试
居然开始讲用户测试了,震惊,不过确实很重要,仔细学一下。
但是也不用特别在意,因为关于游戏测试的事项,《游戏设计艺术》里有更详细的讲述。我会在那个路线里重点讲(不过是书里很后面的内容了,应该需要一段时间才能走到)。这里看看就行。
2.4.1 是什么
这个就不用说了,大家都知道。不过需要注意的是,用户测试不是个一次性流程,而是应该贯穿整个制作流程,得到反馈再来改进游戏的一个循环过程。
2.4.2 为什么要有一个结构化的测试流程
好的用户测试并不是给找一群人,给他们玩游戏,然后得到不同的信息反馈。当然这也有用。但是好的用户测试应该是一个结构化系统,尽可能全方位地从测试里面获取各式各样的信息。包括区分测试人群进行不同人群的比对等等。
理想状态下,你应该在游戏开发的不同阶段进行测试。
如果在游戏开发完成度比较高的时候去测试,很多东西可能已经不好更改了。这还不只是说玩法设计上面的不好更改。有些 bug 如果是牵一发动全身的,这时候也就已经很难办了。
2.4.3 用户测试的阶段
用户测试大概分这几个阶段。
- 设定目标。
- 计划 session。(我不知道怎么翻译比较好)
- 执行跟进 session。
- 评估结果。
2.4.3.1 计划用户测试(包含 1, 2 两步)
2.4.3.1.1 设定目标
问自己两个问题:
- 你想从这个测试中获取什么信息?
- 你要给用户什么来测试?(一个小关卡?一个原型?一个框架?还是一个完整的游戏?)
2.4.3.1.2 准备问题
测试的时候要问用户问题的,我门要准备一些开放性问题,一些固定回答问题,或者两者结合:
- 开放性问题:用户能够自由回答,类似于填空题。比如说你玩的时候哪里感到最开心?你觉得游戏好不好玩?之类的。
- 固定回答问题:只给用户一些选择去选,类似于选择题。比如说让用户 1-5 打个分,或者只能选是或者否的一些问题。
固定回答更适合问卷。而开放性问题则最好是当面问,因为用户没法和你直接交流,或者用户赶时间就填了一些不太好理解的话。你也没法继续问深入讨论下去。
2.4.3.1.3 计划 session
session 就是测试用户已经拿到游戏了,开始玩游戏了,在给你反馈之前的这一时间段。
这个时间段也是需要好好计划的,不是上来就直接让他们玩,有这些问题需要考量:
- 确认好日期和时间。比如说你的测试用户是上班族,那你最好别开在工作日白天。
- 根据你游戏的目标用户,找对应的测试人员。比如说你想做给 rpg 老手玩,那你就找一些 rpg 老鸟。你想给没接触过 rpg 的人玩,那你应该找那些从来没玩过 rpg 的人来测。
- 确定好测试人数。(这个我不确定,不是越多越好吗)
- 最好能把整个测试过程记录下来。(如果可能的话,比如录屏,记录尽可能多的游戏生成日志,等等)
- 如果你是一个团队的话,可以找一个 leader 和一个记录人。
2.4.3.2 session 开始前的准备(第 2,3 步)
以下 tips 对你有帮助。
2.4.3.2.1 观察,而不是指导
用户卡住的时候不要去告诉他怎么做。这是一个信息告诉你你的引导不太行。
如果卡很久的话,你可以选择告诉他。以便让他继续接下来的测试。
2.4.3.2.2 不要解释你的设计思路
用户遇到了一些问题,也许确实是走错了路,然后你去跟他解释,很有可能他就信服了。
但是这并不是一个好的测试,因为其他人很有可能遇到相同的问题,你不可能一一向所有人解释。
2.4.3.2.3 不要在测试的时候解决问题
不要在用户告诉你某个问题之后,你就立刻去关注这个问题,想出解决方案。测试的目的在于搜集问题。如果用户发现了一个问题,你就记录下来,然后让用户赶紧去看下一个问题。而不是和你讨论这个问题怎么解决。
包括测试用户自身也是,很多用户测试的时候甚至会帮你想这个问题可以怎么解决,你应该引导他们去找下一个问题,而不是在在这个问题上花费过多时间。
解决问题应该在测试完毕之后。
2.4.3.3 执行跟进 session(第 3 步)
每个 session 都不太一样,但基本结构一般都是如下:
- 向你的用户介绍这个测试的一些情况。
- 确认好 session 的目标。
- 向用户介绍记录方式,确认能否接受。
- 提供测试资源,观察用户测试。
- 问之前准备好的问题。
- 总结用户的答案。
- 结束
2.4.3.3.1 一些跟进的 tips
我决定不写出来。因为很多和游戏设计艺术里说的冲突,而我更偏向于那本书里的内容。感兴趣可以自己去看。
2.4.3.4 结束 session 之后
做完 session,立刻做以下的事情:
- 看看记录有没有记录好。
- 把所有想的东西都写下来。
- 和测试者讨论一些细节问题。
- 写个总结文档。
- 决定哪些反馈需要更改,哪些不用。
2.5 如何进阶
按照课程的说法,学到这我已经完全入门了。这一节会告诉我一些各种各样的 tips,让我比较安稳地走上这条路。
2.5.1 项目优化
之前的项目,并不是特别完美。有很多特性可以帮我们更好地完成任务。有些代码写的不尽如意。现在来一一优化。(不过例子里用的是很老的 unity editor 版本了,感觉还是会有很多特性没讲到)
2.5.1.1 变量属性
之前用到的变量很少,也就 public,private。(虽然我本人还用了 static, [SeralizedField]) 这里介绍了一些别的,类似于 static, const, readonly, [SeralizedField]。没什么好讲的。
2.5.1.2 别的事件函数
之前只用到了 start 和 update。实际上还有 FixedUpdate, 和 LateUpdate 等等非常多。
- FixedUpdtae 以前讲过,总之就是特别适合进行物理计算。顺便一提,FixedUpdate 会在 Update 之前执行,这个之前没有提到过。
- LateUpdate 则是特别适合进行摄像机位置计算。当你需要控制摄像机位置的时候,一般用这个比较好。尤其是当你发现,有时候摄像机跟随物体的时候,总是有点微小的晃动的时候。原理也很简单,因为在物理计算之后,摄像机就能够准确地算出下一步应该去哪里。
- Awake。Awake 在 Start 之前。Awake 会在脚本实例化的时候调用。而 Start 会在这个实例被启用的时候调用。也就是说即使禁用了这个脚本组件,awake 也会调用,不过 Start 就不会调用了。(不过如果整个对象都被禁用了(如 setActive(false)),那 awake 也不会被调用)
2.5.1.3 对象池
之前新建 object 的方式比较低效。对象池能够更高效地进行操作。
2.5.1.3.1 导出项目
如果想备份一下目前的项目,可以在 Assets -> Export Package 里操作(2022 版 unity editor)。
2.5.1.3.2 对象池的思想
像是之前生成物体都是通过预制体来 Instantiate,但是这个过程其实还挺耗费性能的。好不容易实例化了一个,之后又要删掉再重新实例化。
而对象池的思想就是在一开始就生成一大堆对象组成的对象池,然后需要用到的时候激活或者停用。(没错,就是那个 SetActive)。所以其实很简单。在一开始的时候根据需要生成多个 SetActive(false) 的物体。需要使用的时候就激活,然后把位置调到对应的地方。
可以看一下其中一种实现代码:
2.5.3 搜索 和 解决 bugs
好家伙,看了一眼,居然在认真教你怎么搜索比较好。
不在这个推荐算法的时代,很多人确实不太会用搜索引擎。如果你平时很少用搜索引擎,确实可以看一下。
不只是教你怎么用,还教你有些时候需要搜索两遍的情况,比如说第一次搜做某个功能应该用到什么函数,第二次搜索怎么用这个函数。等等。
很多时候都可以直接搜出一个解决方案出来。相比之下,一些用的人少的游戏引擎,就还挺难搜的。
2.5.4 分享项目
就是打包,或者打包成 webgl 发布到网站。都是学过的内容了。
2.5.5 ECS 生存指南
好家伙,什么东西啊这是??
懵逼中,不过看了一下,全称是 Entity Component System。是属于新的 DOTS(数据导向技术栈)的一部分。表示一种新的编程思想。
和之前的 Unity 编程系统不一样(基于 Object 和 Component,像是 EnemyPrefab,Collider 这之列的),新系统会基于 data(基于像是移动速度,位置,生命值这之类的)。
用这种系统的原因,就是因为这样可以极大的提高运行效率。
2.5.5.1 简单介绍
ECS 是比较深入的知识。因此这里就只是简单介绍一下。
先从 DOTS 说起,DOTS 全称是 Data-Oriented Technology Stack,一个技术栈,自然包含了多个技术:
- ECS
- C# Job System
- The Burst Compiler
数据导向,意味着代码主要是围绕着数据,而不是 Class 来设计。
能够和很好地提升性能。教程给了个视频,画面很好,并且 60 帧。最重要的是,在手机上跑的。
然后大概给看了一下新代码长啥样:
2.6 求职
不需要,且不符合国情,跳过。 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|