GAME104第十五节

事件机制

对象的生命周期问题会导致一些游戏的bug。比如这一帧要调用的go,实际在上一帧就销毁了。

事件定义

事件类型和事件参数

事件注册

对象强引用(object strong reference):对象注册在这就不能删除,保证整个引用的安全性。会导致内存越来越大。

wake reference:增加额外一步判断物体是否被删掉。

事件分发

直接派发(马上处理)

方式:收到消息,直接就处理。

可能会导致帧率不稳定,不能并行处理消息

事件队列(下一帧处理)

Event Queue 事件队列

方式:收到消息需要先存到队列里,不会立即调用。

  • 把所有需要运行的event全部catch一起,变成一个q,然后下一帧全部处理。
  • 把几百个event拍成q和把q变成几百个event,序列化和反序列化。

这么做是为了保证消息的正确和完整设计了一个队列

用ring buffer的方法管理event queue的池子。

进一步可以把event的功能再区分,比如NetEventManager、CombatEventManager、AnimationEventManager等。

产生的问题

问题1:事件处理顺序无法确定。

消息执行的顺序无法保证(很多的引擎会把不同系统的处理顺序给定死,比如有时需要先处理动画在处理物理等。)

这个问题非常难解决

现代引擎中,通常会有三种tick去支持。下一帧一上来就处理完,有的是在post tick处理,有的在pre tick 处理,有的是immediate处理

问题2:事件的递进式关系。

event的处理机制一般会是在下一帧去处理的。

假设一个简单的递进关系,eventA触发eventB,eventB触发eventC(比如砍人一刀会飙血,那会希望在同一帧下屏幕会有渲染飙血的效果)。

这里就需要用一些hard core去专门处理这个问题。

游戏逻辑与脚本系统

编译语言

早期的引擎直接采用C/C++,这类原生的编译语言进行代码的编写。

编译语言:编译成高性能的机器码,比汇编语言更易于使用。

游戏需求随着硬件的发展而变得复杂,需要快速迭代游戏逻辑

编译语言的问题:

  • 问题1:即使稍作修改也需要重新编译(每改一个gameplay,游戏引擎就得全部渲染一遍)
  • 问题2:如果代码不正确,程序很容易崩溃(游戏发布后会有bug)
  • 问题3:游戏玩法定义的设计师,无法直接更改代码

问题1、2解决方案:hot update 热更新

问题3解决方案:脚本语言

脚本语言

脚本语言是一种解释语言。

支持热更新;能够快速修改迭代;中间某个函数换掉后,还能继续运行;不会把本体crush掉。

写非常复杂的网络服务器端时常用。

image-20241112173712263

  • 脚本文本通过自己的编译器,变成一堆的bytecode,用一个虚拟机执行bytecode,就可以跑起来了。相当于在游戏系统上运行了一个自己的虚拟机。

Lua

在魔兽世界、文明5中使用。

优点:稳健且成熟;出色的运行时性能;重量轻,可扩展性强

缺点:库很轻量级,啥没有要自己写。

Python

在模拟人生4:EVE Online使用。

优点:支持反射;内置的面向对象支持;拥有广泛的标准库和第三方模块

C#

脱机字节码,在Unity中使用,把C#这样的原生语言变成一个脚本语言使用。

优点:学习曲线低,易读易懂;内置的面向对象支持;社区环境好,有很多活跃的开发者

Lua、C#和Python比较

省内存:Lua>C#>Python

运行速度:C#>Lua>Python

热更新

脚本语言的热更新,就是把函数指针给修改掉。

老的函数有个函数指针,在扩这个函数时,把函数指针重新指向新的脚本即可。

脚本语言的坏处: 运行效率慢。

just in time:可以一边执行一边编译。(比如大名鼎鼎的lua)

脚本与引擎之间的对象管理

引擎使用原生编译语言比如C++编写,gameplay部分用脚本语言编写。对于游戏中的对象,对象归谁管,取决于游戏本身。

  • 如果本身游戏的对象没有那么多,但是有重度的角色细节的表现(比如动作、Ai等),比如MMO。把生命周期交给引擎管理。
  • 如果玩法非常多、人物也非常多,玩法还会产生很多的人物,比如MMORPG。一般把生命周期交给脚本管理。这样在玩法系统中可以很容易的生成和销毁非常多的对象。

脚本系统的体系结构

引擎包脚本

  • 引擎调用脚本,到了某个特定的、比如component时,把那段相应的处理写成脚本。
  • 比如unity(原生态就是每个component可以拓展成一个脚本,用C#)

脚本包引擎

  • 早期有些游戏会用到,现在很少用。
  • 把引擎单纯当成要给sdk库,引擎提供了各种各样的服务,然后由脚本控制整个tick的flow,引擎把所有的go给tick一遍,到了系统休息,脚本给份名单,引擎再根据把所有的go给干掉。

可视化脚本

UE的Blueprint 蓝图系统,unity的Visual Scripting。

对于一些设计师、无程序学习背景的人,可视化脚本非常方便。

Visualscript也是一种程序设计语言,它通常需要变量、声明与表达、控制流、功能、类(面向对象的程序设计语言)。

  • 用不同颜色的“拐角”来定义不同的数据类型。
  • 使用“节点”表示语句和表达式。
  • 通过“执行引脚”使用执行线来使语句顺序排列。

可视化脚本的问题:

  • 工业化应用时,速度不够
  • 脚本多时,会变成“蜘蛛网”
  • 目前大多数都是,直接把Visual Scripting变成Bytecode,然后在虚拟机上跑。

3C系统

3C:角色、控制、相机

3C是最直接的操作体验的核心。

Control:Aim Assist、Feedback

Camer:PoV(位置)和FoV(张角)

QA补充

有些平台不允许热更:

审核时的内容通过,后续热更的内容不通过

……