CD Code Digest Hub /GTA V · v2

过场动画(Cutscene)系统

50 分钟阅读 11 个章节 2 张图

本页解释 GTAV 的过场动画:离线导出的 cut 文件数据格式(cutfCutsceneFile2、对象、事件、事件参数)、RAGE 运行时(cutsManager 状态机、事件派发、时间轴、分段与拼接)、以及游戏层 CutSceneManager 的接入(流式加载、实体映射、音频主时钟、跳过与阻断标签、脚本接口)。过场动画是一套独立于 MoVE/AnimScene 的“时间轴 + 事件”系统,最终仍通过动画任务驱动角色的动作树。

背景与相关页面#

相关源码文件#

文件内容
rage/suite/src/cutfile/cutfile2.h/.cpp/.psccutfCutsceneFile2 数据模型与加载
rage/suite/src/cutfile/cutfobject.h/.psc对象类型(模型、相机、灯光、音频、粒子、bounds、overlay…)
rage/suite/src/cutfile/cutfevent.h、cutfeventargs.h、cutfeventdef.h事件 id、事件类型、事件参数、事件定义
rage/suite/src/cutfile/cutfdefines.h、cutfile.h常量(帧率、扩展名);旧格式 cutfCutsceneFile
rage/suite/src/cutscene/cutsmanager.h/.cppcutsManager 运行时
rage/suite/src/cutscene/cutsentity.h、cutsanimentity.h、cutsaudioentity.h、cutsboundsentity.h、cutsevent.h、cutseventargs.h运行时实体基类与运行时事件
game/Cutscene/CutSceneManagerNew.h/.cpp游戏层 CutSceneManager : cutsManager
game/Cutscene/CutSceneStore.*g_CutSceneStore(PSO 加载)
game/Cutscene/CutSceneAssetManager.*、CutSceneAnimManager.*资产/动画字典流式
game/Cutscene/AnimatedModelEntity.*、CutSceneCameraEntity.*、CutSceneLightEntity.*、CutSceneSoundEntity.*、CutSceneParticleEffect*.*、CutSceneOverlayEntity.*、CutSceneBoundsEntity.*、CutSceneFadeEntity.*、CutsceneObject.*游戏实体
game/Cutscene/CutsceneCustomEvents.h项目自定义事件
game/Cutscene/CutSceneDebugManager.*调试(__BANK)
game/script/commands_cutscene.cpp脚本命令

1. 三层架构#

图证据:store 以 PSO 加载 src/dev_ng/game/Cutscene/CutSceneStore.cpp:36-64;GetEntityObject 通过虚函数 ReserveEntity 创建实体 src/dev_ng/rage/suite/src/cutscene/cutsmanager.cpp:3130-3149;游戏覆写 src/dev_ng/game/Cutscene/CutSceneManagerNew.h:266、src/dev_ng/game/Cutscene/CutSceneManagerNew.h:739-745;CTaskCutScene 创建 src/dev_ng/game/Cutscene/AnimatedModelEntity.cpp:1742-1753;音频时钟 src/dev_ng/game/Cutscene/CutSceneManagerNew.cpp:4671-4673;脚本调用 src/dev_ng/game/script/commands_cutscene.cpp:140-156;相机实体使用 camCutsceneDirector(CutSceneCameraEntity.cpp 中通过 camInterface::GetCutsceneDirector 访问,见相机页)。

2. 数据格式:cutfCutsceneFile2#

2.1 顶层字段(parser psc)#

src/dev_ng/rage/suite/src/cutfile/cutfile2.psc:5-58:

