GAMES104:15 游戏引擎的玩法系统基础-学习笔记

文章目录

  • 0,游戏性课程框架
  • 一,事件机制
    • [1.1 事件的定义](#1.1 事件的定义)
    • [1.2 callback的注册](#1.2 callback的注册)
    • [1.3 事件的分发系统](#1.3 事件的分发系统)
  • 二,游戏逻辑与脚本系统
    • [2.1 特点和常见脚本语言](#2.1 特点和常见脚本语言)
    • [2.2 脚本语言的GO管理](#2.2 脚本语言的GO管理)
    • [2.3 脚本语言的架构](#2.3 脚本语言的架构)
    • [2.4 可视化脚本](#2.4 可视化脚本)
  • [三,Gameplay 开发中的3C :Character、Control、Camera](#三,Gameplay 开发中的3C :Character、Control、Camera)
    • [3.1 角色](#3.1 角色)
    • [3.2 控制](#3.2 控制)
    • [3.3 相机](#3.3 相机)
  • QA

0,游戏性课程框架

  • Gameplay 的挑战:
    1. 玩法系统要和动画、特效、UI、声效、Audio、外设等多个系统共同合作,因此岗位涉及面很多
    2. 同一个游戏也有很多不同的玩法,比如巫师三和昆特牌,对玩法系统的可拓展性要求高
    3. 玩法的快速迭代

一,事件机制

事件机制就是让GameObject 互相交互的机制,比如走到哪里发生爆炸。这种机制如果全都使用ifelse语句写死条件,系统会崩溃掉,所以一般使用event或者message的形式来实现。

想应对比较复杂的游戏机制时,事件机制一般采用发布-订阅模式(Publish-subscribe Pattern):不同的发布者发送不同类型的事件给事件调度者(event dispatcher),可以理解为一个调度公司,事件调度者把事件告诉对应的订阅者(不知道发布者是谁),然后订阅者作出相应的动作(callback)

  • 该模式的三个关键点分别是 事件的定义、callback、事件的分发系统

1.1 事件的定义

Event Type + Event Argument(配置)

Event虽然可以使用基类去继承, 但如果不断加入新的事件类型和对应编辑性,则每次都需要重新编译(与上节课的代码反射相关),这时常见解决方法有:

  1. 将新事件新编译成的C++代码当成 DLL,加入到系统中(UE)
  2. 上层采用 C# 语言,方便动态挂接和扩展
  3. 用脚本语言

1.2 callback的注册

回调函数或触发函数(invoke)。回调函数的注册和触发有一个时间差,在这段时间有可能发生意外,比如订阅者被销毁,因此对象的生命周期和回调函数的安全性是非常重要的。

可以使用c++11中类似智能指针的技术解决:

  1. 强引用:使订阅者在有事件注册时不能销毁。但是会导致系统内存越来越大,所以很少这么用,只有部分情况,比如物体之间有父子关系时使用。
  2. 弱引用:在执行回调函数前,判断订阅者是否存在即可。但是性能会下降一些。

1.3 事件的分发系统

如果分发系统把所有的消息都从头到尾扫一遍的分发效率很低,需要专门的管理。

  • 立即执行:消息来了马上就分发。(但是可能会在线程中打断父函数的调用)

问题:

  1. 当发生连锁反应时,比如手雷引爆其他手雷,会造成回调函数的层数过深的问题。
  2. 如果事件回调本身很耗时,比如粒子系统,帧率会骤降
  3. 调用一层套一层,很难并行
  • 事件队列:把事件存储到Queue中,后续统一处理;并且需要序列化后存储,用到时候再反序列化(c++反射)---跨进程夸网络需要

具体实现:

  1. 使用循环队列Ring Buffer来管理内存(申请一次内存即可)
  2. 使用Batching分批管理:将事件分类,比如网络事件、动画事件、战斗事件等,每一类别分别采用一个队列。

问题:

  1. 不能保证消息执行的顺序(比如先动画后物理等逻辑关系),所以为了保持系统健壮性需要同时支持 PreTick、ImmediateTick,PostTick(这块是bug高发地)
  2. 是one-frame delays系统,会导致一帧左右的延迟(及时性差),因此在需要及时性的地方,比如战斗打击,就要hardcode一下专门处理

二,游戏逻辑与脚本系统

  • 早期游戏逻辑都是直接用c++写的,但这样不可持续,因为:

    1. 每次对游戏逻辑进行修改都要重新编译;
    2. 当遇到错误代码时,很容易导致程序崩溃;
    3. 当已发布游戏遇到 bug 时,难以进行热更新。(现在游戏遇到bug,官方更新一个补丁就能解决,就是用到热更新)
    4. 玩法基本是由设计师负责的,不会写代码,而用脚本语言更容易。
  • 脚本语言运行时会先被编译为bytecode,再到虚拟机上运行,代价是速度慢一些

2.1 特点和常见脚本语言

  • 脚本热更新:可以快速迭代、线上解决bug--其实就是更新函数指针(但需要考虑工程鲁棒性)

  • 脚本语言优点:

    1. 好学易上手
    2. 热更新方便
    3. 脚本语言一般运行在虚拟机沙盒上,可以自己crash而不会导致系统crash,更稳定(大型游戏一旦某个功能crash掉,会立马重新启动脚本重新接入)
    4. 可以快速迭代
  • 脚本语言的问题:

    1. 慢,比如lua就慢很多。可以使用JIT优化---一边解释一边编译
    2. 需要虚拟机去运行脚本语言
    3. 调试不方便
  • 几个受欢迎的脚本语言:

    1. Lua(魔兽世界),轻量内存少,但内库少需要自己写
    2. Python,库强大丰富,不轻量,占用内存多
    3. C#(Unity、暴雪),学习成本低,本身就是编译语言,内存占用中等

2.2 脚本语言的GO管理

脚本语言汇总最难的事对象的管理,但是由谁管理 GO的生命周期呢,是代码还是脚本呢?

  • 引擎代码管理

引擎生命周期管理器--更严谨也有没写好内存泄漏的可能

当脚本涉及到本地对象的时候不安全

当玩法复杂需要创建对象时,在脚本中创建更简单。

  • 脚本管理

GO的生命周期可以被脚本的GC系统(Garbage Collection垃圾回收器)自动管理-----省事但慢,甚至用到10%时间

对象释放的时间不可控(GC 控制)

脚本中如果引用关系过于复杂容易发生内存泄漏

  • 因此一般大型单机都是引擎直接管理,而玩法复杂的比如mmorpg一般用脚本管理GO

2.3 脚本语言的架构

  1. 引擎包脚本:主要玩法写在native code里,把组件扩展成脚本
  2. 脚本包引擎:主要玩法写脚本里,把引擎当成 SDK库提供各种服务。(迭代快,需要认真设计接口,但现在用的少---弹幕说网易的自研引擎就是这样)

2.4 可视化脚本

  • 比如UE的蓝图,Unity的Visual Scripting、Shader Graph就是可视化脚本,这种形式对艺术家友好,并且可视化更不容易产生错误。
  • 并且可视化脚本debug十分方便,每个节点的输出都可以看到
  • 可视化脚本的问题:
    1. 团队工作时,可视化脚本很难合并,会丧失语义且效率低下(因此很多团队前期用可视化脚本,成熟后会翻译为代码)
    2. 有时候可读性很差,一团乱麻
  • 可以把可视化脚本翻译为脚本,然后再执行(再一次应征可视化脚本就是脚本)

三,Gameplay 开发中的3C :Character、Control、Camera

  • 3C系统是游戏体验的核心
  • 要了解什么是3C系统,《双人成行》可以作为最好的案例。

3.1 角色

  • 角色移动:障碍、上下坡、起步和停下等,要处理非常多细节和复杂状态,比如滑行、滑冰、飞等
  • 与环境互动:雪地系统、音效、粒子等等
  • 真实物理互动:状态机控制下的各种状态

3.2 控制

控制系统是游戏丝滑手感的由来

  • 输入设备控制:鼠标键盘、手柄、方向盘、甚至飞行控制器等的控制,比如自动吸附、调整相机等(瞄准辅助也是类似)
  • 反馈感:比如振动或力反馈,键盘背光也算吧
  • 按键组合:拳皇

3.3 相机

  • 相机并不是固定在角色身后的,而是随着角色跑动、走动等状态变化,相机远近大小都跟着变化,或者Camera Track(模仿电影视角更有代入感)
  • Spring Arm:当靠近墙时,保证相机不穿墙。
  • 相机效果:互动抖动、滤镜、各种后处理等
  • 视角变化:第一、三人称切换、武器不同变化、载具不同变化,这个变化还需要插值
  • 除了上述要求,还需要提供一个可视化脚本系统,让设计师能对相机参数进行调整设计。

QA

  • 接入可视化脚本是不是就不需要传统脚本了?不是,很多时候传统脚本效率更高,一般两者都需要
  • 未来平台会不会趋向禁止热更?现在确实一些平台比如ios、ps不喜欢热更,未来会不会变化不能确定
  • 会不会用逻辑和表现分离的模式开发?实际上大部分是分离的,比如一些修仙类游戏的表现比较简单,表现和逻辑可以分的非常开,这样团队规模也可以做得很大,开发效率也会高。但现在更多玩家喜欢互动更多的3A游戏,这样逻辑和表现联系就更紧密,需要糅合去做,对开发者要求也更多。
相关推荐
青椒大仙KI1112 分钟前
24/9/19 算法笔记 kaggle BankChurn数据分类
笔记·算法·分类
liangbm31 小时前
数学建模笔记——动态规划
笔记·python·算法·数学建模·动态规划·背包问题·优化问题
潮汐退涨月冷风霜1 小时前
机器学习之非监督学习(四)K-means 聚类算法
学习·算法·机器学习
GoppViper1 小时前
golang学习笔记29——golang 中如何将 GitHub 最新提交的版本设置为 v1.0.0
笔记·git·后端·学习·golang·github·源代码管理
羊小猪~~1 小时前
深度学习基础案例5--VGG16人脸识别(体验学习的痛苦与乐趣)
人工智能·python·深度学习·学习·算法·机器学习·cnn
Charles Ray2 小时前
C++学习笔记 —— 内存分配 new
c++·笔记·学习
重生之我在20年代敲代码2 小时前
strncpy函数的使用和模拟实现
c语言·开发语言·c++·经验分享·笔记
骑鱼过海的猫1233 小时前
【tomcat】tomcat学习笔记
笔记·学习·tomcat
贾saisai5 小时前
Xilinx系FPGA学习笔记(九)DDR3学习
笔记·学习·fpga开发