过场动画(Cutscene)系统
本页解释 GTAV 的过场动画:离线导出的 cut 文件数据格式(cutfCutsceneFile2、对象、事件、事件参数)、RAGE 运行时(cutsManager 状态机、事件派发、时间轴、分段与拼接)、以及游戏层 CutSceneManager 的接入(流式加载、实体映射、音频主时钟、跳过与阻断标签、脚本接口)。过场动画是一套独立于 MoVE/AnimScene 的“时间轴 + 事件”系统,最终仍通过动画任务驱动角色的动作树。
背景与相关页面#
- 动画核心与动作树:rage-animation-and-move.md;游戏动画接入(clip 字典 store、synced scene、AnimScene):game-animation-and-ik.md。
- cutscene 相机导演
camCutsceneDirector与相机动画的应用:../21-weapons-camera/camera-system.md(本页只说明实体接口)。 - 过场音频
g_CutsceneAudioEntity:../13-audio/game-audio.md。 CTaskCutScene等任务:../07-ai-tasks/task-catalogue.md。- 脚本原生命令注册机制:../14-script-runtime/natives-and-commands.md。
- PSO/parser:../02-rage-core/parser-and-metadata.md;流式 store:../04-rage-framework/streaming-engine.md。
- 回放录制(cutscene 可触发 replay 录制事件):../19-persistence-replay/replay-and-video.md。
相关源码文件#
| 文件 | 内容 |
|---|---|
rage/suite/src/cutfile/cutfile2.h/.cpp/.psc | cutfCutsceneFile2 数据模型与加载 |
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/.cpp | cutsManager 运行时 |
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_pCutsceneObjects | cutfObject* 数组(拥有),对象 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、lightxmlsrc/dev_ng/rage/suite/src/cutfile/cutfdefines.h:56-61。
3. 事件模型#
3.1 事件 id 空间#
| 范围 | 来源 | 示例 | 证据 |
|---|---|---|---|
0 .. 0x7f | cutfile 内置(导出数据中的事件) | 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 .. 0xff | cutscene 运行时内置 | 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 zoom | cutsevent.h:18-52 |
0x100 .. | 项目自定义 | SET_OVERLAY_PROPERTIES/METHOD、SET_VEHICLE_DAMAGE、SET_WATER_REFRACT_INDEX、SET_CASCADE_SHADOW_BOUNDS(_PROPERTIES)、CUSTOM_CLOTH、LOAD_INTERIOR | src/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:
- 正向播放:用游标
m_iNextEventIndex依序派发所有time <= 当前时间的事件;若场景是拼接的,只派发落在“可播放”拼接段中的事件(CLEAR_LIGHT有特例:刚越过有效段边界一帧内仍派发)。 - 适时触发结束淡出。
- BANK 下倒放/后退:逆序派发相反事件,回到 0 时把游标归零。
- 最后向所有实体广播
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),再UpdateSectionInfosrc/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(动画已分段而音频未分段),负值钳为 0src/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 请求、加载与开始#
- 请求:
RequestCutscene(name, bPlayNow, fades..., scriptId, playbackContextFlags):同一脚本重复请求直接返回;断言当前无活动过场且 store 中存在该槽;重置成员;bPlayNow时立即SetGameToCutSceneState()(关雷达、关玩家控制等),否则标记为 seamless;记录脚本线程与场景哈希、登记脚本资源,最后Load(...)src/dev_ng/game/Cutscene/CutSceneManagerNew.cpp:3779-3845。Load只保存淡入淡出选项并把状态置为CUTSCENE_LOAD_CUTFILE_STATEsrc/dev_ng/game/Cutscene/CutSceneManagerNew.cpp:1477-1493。 - cut 文件流式:
LoadCutFile以STRFLAG_PRIORITY_LOAD|STRFLAG_CUTSCENE_REQUIRED请求g_CutSceneStore槽src/dev_ng/game/Cutscene/CutSceneManagerNew.cpp:1498-1512;DoLoadingCutfileState在槽加载后SetCutfFile(pDef->m_pObject)并 AddRefsrc/dev_ng/game/Cutscene/CutSceneManagerNew.cpp:1596-1644。 - 资产加载:游戏版
DoLoadState额外处理拼接数据、校验音频加载/播放事件、对 load 事件排序,再创建实体并派发src/dev_ng/game/Cutscene/CutSceneManagerNew.cpp:1946-1980。 - 播放列表(
REQUEST_CUTSCENE_WITH_PLAYBACK_LIST):位掩码第 i 位为 0 的拼接段被标记bValidForPlayBack=falsesrc/dev_ng/game/Cutscene/CutSceneManagerNew.cpp:3648-3664、src/dev_ng/game/script/commands_cutscene.cpp:143;事件派发与时间推进都会跳过这些段(第 4.2、5.3 节)。 - 开始:脚本
START_CUTSCENE→PlaySeamlessCutScene(scriptId, flags):只有加载它的脚本可启动(否则断言),记录选项并置m_bCanStartCutscenesrc/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_MANAGER | CCutSceneAssetMgrEntity(单例成员 m_pAssetManger) | 模型/ityp/变体/overlay 等流式请求(strRequest/strModelRequest/strRequestArray<3>)src/dev_ng/game/Cutscene/CutSceneAssetManager.h:83-293 |
ANIMATION_MANAGER | CCutSceneAnimMgrEntity(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 |
CAMERA | CCutSceneCameraEntity | 驱动 camCutsceneDirector |
AUDIO | CCutSceneAudioEntity | 驱动 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_BOUNDS | CCutSceneFixupBoundsEntity / CCutSceneHiddenBoundsEntity / CCutSceneBlockingBoundsEntity 等 | 修正/隐藏世界物件、阻挡区域 |
LIGHT / ANIMATED_LIGHT | CCutSceneLightEntity | 过场灯光 |
PARTICLE_EFFECT / ANIMATED_PARTICLE_EFFECT | CCutSceneParticleEffectsEntity | 粒子 |
SUBTITLE、SCREEN_FADE | CCutSceneSubtitleEntity、CCutSceneFadeEntity | 字幕、淡入淡出 |
OVERLAY | CCutSceneScaleformOverlayEntity 或 CCutSceneBinkOverlayEntity | Scaleform/Bink 叠加 |
RAYFIRE、DECAL | CCutSceneRayFireEntity、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包含了它。