字段含义
m_fTotalDuration总时长(秒)
m_cFaceDir、m_iCutsceneFlags[4]面部目录;128 位标志位集(见 2.2)
m_vOffset、m_fRotation、m_vTriggerOffset场景原点偏移、朝向、触发偏移
m_pCutsceneObjectscutfObject* 数组(拥有),对象 id 即数组下标
m_pCutsceneLoadEventList加载阶段事件(加载场景/字典/模型/音频…)
m_pCutsceneEventList播放阶段事件(按时间排序)
m_pCutsceneEventArgsList事件参数(拥有,事件通过索引共享)
m_attributes、m_cutfAttributes通用属性表
m_iRangeStart/End、m_iAltRangeEnd帧范围
m_fSectionByTimeSliceDuration、淡入淡出时长与颜色、m_iBlendOutCutsceneDuration/Offset、m_DayCoCHours分段/淡入淡出/混出/昼夜 CoC 小时掩码
m_cameraCutList、m_sectionSplitList相机切换时间点、分段切点
m_concatDataList(atFixedArray,CUTSCENE_MAX_CONCAT = 40)拼接段:场景名、偏移、起始时间、旋转/俯仰/翻滚、帧范围、bValidForPlayBack
m_discardFrameList每个子场景被丢弃的帧

SConcatData/SDiscardedFrameData 定义见 src/dev_ng/rage/suite/src/cutfile/cutfile2.psc:60-77、src/dev_ng/rage/suite/src/cutfile/cutfile2.h:129-170。帧率常量 CUTSCENE_FPS = 30.0f src/dev_ng/rage/suite/src/cutfile/cutfdefines.h:18。

2.2 场景标志#

ECutsceneFlags 包括:开始/结束时淡入淡出游戏或场景、长/短淡出、段间淡入淡出、关闭环境光/车灯、单一音轨、静音音乐播放器、允许电台泄漏、导出时骨骼 id 转换与相机插值、已分段(CUTSCENE_IS_SECTIONED_FLAG)及按相机切/时长/切点分段、使用父缩放、单一场景朝向、启用景深、故事模式、游戏内 DOF 起止、catch-up/blend-out 相机等 src/dev_ng/rage/suite/src/cutfile/cutfile2.h:74-118。

2.3 对象类型#

ECutsceneObjectType:AssetManager(每场景 1 个,负责加载)、Overlay、ScreenFade(全部淡入淡出共 1 个)、Subtitle、Model、HiddenModel、FixupModel、ParticleEffect、BlockingBounds、Light、Camera、Audio(全部音频共 1 个)、Events、AnimationManager(全部动画事件共 1 个)、AnimatedParticleEffect、RemovalBounds、Rayfire、Decal、AnimatedLight;自定义从 CUTSCENE_NUM_OBJECT_TYPES 起 src/dev_ng/rage/suite/src/cutfile/cutfobject.h:28-50。类层次以 cutfObject → cutfNamedObject → cutfNamedAnimatedObject / cutfNamedStreamedObject → cutfNamedAnimatedStreamedObject → cutfModelObject → cutfPed/Vehicle/Prop/WeaponModelObject 为主干,另有 Light/AnimatedLight、Camera、Audio、Bounds、Decal、ParticleEffect 等 src/dev_ng/rage/suite/src/cutfile/cutfobject.h:178-3068。灯光对象带大量 CUTSCENE_LIGHTFLAG_*(阴影、体积光、角色光、仅反射等)与按小时启用的位掩码 src/dev_ng/rage/suite/src/cutfile/cutfobject.h:73-110。

2.4 加载路径#

  • 运行时:g_CutSceneStore 是 fwAssetStore<cutfCutsceneFile2>(名 "CutSceneStore",容量参数 585)src/dev_ng/game/Cutscene/CutSceneStore.cpp:23;LoadFile 用 psoLoadFile(PSOLOAD_PREP_FOR_PARSER_LOADING, IGNORE_CHECKSUM) + psoInitAndLoadObject 载入,随后 InitExternallyLoadedFile(name, true) src/dev_ng/game/Cutscene/CutSceneStore.cpp:36-64、src/dev_ng/rage/suite/src/cutfile/cutfile2.h:220。
  • 开发/工具:cutfCutsceneFile2::LoadFile 按扩展名用 PARSER.LoadTree 解析 cutxml/cutbin/cuttune/cut 等(HACK_GTA4 下接受 cut),旧二进制格式已被编译掉(Quitf);加载后强制对象 id 连续、记录场景名,BANK 下还从灯光文件替换灯光 src/dev_ng/rage/suite/src/cutfile/cutfile2.cpp:490-560。扩展名常量:cutxml、cutbin、cuttune、cutsub、lightxml src/dev_ng/rage/suite/src/cutfile/cutfdefines.h:56-61。

3. 事件模型#

3.1 事件 id 空间#

范围来源示例证据
0 .. 0x7fcutfile 内置(导出数据中的事件)LOAD_SCENE、LOAD/UNLOAD_ANIM_DICT、LOAD_AUDIO、LOAD_MODELS、HIDE/SHOW_OBJECTS、FIXUP_OBJECTS、ADD/REMOVE_BLOCKING_BOUNDS、FADE_IN/OUT、SET/CLEAR_ANIM、PLAY/STOP_PARTICLE_EFFECT、SHOW/HIDE_OVERLAY、PLAY/STOP_AUDIO、SHOW/HIDE_SUBTITLE、SET_ATTACHMENT、SET_VARIATION、CAMERA_CUT、ENABLE/DISABLE_DOF、CATCHUP/BLENDOUT_CAMERA、TRIGGER/REMOVE_DECAL、一组 CASCADE_SHADOWS_*、SET/CLEAR_LIGHT、START/STOP_REPLAY_RECORD、第一人称 blend-out/catch-up 相机cutfevent.h:31-151
0x80 .. 0xffcutscene 运行时内置START_OF_SCENE、END_OF_SCENE、PLAY、UPDATE_FADING_OUT_AT_BEGINNING、UPDATE_LOADING、UPDATE、UPDATE_UNLOADING、UNLOADED、PAUSE、STOP、CANCEL_LOAD、SET_(DUAL_)ANIMATION/CLIP、DICTIONARY_LOADED、SKIPPED、调试用 step/fast-forward/rewind/restart/face zoomcutsevent.h:18-52
0x100 ..项目自定义SET_OVERLAY_PROPERTIES/METHOD、SET_VEHICLE_DAMAGE、SET_WATER_REFRACT_INDEX、SET_CASCADE_SHADOW_BOUNDS(_PROPERTIES)、CUSTOM_CLOTH、LOAD_INTERIORsrc/dev_ng/game/Cutscene/CutsceneCustomEvents.h:21-30

每个事件 id 有“相反事件”(倒放/卸载时派发;CUTSCENE_OPPOSITE_EVENT_USE_PREVIOUS = -1 表示回找上一个同 id 事件,CUTSCENE_NO_OPPOSITE_EVENT = -2 表示无)与排序 rank(内置播放事件 < 255,项目事件从 256 起,卸载事件以 65535 为基准倒数)src/dev_ng/rage/suite/src/cutfile/cutfevent.h:153-172;项目事件的显示名、rank(均为 CUTSCENE_LAST_EVENT_RANK + 1)与相反事件(均无)由 CutsceneCustomEvents.h 中的表提供 src/dev_ng/game/Cutscene/CutsceneCustomEvents.h:35-105。

3.2 事件类型与参数#

事件分三种派发类型:CUTSCENE_EVENT_TYPE(广播给所有实体)、CUTSCENE_OBJECT_ID_EVENT_TYPE(单对象)、CUTSCENE_OBJECT_ID_LIST_EVENT_TYPE(对象列表)src/dev_ng/rage/suite/src/cutfile/cutfevent.h:22-29,对应类 cutfEvent、cutfObjectIdEvent、cutfObjectIdListEvent src/dev_ng/rage/suite/src/cutfile/cutfevent.h:203、src/dev_ng/rage/suite/src/cutfile/cutfevent.h:451、src/dev_ng/rage/suite/src/cutfile/cutfevent.h:511。参数类族包括 cutfNameEventArgs、cutfLoadSceneEventArgs、cutfObjectIdNameEventArgs、cutfAttachmentEventArgs、cutfObjectIdListEventArgs、cutfPlayParticleEffectEventArgs、cutfTriggerLightEffectEventArgs、cutfObjectVariationEventArgs、cutfVehicleVariationEventArgs、cutfVehicleExtraEventArgs、cutfSubtitleEventArgs、cutfCameraCutEventArgs(含按昼夜的 DOF 修正 cutfCameraCutTimeOfDayDofModifier)、cutfDecalEventArgs、cutfCascadeShadowEventArgs 等 src/dev_ng/rage/suite/src/cutfile/cutfeventargs.h:76-2506。

