从零开始独立游戏开发学习笔记(二十五) |
您所在的位置:网站首页 › lol游戏更新慢 › 从零开始独立游戏开发学习笔记(二十五) |
很抱歉,最近花了一点时间稍微玩了下某款热门游戏。 更新慢很抱歉,但实在是太好玩了,虽然我不喜欢宏大叙事,但是无奈它探索感做的太好,美术实在太棒。 游玩时间,敬请见证。
不过不管怎么说,至少小狐狸教程还是做完了( 1. Class 调用首先按照创建青蛙的逻辑创建老鹰,很简单就不说了。 1.1 爆炸效果我们想让敌人在消灭前播放这个动画,爆炸效果的制作就不说了。着重说一下 animator 里之后的做法。 在 Animator 里设置一个 trigger 变量,而不是之前一直使用的 bool 变量。 1.1.1 triggertrigger 和 bool 不一样的是,当 trigger 被触发后,会立刻回到 false 状态。 1.1.2 在 player 里改变 enemy 的状态我们的消灭敌人的代码是在 player 的 script 里的。但是我们要改变的并不是 player 的动画而是 frog 的动画。因此需要获取到对方的 animator。 当然,因为在 collider 里已经给出了碰撞体的信息,可以通过 collision.gameObject.GetComponent() 来获取,不过此时我们换一种思路,让死亡的逻辑写在 enemy 上而不是 player 上。方法就是我们在 frog 里写一个 public 函数,然后在 player 里调用这个函数。但是如果这么写的话会遇上这么个情况:
不可能每一类敌人都要写一次销毁函数。因此我们新建一个 enemy 类来让这些功能复用。 这里就需要使用代码了: 给 Enemy 添加 Animator 变量,并在 Start 中赋值。全部给 protected 是因为这两个属性方法会在子类中被调用。其中 Start 会重名因此加上 virtual 以便 override。首先点开 main camera,会发现里面已经有了一个 audio listener 的组件。这个是用来收集声音的。 一般来说 audio 分为 listener 和 source。listener 自动集成在 main camera 上。然后在游戏里摆放各种 audio source 来让 listener 听。 2.1 人物自带 BGM给 player 添加一个 audio source 组件,然后将 BGM 拖进 audio clip 属性中即可给 player 绑定一个随时播放的 bgm。
要给敌人添加消灭音效。先添加一个音效,然后去掉 play on awake 和 loop 因为只想在爆炸的时候播放。
随后在代码里获取 AudioSource 组件后调用 Play 方法即可。
ctrl + r (两次),可以给当前变量批量改名。比 ctrl + f 的好处是会自动判断是否同一个变量(毕竟是强类型语言)。 2.3 受伤音效,拾取物品音效如果添加多个音效的话,GetComponent 如何分别呢。教程里给的方式是换用 public 变量,这样在外面拖组件就行了。
通过 panel 来写,大部分之前基础课程学过了,直接看效果:
Project Setting->Input 这里可以这样添加新的按键:
有时候我们想在游玩的时候看到实时的碰撞体,这个时候就要启用右上角 Gizmos 按键,并在 hierarchy 中选中想要观察的物体。
我们可以看到蹲下的时候,碰撞体并不会改变。因此蹲下的时候,我们把头部的碰撞体 disable 掉。
当我们通过比较矮的地方时,如果松开下蹲键,人物会恢复站立,如图:
这个在之前的基础教程里讲过,不过附带一些小知识。 5.1 如何引入 GameManagerUnity 会把命名为 GameManager 的脚本图标换成齿轮。GameManager 一般用于管理场景切换(重新开始,胜利,失败,等等)。不过如何在其他脚本里引入这个脚本呢? 5.1.1 public首先尝试新 public 一个 GameManegr 类:
一个 object 上可以挂载多个脚本,这种 object 同属于多个类。比如说刚刚的空物体,我们可以添加一个 enemy 脚本,这样 GameManager 也可以作为 Enemy 类被引入(当然没有必要,这只是为了演示效果)。 有些时候 tilemap 制作的地图之间会有缝隙,此时将 grid 的 cell size 的 x,y 值调成 0.99 即可解决。 5. 2d 光效项目创建的时候并没有选择 URP,这里就先做一个简单的光效:
先创建一个 material,shader 换成 sprite/diffuse
被光照的背景有了缝隙,反而需要我们把 grid 的 cell size 从 0.99 改回 1,如果还有可以去 project setting->graphic 里将抗锯齿关掉。 6. 优化代码 6.1 敌人销毁销毁动画最后我们加了个触发器来 Destroy 敌人。但是当时我们触发器事件放在最后一帧后面的一些位置,我们应该和最后一帧放一起,以让动画更加顺滑。 7. 视觉差 parallax接下来要做人尽皆知但又酷炫的视觉差效果。 7.1 cinemachine 更换跟随之前 cinemachine 的边界是挂在 backgroud 上的,但是现在我们要让 background 移动了,因此我们得换个地方。新建一个空物体,把 background 的 collider 组件和 position 复制过去即可。 7.2 代码新建一个 Parallex 脚本,以供复用。
public 一个 transform 用于记录 camera 的位置。以及一个速率以供调整。最终代码如下:
当 FollowRate 为 1 的时候,背景和人物同时移动,背景相对人物静止。所以我们只要给背景和中景不同速率即可。 8. 主菜单 新建一个 scene,添加 UI panel。 如果不想用图片,给 panel 的 background 设置为 None,再设置 color 纯色背景。 如果要用图片,将 background 换成我们想要的图片,再调整 color 为我们想要的感觉。 想要给 button 绑定事件,就必须有一个 object,引用这个 object 上的函数。因此我们给 canvas 添加一个脚本,在脚本里写函数,然后从这个 object 里读取函数。(无法直接读取脚本,必须得有一个实例) 9. 暂停菜单和主菜单区别不大,就是些 UI 操作。 不过涉及到暂停和音量调节。 9.1 暂停通过改变 timescale 来暂停:
通过 AudioMixer 来实现: 创建一个 AudioMixer,发现 inspecter 窗口属性很少,因为主要在 window->audio->audio mixer 面板里。 可以看到,-80 是最小值,0 是正常音量。因此我们给之前 UI 里的 slider 调整下最小值和最大值。 在 player 当时创建的 audio source 里,给 output 里加上刚刚创建的 audiomixer,audiomixer 会自动创建一个 master 的 group,选那个就行。 然后我们想在脚本里修改,但是发现 audioMixer 根本无法添加组件,也就无法添加脚本。那么对于这样的情况,我们有一个办法,就是将想要调整的属性 expose 出去,这里我们想要修改 volume,因此右键 volume 属性即可看到。有些版本没有上面的 dynamic float,此时可以在函数里直接获取 slider 的值即可。毕竟 slider 也只是个组件。 10. 手感调整 10.1 FixedUpdate之前提到过 FixedUpdate 是一定每一段时间执行一次,但其实并不是。试想一下你电脑就是 literally 很卡,FixedUpdate 怎么可能保证的了。它只能尽量去保障,并且如果你电脑不是经常卡,而是某一段时间突然卡一下,那么接下来 FixedUpdate 会一下次执行好几次,以便保持 1s 内执行的次数是固定的。比如说本来应该 0.2s 执行一次,结果某次突然卡了 1s,那之后就会立刻执行 5 次 FixedUpdate 来弥补。 10.2 跳跃手感调整,二段跳用和下蹲的时候同样的方法来检测人物和地面的接触,以此来判断跳跃动作。 给人物添加一个地面监测点。 代码里添加 jumpPressed 和 jumpTimes,前者是为了在 update 里读取在 fixedUpdate 里跳跃。后者是为了二段跳。所谓单向平台,就是可以跳上某一个平台,并在跳跃的时候无视这个平台障碍物。也就是说可以从平台下方直接跳上来。 首先随便创建一个平台。创建 collider。 勾选 collider 中的 used by effector 添加一个 platform effector 2D,没错,单向平台是一个内置组件,不需要我们手动实现。 勾上 use one way 即可。 10.4 bug 修复(这里内容来自 Brackeys) 10.4.1 从高处跳下会被卡住:这是因为速度太大,碰撞的那一帧没有判断到,在 player 的 rigidBody 里将 collision detection 改成 continuous。
这是因为头部的 box colllider 比身体的 circle collider 大,这样头部就会被卡住。 修改方法就是把身体的 collider 调整为略微大于头部即可。 11. 音效管理 SoundManager作者觉得 player 身上挂了太多 audioSource 了。想解离出来: 首先和 GameManager 一样,先创建一个 object,上面创建 SoundManager 脚本。 添加一个 AudioSource 组件,我们想让之后通过更换这个组件的 clip,再播放,达到只使用一个 audio source 的效果。之前使用 gamemanager 的时候,每次我们都要引入 gamemanager 那个 object,拖拽再调用。 我们当然也可以吧 gamemanager 或者 soundManager 设置为静态类,这样就不用每次拖拽了。(前者因为要用 invoke 还不能用静态类) 不过除了静态类,还有一种方式不用引入也能调用方法,那就是单例模式。(注意:单例模式依然要实例化挂载一个空物体上,只是不用拖拽了) 将代码改成如下: 注意标红的位置: 首先创建了一个静态变量,类型为自身。 在 awake 生命周期函数里让 instance 等于 this。也就是 instance 为实例本身。 也就是说,这个类有一个静态变量可以被外面调用,而这个静态变量里储存的值刚好是自身的实例化。因此可以通过这个 instance 来调用方法。因为 instance 就是一个 soundManager 的实例。接下来我们就可以非常简单地播放 bgm 了,如下图,无需 public 后拖拽:
同样的方式我们可以用来创建剩余的 audio,甚至还可以把之前的 GameManager 也优化了。 11.2 字段优化刚刚创建的那么多 clip,其实不太想设置成 public,不然代补补全东西太多了,但是我们又想在外面拖拽,那么就需要用 SerializeField 字段了:
这样即使是 private ,也可以在外面拖拽了,但是仍然能够保持在别的代码里无法访问的限制。 11.3 BGM 同时播放刚刚把bgm放进去其实并不好,因为只能同时存在一个声音,如果跳起来的话,bgm 就没有了。因此 bgm 应该单独拿出来。
如果实际操作会发现,每次换音频,insepector 都会变一下,每次都要点回成 soundManager 的 insepector,很麻烦。可以选择 inspector 右上角的锁来锁定住。 12. build之前基础教程里很详细了,不再赘述。 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |