不兼容的变更
NarraLeaf-React 各版本间的破坏性变更与不兼容改动,以及各自的迁移方式
完整变更见 CHANGELOG
0.39.2
- 宿主收到的脚本错误(
RuntimeScriptError,通过GameConfig.onError拿到)的message现在只是那一句话。以前它后面还接着出错动作的 id、类型以及那个动作的整个构造栈,宿主把它显在面板里时,折叠线上方全是打包器的栈帧。现在这些各自成字段 ——error.action(id与type)、error.actionStack,以及仍然给出单字符串形式的error.composedMessage。靠解析 message 字符串来拆这几样东西的宿主要改成读字段。 把错误对象整个打进日志的不会丢任何东西:error.stack依旧带着完整拼接
0.36.0
ThroughColor和Exposure的hold已弃用,改用holdMs,单位是毫秒而不是占总时长的比例。没有holdMs时hold仍然被读取,所以不会编译不过- 同一个
hold值现在会比以前保持得久。 那个比例从来就不是它自称的比例:在默认缓动下,标称 30% 的保持实际只占墙上时间的 17.8%,所以全默认的ThroughColor跑在 300ms 上时纯色只保持了 53 毫秒。按旧行为调过节奏的转场会明显变慢;改用holdMs直接写你想要的长度
0.35.0
- 对话文本缩放默认开启。 一行先按
fontSize排,能装下就不动;一旦顶到盒子边缘,每多一个字都会重新测量并把字号降到刚好能装下整行,下限是autoFitMinFontSize。如果一个游戏的对话框尺寸当初就是按“会溢出”调的,那些行现在会变小而不是溢出。单个框用autoFit={false}关掉,全局用GameConfig.disableTextScaling
0.29.1
Camera.resetCamera在第一帧清除滤镜,不再让滤镜随时长一起缓动退出。姿态仍然缓动。原先靠这段时长让调色随平移一起淡出的场景,现在调色会立即消失
0.29.0
- 对话正文在横排与竖排下都按严格禁则排版,CJK 行内的拉丁词不再被拆开。断行位置与此前不同:原先会被拆开的词现在整体移到下一行,因此按旧断行量过的对话框可能多出一行。剧本不需要任何改动
- 严格禁则只在文档声明了语言时生效。承载播放器的页面若没有
lang,得到的是浏览器的默认规则,参见 Dialog
0.27.0
- 传给
Scene.jumpTo的过渡跨整个舞台播放,而不再作用于离场场景的背景图。立绘、文字以及其他所有层现在都参与跳转,不会在跳转结束时凭空消失。过渡本身的写法没有任何变化,但它的几何依据变成了舞台:Push位移的距离是舞台宽度,Mask铺在舞台矩形上,刻意小于舞台的背景会被一起扫过,而不再是被扫的那一张图。参见 JumpConfig JumpConfig.transition的类型从ImageTransition放宽为Transition。所有内置过渡两者都满足,因此已有调用不受影响allowSkipBackgroundTransition由allowSkipSceneTransition取代,默认值为true。旧的开关从来没有被读取过:背景过渡和其他图像一样受allowSkipImageTransition管辖。新开关管的是跳转所播放的舞台过渡。请在game.configure调用里改名,参见 GameConfig
0.26.0
Camera.reset现在叫Camera.resetCamera。每个元素都自带一个内部的reset()——新游戏开始或读档时引擎运行的生命周期钩子——而 Camera 却把这个名字给了可链式调用的创作辅助方法,于是newGame()从不恢复镜头姿态,平移或缩放过的故事会把那个取景带进下一次游玩。请把剧本里所有camera.reset(...)改名。 现在在 Camera 上调用reset()触及的是生命周期钩子:它立即恢复到配置的姿态,不做任何动画,返回的是 Camera 本身而不是可链式调用的动作LiveGame.undo不再接受动作 id,并且在无处可退时返回false而不再抛出异常。一行由它的令牌通过 restoreToHistory 指定。不带参数的undo()照常可用,而且现在读档之后同样有效——这是它此前从未做到过的LiveGame.getHistory不再包含播放头之前方的行。正常游玩期间没有任何变化;回退之后,当前行之外的那些行改由新的 getFuture 返回。因此用getHistory搭起来的回溯界面不会再列出尚未发生的内容LiveGame.restoreToHistory两个方向都够得着,并且不再丢弃目标行之后的那些行。此前依赖它裁剪回溯的代码,现在会发现那些行仍然可以抵达——移动的是播放头,而不是切断时间线- 存档格式 v3。
elementStates只列出状态与剧本所写不同的元素,读档会在应用存档之前重置每一个元素。v1 与 v2 存档在 0.26.0 中照常读取,但更旧的引擎无法正确读取 v3 存档:它会跳过那次重置,于是存档没有列出的元素会保留运行中的那一局塞给它们的状态。在引擎的动作派发之外写入元素状态的宿主应当调用element.markDirty(),否则存档不会带上它——在app.debug: true时,引擎会对发现的未标记状态发出警告。参见 SavedGame - Character 的名字现在会随存档保存。
setName的改动此前会在读档时被静默丢失;在角色揭晓之后存档,读回来仍然是「???」。更早版本写出的存档不含角色条目,仍可照常读取,读回后保留剧本所写的名字。由于角色现在也会占用存档条目,需要恢复存档的应用应当通过DevTools.setElementStaticId给自己的角色阵容命名 - Layer 不再把自己的姿态带出声明它的那个场景。离开场景现在会重置该场景摆上舞台的图层——配置的 z-index 与姿态——而不只是重置站在图层上的可显示元素;
newGame()同样如此。此前依赖图层在后续场景中保持移开或淡出状态的剧情,现在需要重新设置。故事镜头是例外 - 点击舞台会推进 ADV 对话,此前只有跳过键才会。点击会把正在打字的一行补完,并推进已经打完的一行;它从不「强制」,因此不会像按住跳过键那样一路跑完整个场景。此前自行基于
event:state.player.stageClick实现点击推进的应用,现在一次点击会推进两行
0.23.0
- Sound 的
type现在是 SoundBusId(SoundType | (string & {})),不再是SoundType。SoundType没有改动,依然导出,三个取值的含义也完全一致,因此只用这三个值的代码无需改动——但如果代码对音频的type做穷举switch、依赖它只有三个成员,现在需要补上 default 分支 Sound.voice()、Sound.bgm()和Sound.sound()现在为type提供默认值,而不是强制覆盖。Sound.voice({src, type: "alice"})此前会悄悄产生一段voice音频,现在产生的是alice总线上的音频。此前向工厂方法传入type并依赖它被忽略的代码,现在会真正生效Preference会复制传给它的默认值对象,而不是直接写入其中。同一进程中的两个Game不再共用同一个设置对象,拖动滑条也不再改写此后整个进程的Game.DefaultPreference。刻意去修改那个共享对象的宿主,现在必须改走game.preference
0.22.0
LiveGame.playSound以及对话行的语音,现在以Sound配置的音量开始播放,而不是满音量。Sound.voice({src, volume: 0.4})经这两条路径播放时,此前听起来是 1,现在是 0.4。显式传入目标音量的调用方不受影响- 对
bgm类型的音频调用Sound.play()不再抛出StaticScriptWarning,而是打印一条console.warn并正常播放。此前依靠这次抛出在构建链时明确失败的剧情,现在会照常运行
0.20.0
Chained*系列类型别名——ChainedControl、ChainedPersistent及其同类——已被移除。它们本就是@internal,从未出现在产出的声明文件中;此前使用它们的公开签名现在直接写出所代表的链式类型:Control.do()返回Proxied<Control, Chained<LogicAction.Actions>>,Persistent.set()返回Proxied<Persistent<T>, Chained<LogicAction.Actions>>。没有任何签名的形状发生变化,运行时行为也没有变动
0.19.1
StackFrameSnapshot.branches现在是StackSnapshot[],不再是「帧数组的数组」,因此一个分支会完整地到达——连同它的loop和tag——而不是被削减成它的帧。branches[i][0]变成branches[i].frames[0]。这个类型是实验性且只读的,所以选择直接纠正它,而不是另开一个平行字段
0.17.1
- fastForward 的
reason新增了"stalled"。既有取值的运行时行为不变,但返回类型变宽了:对reason做穷举switch的代码需要补上这个分支才能通过编译。忽略返回值的宿主不受影响 - 快进现在可能因为一个无法跳过的步骤而提前结束。每个挂起的行有
options.stepTimeout毫秒(默认10000)的时间去结算;超出该时限的步骤会以"stalled"结束本次快进,而不是继续越过它。此前快进会停在那里、返回的 Promise 两边都不结算,因此现在能正常工作的用法不会失效——但把「非"menu"即成功」当依据的宿主,现在需要把"stalled"区分出来。如果剧情会快进穿过较长的、无法跳过的媒体,请调高stepTimeout
0.17.0
onPreloadComplete、oncePreloadComplete、whenPreloadComplete()与event:preloaded.complete现在都在进入游戏之前触发——此时菜单可能还在屏幕上——而不是在newGame()挂载出场景之后。入口场景在故事被加载时就已被注册为预加载场景,这正是本次发布的目的。这不会导致任何编译失败;只是回调运行的时刻变了- 如果你用它来为加载步骤把关,它现在只会把这件事做得更好,无需改动
- 如果你用它来表示**「游戏内容已经上屏」**,请改用
onFirstSceneReady/whenFirstSceneReady()。这两者没有变化,仍然要求存在一个真正挂载的场景 - 详见预加载
0.16.0
过渡 API 围绕两个理念进行了重构:转场方式(引擎)使用 new 实例化并只接受一个选项对象,而它们播放的遮罩图案由 Mask 上的静态工厂方法构建,通过 pattern 选项传入
Dissolve和FadeIn不再接受位置参数new Dissolve(1000, easing)→new Dissolve({duration: 1000, easing})new FadeIn(500, [x, y], easing)→new FadeIn({duration: 500, offset: [x, y], easing})—— 注意参数从startPos改名为offset
SoftWipe、SoftIris和Blinds已移除,请使用 Reveal 搭配对应的图案new SoftWipe({duration, direction, feather})→new Reveal({duration, pattern: Mask.wipe({direction, feather})})new SoftIris({duration, center, feather})→new Reveal({duration, pattern: Mask.iris({center, feather})})new Blinds({duration, orientation, slats})→new Reveal({duration, pattern: Mask.blinds({orientation, slats})})
MaskTransition已移除,其硬边裁剪等价于使用零羽化图案的RevealMaskTransition.circle({duration, center})→new Reveal({duration, pattern: Mask.iris({center, feather: 0})})MaskTransition.wipe({duration, direction})→new Reveal({duration, pattern: Mask.wipe({direction, feather: 0})})
ThroughColor的静态工厂方法已移除,现在直接用new构造,几何形状通过pattern传入ThroughColor.fade({duration, color, hold})→new ThroughColor({duration, color, hold})ThroughColor.wipe({direction, feather, ...rest})→new ThroughColor({...rest, pattern: Mask.wipe({direction, feather})})ThroughColor.blinds({orientation, slats, ...rest})→new ThroughColor({...rest, pattern: Mask.blinds({orientation, slats})})ThroughColor.iris({center, feather, ...rest})→new ThroughColor({...rest, pattern: Mask.iris({center, feather}), inverted: true})—— 注意inverted: true:经典的圈入到黑是从四周向中心收拢,即该图案的反转方向
- 移除的选项类型:
SoftWipeOptions、SoftIrisOptions、BlindsOptions、MaskTransitionCircleOptions、MaskTransitionWipeOptions、ThroughColorFadeOptions、ThroughColorWipeOptions、ThroughColorBlindsOptions、ThroughColorIrisOptions。新导出的类型:DissolveOptions、FadeInOptions、RevealOptions、ThroughColorOptions、ThroughColorUncover、MaskPattern,以及各工厂方法对应的*PatternOptions类型
0.13.0
SavedGame的store现声明为 SerializedNamespaceData,不再是 StorableData。它携带的一直是带标签的形式,错的只是声明。存档格式本身没有变化,已有存档仍可正常读取 —— 但如果你的代码直接读取savedGame.game.store并依赖旧的声明,现在会看到它一直以来实际拿到的带标签形状- 0.12.x 及更早版本写出的存档重新可以正确读取,但有一个例外:在受影响的版本上读档后再存档产生的存档,其中的值在磁盘上被打了两层标签,而这无法与游戏真正存入的值区分开。此类存档不会被修复
image.darken(darkness, duration)现在会在duration内播放动画,而不再立即生效。此前只有同时传入缓动函数时动画才会运行,否则duration会被静默丢弃。若需要旧的瞬间生效行为,请传入0作为duration
0.9.0
JumpConfig.unloadScene已移除
0.8.0
Displayable.scale方法已变更。现在接受scaleX和scaleY两个参数,不再使用单个scale参数
0.7.0
Router已弃用,请使用更完整的LayoutRouterPage已重构game.config.skipKey和game.config.nextKey已弃用,请使用game.keyMap
0.6.0
- 游戏执行模型从单节点
currentAction切换为 StackModel。它支持:- 显式处理
Awaitable - 子栈递归调用
- 完整序列化与反序列化
- 在场景操作中中断调用栈
- 更好的分支与合并
- 反序列化和撤销时减少状态混乱
- 更完整地处理嵌套操作
- 显式处理
game.config.skipInterval已弃用,请使用GamePreference.skipInterval
0.5.0
game.config.cps已弃用,请使用GamePreference.cps- 菜单的
GameElementHistory.selected可能为null
0.4.0
game.config.elements.say.textInterval已弃用,请使用game.config.elements.say.cpsgame.config已重构,详情见 GameConfiggame.config.player已弃用,请使用game.configgame.config.elements已弃用,请使用game.configgame.config.elementStyles已弃用,请使用game.config
0.3.0
- NarraLeaf-React 现在要求 React 19 或更高版本
- Image 配置已变更:
config.src应为标签定义或字符串- 标签式图片配置中,作为解析器函数的
config.src移到config.src.resolve - 图片不能再标记为 wearable,请使用
image.wear或image.asWearableOf
Image方法变更:setAppearance、setTags、setSrc改为charapplyTransform改为transformwear是addWearable的新别名asWearableOf是bindWearable的新别名init、setPosition、dispose、copy已移除IImageTransition已移除,请使用ImageTransitionFade已移除,请使用 Dissolve,它接受相同的持续时间和缓动参数
Text方法变更:applyTransform改为transformapplyTransition已移除ITextTransition已移除,请使用TextTransition
Transform方法变更:overwrite已移除- Transformer API 已完全弃用
Scene方法和属性变更:activate、deactivate已移除,场景生命周期由游戏自动管理applyTransform已移除,请使用scene.background.transforminherit已移除requestImagePreload改为preloadImage
Sound方法变更:- 使用
copy创建新的声音实例 play、stop和setVolume可接收duration参数fade已移除,请使用setVolume
- 使用
- 可显示元素中,变换状态已从元素状态中分离
Sound配置变更:sync和type已移除- 使用
preload启用 Howler.js 的预加载 - 使用
seek设置初始播放位置
Scene配置不能再指定invertY和invertX,请使用 story 配置中的originTop、Center、Bottom、HBox和VBox已弃用,请使用PageRouterAPI- 所有
ITransition已弃用,请使用TransitionAPIFontSizeTransition改为FontSizeBaseImageTransition改为ImageTransitionBaseTextTransition改为TextTransition
0.2.2
SceneConfig.invertY默认值现在是true
0.2.0
Image构造函数签名已变更。第一个参数必须是配置对象
0.1.2
game.config.player.width和game.config.player.height不能再是字符串