4. 运行时:cutsManager#

4.1 状态机#

ECutsceneState src/dev_ng/rage/suite/src/cutscene/cutsmanager.h:363-387:

图证据:PreSceneUpdate 按状态分派 Do*State src/dev_ng/rage/suite/src/cutscene/cutsmanager.cpp:1083-1175;DoLoadState:进入 STREAMING_ASSETS_STATE,为 load event 涉及的对象预先创建实体,派发全部 load 事件(若淡出被覆写则跳过 FADE_OUT),转 LOADING src/dev_ng/rage/suite/src/cutscene/cutsmanager.cpp:2232-2269;DoLoadingState:所有实体不再 IsLoading 后创建全部实体、置 PAUSED,m_bPlayNow 时 Play() src/dev_ng/rage/suite/src/cutscene/cutsmanager.cpp:2271-2329;游戏 StartCutscene 在非 FINAL 未授权时转 CUTSCENE_AUTHORIZED_STATE src/dev_ng/game/Cutscene/CutSceneManagerNew.cpp:4916-4931;CUTSCENE_AUTHORIZED_FOR_PLAYBACK 定义为 !__FINAL src/dev_ng/rage/suite/src/cutscene/cutsmanager.h:329。图中 SKIPPING/LOADING_BEFORE_RESUMING/CANCELLING/UNLOADING 之间的具体迁移条件来自状态注释与函数名,未逐个展开实现。

观察:PreSceneUpdate 的 CUTSCENE_UNLOADING_STATE 分支缺少 break,落入 default: break,无实际影响 src/dev_ng/rage/suite/src/cutscene/cutsmanager.cpp:1168-1173。另有流式子状态 STREAMING_IDLE/CUTFILE/ASSETS 与播放子状态(正常/倍速/倒放/暂停/跳过)src/dev_ng/rage/suite/src/cutscene/cutsmanager.h:1202-1207、src/dev_ng/rage/suite/src/cutscene/cutsmanager.h:345-352。

4.2 播放与事件派发#

DoPlayState 首次派发 CUTSCENE_START_OF_SCENE_EVENT,然后 UpdatePlayBackEvents(),并在到达结束时间时 Stop(SKIP_FADE, ...) src/dev_ng/rage/suite/src/cutscene/cutsmanager.cpp:2470-2575。UpdatePlayBackEvents src/dev_ng/rage/suite/src/cutscene/cutsmanager.cpp:2356-2468:

  1. 正向播放:用游标 m_iNextEventIndex 依序派发所有 time <= 当前时间 的事件;若场景是拼接的,只派发落在“可播放”拼接段中的事件(CLEAR_LIGHT 有特例:刚越过有效段边界一帧内仍派发)。
  2. 适时触发结束淡出。
  3. BANK 下倒放/后退:逆序派发相反事件,回到 0 时把游标归零。
  4. 最后向所有实体广播 CUTSCENE_UPDATE_EVENT,参数含当前时间、delta、分段起点与分段时长。

DispatchEvent 按事件类型分发:广播型交给所有实体;对象型通过对象 id 找到 SEntityObject{pObject, pEntity} 后调用实体的 DispatchEvent;BANK 下对 LOAD_SCENE/CAMERA_CUT 用编辑器中的最新偏移/裁剪距离重建参数 src/dev_ng/rage/suite/src/cutscene/cutsmanager.cpp:2686-2760。实体接口为 cutsEntity::DispatchEvent(manager, object, eventId, args, time, stickyId);派生出 cutsUniqueEntity(每对象一个)与 cutsSingletonEntity src/dev_ng/rage/suite/src/cutscene/cutsentity.h:29-52、src/dev_ng/rage/suite/src/cutscene/cutsentity.h:96、src/dev_ng/rage/suite/src/cutscene/cutsentity.h:139。

