纵观整个插件,它利用了 Godot 的节点组合思想,将 Player 分成了两个部分——摄像头操作和其他行为。行走、跑步、跳跃、下蹲、游泳、飞行等都是一些相对独立的行为,这些对 Player 移动行为上的操作被分成了一个个可选择挂载的 MovementAbility,当行为被挂载在 Player 上这些操作就生效了,它们分别控制 Player 主体的运动。
同时,因为头的标记点是和身体分开的,在游戏中涉及到镜头运动的一些演出上,我就可以维持人物本身不动,而控制头标记的位移,实现例如从地面醒来并坐起、坐在凳子上、以正视图视角查看屏幕等操作。此时Player本身并没有移动,而是头标记在空间中运动。(我采用了两种动画方式,一种是可打断的、简单快速响应的 tween 动画,一种是演出复杂、不可打断的手动 k 帧动画)
这次设计的 3D 场景中的主要难点是监控摄像头的查看和控制、对电脑中 UI 的独立控制。最开始我并没有想直接做在 3D 中,虽然效果比较好,但是也比较复杂,不如点击后直接弹出一个 UI 来查看和操作。不过我最终还是选择了 3D 直接展示,因为效果真的很棒!而且 Godot 引擎中很容易可以实现这一点。
可能有的朋友会问,使用这么多 Camera 和 FrameBuffer 性能不会很糟糕吗。对我们项目来说其实还好,因为这次做的是复古低分辨率的类型,整个视口的分辨率很低(512*360),这些子视口的分辨率自然更低了,所以在没有特意做优化的情况下,也不会特别卡。同时,这些显示器在不注视的情况下图像是不会更新的,也优化了一定的性能。
在 3D 游戏中,需要和很多物体进行交互,例如查看、拾取、操作等等。在交互时基本操作都是,看向物体,物体提示操作的按键,按键后开始交互。
刚开始实现时,我将相关逻辑写在 Player 下,比如坐在椅子上、看屏幕等等。但当物品渐渐增多,Player 的代码变得臃肿起来,不好定位问题也不方便查看和扩展。于是我将交互物体部分进行了重构。
正如开头所写,物体的交互是有一套基本操作的。那么 Player 实际关心的只有对物体的注视,和一些基本状态的维护,把对物体的操作归还给物体本身,来实现一定程度的逻辑解耦。和直觉的逻辑实现不同,让物体自己负责被操作这件事,自己的事情自己做(
所以,把 Thing 抽象为一个父类,实现被注视状态的维护,当 Player 的射线拾取到 Thing 时,就将 Thing 设置为被注视。而各个不同的物体对 Thing 进行扩展,描述当被注视时不同的操作会对物体本身和 Player 造成什么影响。例如椅子会操作Player坐过来,电视会操作Player看过来,手机会消失并通知Player已经有手机了、身上的手机可以显示了等等。
跟上述思想类似,同时也和 Player 上挂载不同的 MovementAbility 类似,我将可互动的区域也做成了继承 Ability 父类的不同的行为。当 Player 进入区域和退出区域时会触发事件,而事件会通知所有是 Ability 类型的子节点。这些子节点定义了 Player 进出区域会进行的操作。在游戏中,部分区域回声、BGM、闪屏演出、音频片段的播放等,都是一个个 Ability,节省了很多硬代码的编写,方便在场景编辑时组合使用。
评论区
共 15 条评论热门最新