4.3 时间轴、分段与拼接#

  • 时间源(RAGE 默认实现):PostSceneUpdate 在播放或末尾淡出时计算新时间(BANK:可选时间源 VCR;非 FINAL:VCR;FINAL:GetDefaultTime),再 UpdateSectionInfo src/dev_ng/rage/suite/src/cutscene/cutsmanager.cpp:1223-1261。GetDefaultTime:非 PS3 平台若有音频时间则直接采用音频时间,PS3 上则累加 dt 并在偏离音频超过 CUTSCENE_AUDIO_RESYNC_TIME 时重同步 src/dev_ng/rage/suite/src/cutscene/cutsmanager.cpp:3334-3375。音频时间来自音频实体,分段场景需减去 RangeStart / CUTSCENE_FPS(动画已分段而音频未分段),负值钳为 0 src/dev_ng/rage/suite/src/cutscene/cutsmanager.cpp:3441-3493。游戏层覆写 PostSceneUpdate 并在 PreSceneUpdate 中自行推进时间(第 5.3 节)。
  • 分段(section):带 CUTSCENE_IS_SECTIONED_FLAG 的场景按 m_fSectionStartTimeList 计算当前分段的起点与时长,否则整段 src/dev_ng/rage/suite/src/cutscene/cutsmanager.cpp:1177-1198。动画按分段导出到不同字典,cutsAnimationManagerEntity 负责字典流式与按分段取 clip,GetSectionedName 以 _%d 追加分段号 src/dev_ng/rage/suite/src/cutscene/cutsanimentity.h:51-115。调试宏 CUTSCENE_DEBUG_FINAL 的注释提到“2 个而不是 3 个字典缓冲”src/dev_ng/rage/suite/src/cutscene/cutsanimentity.h:40-41,这表明运行时通常对分段字典做三缓冲预取(推断)。
  • 拼接(concat):一个 cut 文件可拼接最多 40 个子场景,每段有自己的原点偏移/朝向与帧范围;UpdateSectionInfo 在当前拼接段变化时把场景原点切换为该段的偏移、旋转、俯仰、翻滚 src/dev_ng/rage/suite/src/cutscene/cutsmanager.cpp:1200-1220。

5. 游戏层:CutSceneManager#

5.1 生命周期与帧内位置#

  • 创建:CutSceneManagerWrapper::Init(INIT_CORE) → CutSceneManager::CreateInstance();SHUTDOWN_SESSION 时删除所有登记实体并关闭当前过场 src/dev_ng/game/Cutscene/CutSceneManagerNew.cpp:6225-6249;在 gameSkeleton 中注册 src/dev_ng/game/Core/game.cpp:1746、src/dev_ng/game/Core/game.cpp:1933。
  • 每帧两次:PreSceneUpdate(Misc 组,早于 CScene::Update 中的动画/AI/物理)与 PostSceneUpdate(fwTimer::GetTimeStep())(Render Update 组,晚于相机与 post-camera 动画)src/dev_ng/game/Core/game.cpp:2746、src/dev_ng/game/Core/game.cpp:2997、src/dev_ng/game/Cutscene/CutSceneManagerNew.cpp:6253-6263。完整帧序见 rage-animation-and-move.md。
  • PreSceneUpdate:持 sm_CutsceneLock;回放编辑模式下跳过;处理跳过请求与 m_bShouldStopNow;未暂停时 StartCutscene()、UpdateCutSceneTimer()、清理已终止脚本的资产,再调用 cutsManager::PreSceneUpdate()(状态机 + 事件派发);播放时抑制所有 shocking event,并控制小地图 src/dev_ng/game/Cutscene/CutSceneManagerNew.cpp:2775-2860。
  • PostSceneUpdate:DispatchUpdateEventPostScene;播放时 SetGameToCutSceneStatePostScene;单机下若玩家不可见且跨越拼接段,把玩家传送到场景原点以保证世界流式正确;暂停时仍向灯光对象派发 UPDATE(灯光在暂停时也要更新)src/dev_ng/game/Cutscene/CutSceneManagerNew.cpp:3001-3060。

5.2 请求、加载与开始#

  1. 请求:RequestCutscene(name, bPlayNow, fades..., scriptId, playbackContextFlags):同一脚本重复请求直接返回;断言当前无活动过场且 store 中存在该槽;重置成员;bPlayNow 时立即 SetGameToCutSceneState()(关雷达、关玩家控制等),否则标记为 seamless;记录脚本线程与场景哈希、登记脚本资源,最后 Load(...) src/dev_ng/game/Cutscene/CutSceneManagerNew.cpp:3779-3845。Load 只保存淡入淡出选项并把状态置为 CUTSCENE_LOAD_CUTFILE_STATE src/dev_ng/game/Cutscene/CutSceneManagerNew.cpp:1477-1493。
  2. cut 文件流式:LoadCutFile 以 STRFLAG_PRIORITY_LOAD|STRFLAG_CUTSCENE_REQUIRED 请求 g_CutSceneStore 槽 src/dev_ng/game/Cutscene/CutSceneManagerNew.cpp:1498-1512;DoLoadingCutfileState 在槽加载后 SetCutfFile(pDef->m_pObject) 并 AddRef src/dev_ng/game/Cutscene/CutSceneManagerNew.cpp:1596-1644。
  3. 资产加载:游戏版 DoLoadState 额外处理拼接数据、校验音频加载/播放事件、对 load 事件排序,再创建实体并派发 src/dev_ng/game/Cutscene/CutSceneManagerNew.cpp:1946-1980。
  4. 播放列表(REQUEST_CUTSCENE_WITH_PLAYBACK_LIST):位掩码第 i 位为 0 的拼接段被标记 bValidForPlayBack=false src/dev_ng/game/Cutscene/CutSceneManagerNew.cpp:3648-3664、src/dev_ng/game/script/commands_cutscene.cpp:143;事件派发与时间推进都会跳过这些段(第 4.2、5.3 节)。
  5. 开始:脚本 START_CUTSCENE → PlaySeamlessCutScene(scriptId, flags):只有加载它的脚本可启动(否则断言),记录选项并置 m_bCanStartCutscene src/dev_ng/game/Cutscene/CutSceneManagerNew.cpp:4982-5006。下一次 PreSceneUpdate 中 StartCutscene():玩家存在且未受伤时,若已加载则 SetGameToCutSceneState() + Play();若尚未加载完(预流式失败)则强制淡出进入 FADING_OUT 并在加载完成后自动播放(任务内请求会断言要求脚本等待加载)src/dev_ng/game/Cutscene/CutSceneManagerNew.cpp:4902-4979。

5.3 时间更新:音频主时钟、跳过与阻断标签#

UpdateCutSceneTimer 每帧缓存上一时间;非 FINAL 下按擦洗(scrubbing)状态用帧号或倍速时间;否则调用 UpdateTime();随后应用阻断标签并钳到 [m_fStartTime, m_fEndTime],若阻断使时间跳入不可播放的拼接段,再跳到下一个有效段起点 src/dev_ng/game/Cutscene/CutSceneManagerNew.cpp:4400-4533。

UpdateTime src/dev_ng/game/Cutscene/CutSceneManagerNew.cpp:4576-4700:

情形时间来源
跳过中(LOADING_BEFORE_RESUMING/SKIPPING)或刚从跳过恢复m_SkipFrame / CUTSCENE_FPS
跳过后继续播放累加 fwTimer::GetTimeStep_ScaledNonClipped()(不再用音频)
无音频对象、单步、或 BANK 外部时间步累加游戏时间步 / 外部帧 × 步长
正常g_CutsceneAudioEntity.GetCutsceneTime()/1000(BANK 下断言音频时间不回退)

阻断标签:AdjustTimeForBlockingTags 取当前时间对应分段的相机 clip,在分段局部时间上调用 crClip::CalcBlockedTime src/dev_ng/game/Cutscene/CutSceneManagerNew.cpp:4285-4330。后者对名为 Block 的标签:若当前相位落在标签区间内,按 Division 属性(默认 0.5)把相位吸附到区间起点或终点,Focus 为真时吸附到分割点 src/dev_ng/rage/suite/src/crclip/clip.h:674-687、src/dev_ng/rage/suite/src/crclip/clip.cpp:386-420。动作树的 clip 节点同样使用“blocked time”(合成器读取 player.GetBlockedTime())src/dev_ng/rage/suite/src/crmotiontree/composer.cpp:456-459。这表明 Block 标签用于在导出后“剪掉”一段动画(与 m_discardFrameList 的丢弃帧对应,推断)。另有 clip 标签 CBlockCutsceneSkippingTag 用于阻止玩家跳过(见游戏动画页第 7 节)。

5.4 实体映射(ReserveEntity)#

src/dev_ng/game/Cutscene/CutSceneManagerNew.cpp:5024-5190:

cutf 对象类型游戏实体说明
ASSET_MANAGERCCutSceneAssetMgrEntity(单例成员 m_pAssetManger)模型/ityp/变体/overlay 等流式请求(strRequest/strModelRequest/strRequestArray<3>)src/dev_ng/game/Cutscene/CutSceneAssetManager.h:83-293
ANIMATION_MANAGERCCutSceneAnimMgrEntity(m_pAnimManager)按分段请求 clip 字典(STRFLAG_CUTSCENE_REQUIRED|STRFLAG_PRIORITY_LOAD),检查加载,卸载时清标志并 Release src/dev_ng/game/Cutscene/CutSceneAnimManager.cpp:40-190
MODEL(ped/vehicle/prop/weapon)CCutsceneAnimatedActorEntity / CCutsceneAnimatedVehicleEntity / CCutSceneAnimatedPropEntity / CCutSceneAnimatedWeaponEntity创建或接管游戏实体,播放 CTaskCutScene
CAMERACCutSceneCameraEntity驱动 camCutsceneDirector
AUDIOCCutSceneAudioEntity驱动 g_CutsceneAudioEntity(Trigger/Stop/Pause/Skip/IsTrackPrepared)src/dev_ng/game/Cutscene/CutSceneSoundEntity.cpp:51-76、src/dev_ng/game/Cutscene/CutSceneSoundEntity.cpp:204-221
FIXUP_MODEL / HIDDEN_MODEL / BLOCKING_BOUNDS / REMOVAL_BOUNDSCCutSceneFixupBoundsEntity / CCutSceneHiddenBoundsEntity / CCutSceneBlockingBoundsEntity 等修正/隐藏世界物件、阻挡区域
LIGHT / ANIMATED_LIGHTCCutSceneLightEntity过场灯光
PARTICLE_EFFECT / ANIMATED_PARTICLE_EFFECTCCutSceneParticleEffectsEntity粒子
SUBTITLE、SCREEN_FADECCutSceneSubtitleEntity、CCutSceneFadeEntity字幕、淡入淡出
OVERLAYCCutSceneScaleformOverlayEntity 或 CCutSceneBinkOverlayEntityScaleform/Bink 叠加
RAYFIRE、DECALCCutSceneRayFireEntity、CCutSceneDecalEntity预制破坏、贴花

模型实体类层次:CCutsceneAnimatedModelEntity : cutsUniqueEntity,派生 Prop(→Weapon)、Vehicle、Actor,另有 CCutSceneRayFireEntity src/dev_ng/game/Cutscene/AnimatedModelEntity.h:100-648。角色动画通过任务驱动:CreateCutsceneTask 取场景朝向矩阵与相位增量,创建 CTaskCutScene(clip, sceneMat, phase, eventTime);Prop 在每个 UPDATE/PAUSE 事件中刷新任务相位,并在 stop 后按需创建“仅重定位”的游戏实体、标记可交还游戏 src/dev_ng/game/Cutscene/AnimatedModelEntity.cpp:1727-1774。演员实体在创建游戏 ped 时处理组件变体(越界变体回退到默认)src/dev_ng/game/Cutscene/AnimatedModelEntity.cpp:2522-2632。脚本可用 REGISTER_ENTITY_FOR_CUTSCENE 预先把现有实体登记给某个场景句柄(RegisterGameEntity),使过场接管而非新建该实体 src/dev_ng/game/Cutscene/CutSceneManagerNew.cpp:268、src/dev_ng/game/script/commands_cutscene.cpp:681-707。

6. 脚本接口#

commands_cutscene.cpp 注册约 73 个原生命令(SCR_REGISTER_SECURE),代表性的有 REQUEST_CUTSCENE、REQUEST_CUTSCENE_WITH_PLAYBACK_LIST、REMOVE_CUTSCENE、HAS_CUTSCENE_LOADED、REQUEST_CUT_FILE、START_CUTSCENE、START_CUTSCENE_AT_COORDS、STOP_CUTSCENE、SET_CUTSCENE_ORIGIN、GET_CUTSCENE_TIME、IS_CUTSCENE_PLAYING、REGISTER_ENTITY_FOR_CUTSCENE、CAN_SET_EXIT_STATE_FOR_REGISTERED_ENTITY、SET_CUTSCENE_PED_COMPONENT_VARIATION src/dev_ng/game/script/commands_cutscene.cpp:1229-1318。REQUEST_CUTSCENE 系列以 bPlayNow=false、全部 SKIP_FADE 调用 RequestCutscene(另一变体使用 FORCE_FADE 且立即播放)src/dev_ng/game/script/commands_cutscene.cpp:140-156;START_CUTSCENE* 调 PlaySeamlessCutScene src/dev_ng/game/script/commands_cutscene.cpp:310-348。典型脚本流程:请求(预流式,seamless)→ 轮询 HAS_CUTSCENE_LOADED → 登记实体/设置变体 → START_CUTSCENE → 轮询 CAN_SET_EXIT_STATE_FOR_REGISTERED_ENTITY 交还实体 → REMOVE_CUTSCENE(基于命令语义的推断,未逐个阅读脚本)。

7. 调试与构建差异#

  • CUTSCENE_AUTHORIZED_FOR_PLAYBACK = !__FINAL:开发版存在“已批准过场列表”(AuthorizedCutscene/ApprovedCutsceneList),未批准的过场进入 CUTSCENE_AUTHORIZED_STATE(属于内容审批流程,不是 DRM)src/dev_ng/rage/suite/src/cutscene/cutsmanager.h:329、src/dev_ng/game/Cutscene/CutSceneManagerNew.h:211-265、src/dev_ng/game/Cutscene/CutSceneManagerNew.cpp:3847-3851。
  • ENABLE_CUTSCENE_TELEMETRY 仅在 ENABLE_STATS_CAPTURE && __BANK 时开启(灯光遥测,开发统计用)src/dev_ng/game/Cutscene/CutSceneManagerNew.h:72-76。
  • BANK 下:VCR 控件(倒放、单步、快进、擦洗时间线、循环区间)、编辑灯光/隐藏物件/修正物件/阻挡体/绘制距离并回存 cut 文件(cutsManager::Save*)、CutSceneDebugManager(约 276 KB)src/dev_ng/rage/suite/src/cutscene/cutsmanager.cpp:4905-5331。
  • PS3 与其他平台的时间同步策略不同(4.3)。

8. 约束与边界行为#

  • 同一时间只能有一个活动过场(RequestCutscene 断言 !m_bIsCutSceneActive);只有加载过场的脚本可启动它。
  • 对象 id 必须等于其在对象数组中的下标(加载后 EnforceSequentialObjectIds)src/dev_ng/rage/suite/src/cutfile/cutfile2.cpp:548-552。
  • cut 文件缺失时 DispatchEvent/DoLoadState 等直接转入 UNLOAD 状态并复位流式状态(防御路径)src/dev_ng/rage/suite/src/cutscene/cutsmanager.cpp:2686-2693。
  • 时间单调性依赖音频;音频时间回退在 BANK 下断言,跳过后切换为游戏时间步。
  • 播放开始时若资产未就绪会强制淡出等待,而不是黑屏播放。

9. 未决问题 / 证据不足#

  • CUTSCENE_SKIPPING_STATE、LOADING_BEFORE_RESUMING、CANCELLING、UNLOADING 的完整迁移逻辑与游戏覆写(DoSkippingState、DoUnloadState)未逐行阅读。
  • CCutsceneAnimatedActorEntity 的接管/交还(exit state)逻辑、SetGameToCutSceneState 中修改的全局状态清单未展开。
  • CUTSCENE_AUDIO_RESYNC_TIME 的数值未在头文件中找到定义位置。
  • 分段字典缓冲数(2 或 3)仅由注释推断。
  • 旧格式 cutfCutsceneFile(cutfile.h)在运行时是否仍被使用未确认;cutfile2.cpp 包含了它。