更新记录

1.0.0(2026-11-10)

  • 新增原创森林主题路线塔防,三张地图、四类防御塔、标准/无尽模式、首领和技能。
  • 新增纯 UTS 同步规则会话、固定步进、暂停倍速、独立快照和有界诊断。
  • 新增完整启动加载、全屏主菜单、独立选关、战斗、胜负结算及本机续局流程。
  • 新增类型化关卡、经济、塔属性、规则、表现、音效与文案配置及边界校验。
  • 新增真实救援、道路陷阱、每塔索敌、手动集火、波次侦察及可配置连续迎敌。
  • 新增本地战绩、星级、关卡解锁、可选目标与冒险印记,保存失败可重试。
  • 新增同组功能图标、缺图回退、加载代际隔离、触控与弹框输入门禁。
  • 新增本地 Phaser 增强渲染与 WebView 承载,保留基础兼容画面、前后台暂停和资源释放。
  • 新增有界渲染启动阶段诊断、同局手动画面修复与明确兼容继续入口。
  • 新增 uni-app x 完整游戏与 uni-app Vue 2 / Vue 3 选项式 API 接入示例。
  • 新增外置图片/音频清单、差异下载、持久本地缓存、完整版本切换和离线回退。
  • 新增单页复制接入与资源准备状态,组件和共享脚本统一插件 alias。
  • 新增必要第三方来源与许可说明。

平台兼容性

uni-app x(5.34)

Chrome Safari Android iOS 鸿蒙 微信小程序
√ - √ - - ×

其他

多语言 暗黑模式 宽屏模式 蒸汽模式
× × √ ×

森境守卫(lizhao-forest-guard)

介绍

横屏优先的森林路线塔防,暖光营地与卡通玩具3D风格的2D战场构成完整游戏。纯UTS负责规则,Phaser负责增强绘图,uni-app x负责HUD、触控和全屏流程;2.5D是美术空间层次。横竖屏实际战场均覆盖扣除安全区后的可用视口,布防入口默认收起,默认地图不常驻“+”;点击可建地打开工具浮层,下方显示真实费用,点工具即建造。顶部和边缘HUD按塔位避让,竖屏复用紧凑边缘操作。Web通过同源iframe承载本地Phaser,App使用本地WebView,不把Phaser称为原生UTS引擎。新增可跳过手势引导、开场倒计时、真实救援与道路陷阱。另附uni-app Vue 2/3选项式API验证示例。规则在本地执行,不上传游戏数据,无广告或付费能力;图像与音频由外置资源包提供,插件保留固定版本 Phaser 与 DCloud uni.webview JavaScript。

插件提供九个公开同步规则方法,包含战局导出与恢复。增强画面支持启动阶段诊断、前台准备预算和手动修复:失败后暂停并保留当前防线,玩家可有限重试或选择兼容继续。uni-app 选项式示例用于规则 API 接入,不包含完整 uni-app x 页面的画面修复、连续迎敌或双槽持久化流程。App 须使用与当前 UTS 实现和归档格式匹配的编译产物及基座。

完整流程为“资源准备与加载 → 全屏主菜单 → 独立全屏选关 → 战斗 → 胜负结算”。主菜单包含继续当前局、开始冒险、无尽挑战、图鉴和音效;加载失败可重试,失败资源不计入成功进度。完整页面为 uni_modules/lizhao-forest-guard/example/uniappx/index.uvue,可以复制到自己已注册的页面。

完整页面共用原有游戏启动页处理素材下载、校验与画面准备,失败和重试也留在该页。百分比对应当前显示的阶段,未知总量显示“准备中”;素材与启动画面均已就绪后才允许“进入森林”。启动页固定携带 uni_modules/lizhao-forest-guard/static/entry-art/ 内的四张小尺寸插画,合计254078B,用于首次下载、断网和失败状态;不请求尚未准备好的外置图片,也不显示独立素材加载弹框。本地插画的显示完成不计入完整游戏素材进度,战斗及菜单仍使用准备后的外置素材。错误默认显示简短提示,可点击“查看错误详情”读取原始原因。启动舞台直接使用森林地面和角色脚下阴影,不叠加大范围光罩、描边平台或圆章。

功能特色

功能 解决的问题 对应 API / 配置
三张地图 林地、溪谷和遗迹各有12波标准内容,按真实战绩顺序解锁或开放试玩 getGameCatalogSync、levelId、levelUnlockMode
森林结算舞台 胜利庆典/失败鼓励、可跳过逐星与真实最佳/新章提示,无虚构货币 resultAnimationMs、motionEnabled;宿主本地progression计算
连续迎敌 首波手动,后续波次可选自动整备;暂停/离场保护和真实偏好保存 uni-app x模板autoWaveEnabled / autoWaveDefault / autoWaveDelayMs
波次侦察 引擎同源的下一波预告/本波计划,基础属性与实时剩余分开 快照可选waveIntel;宿主WaveIntel
每塔索敌 前线按进度、强敌按最大生命、近身按当前距离;升级保留、归档续玩 towerPriority动作、TowerState.priority、rules.defaultTargetPriority;不越射程
点怪集火 轻点怪物锁定,射程内优先攻击;再次轻点或点空地取消 targetEnemy动作、快照可选enemyTargetId、表现开关enemyTargeting
本关目标与冒险印记 当局目标与历史收藏分开,每章一页,真实通关/三星/全救援印记 levelObjectives、adventureMedals;宿主AdventureBook/progression
四类防御塔 快速单体、范围伤害、减速与高伤害分工 build、upgrade、sell
标准与无尽 完整通关目标和逐波挑战 mode、startWave
技能与操作控制 波内救场、暂停思考、两倍速 skill、pause、resume、speed
移动全屏战场 HUD 资源、建造、技能与波次直接围绕月夜战场操作 uni-app x 完整页面;外置场景、塔怪、技能与角色资源
纯规则模拟器 同一游戏可接入不同的渲染页面 九个同步 API,1000×620 逻辑坐标
Phaser增强画面 背景、塔怪、血条、弹道、射程与粒子,保留宿主HUD和操作 插件内lizhao-forest-guard组件;限频小绘制包
基础显示回退 加载失败、超时或主动选择兼容画面时保留战局 renderer: 'native'及failure事件;静态库仍会打包
手动画面修复 同局暂停、有限重试增强或兼容继续,保留失败报告 uni-app x模板rendererRecovery / rendererRetryLimit / rendererStartupTimeoutMs;组件startup事件
快照与诊断 界面不直接修改内部状态;失败可定位 getGameSnapshotSync、getGameDiagnosticsSync
公开配置 自定义关卡、塔属性、救援/陷阱站点与规则 createGameSync的catalog / rules,校验并按会话深拷贝
救援与道路陷阱 塔转火解救一次奖励;真实扣费、一次范围触发 targetRescue / placeTrap动作、trapSites/rescueTargets及陷阱规则

适合哪些场景

场景 推荐能力 使用边界
塔防波次侦察 获取同源编队、按需查看属性与应对提示 不改变随机/规则,App更新须匹配UTS联编产物
App 内嵌单机小游戏 使用完整 uni-app x 界面 App 需要匹配的 UTS 原生联编与设备验收
塔防规则教学 / 接入验证 使用选项式示例查看调用与失败路径 为 API 验证界面,不代表全屏成品 UI;无联网匹配、排行榜或服务端
自定义皮肤与关卡 替换素材和扩展 catalog 数据 改路线后需同步地图图像并复测可通关性
自动化平衡验证 按固定种子及动作顺序推进模拟器 逻辑测试不能代替桥接和设备性能测试

下载与导入

宿主 示例代码位置
uni-app API 接入验证示例:uni_modules/lizhao-forest-guard/example/uniapp/index.vue
uni-app x 全屏游戏示例:uni_modules/lizhao-forest-guard/example/uniappx/index.uvue

从基础到进阶:按业务模块使用

基础功能配置示例

先导入完整 uni_modules/lizhao-forest-guard/,再将 uni_modules/lizhao-forest-guard/example/uniappx/index.uvue 的内容复制到自己已在 pages.json 注册的 uni-app x(Vue 3 / Vapor / TypeScript)页面。示例的组件及辅助脚本全部通过 @/uni_modules/lizhao-forest-guard/... 引入,运行代码位于插件 static/,图像与音频由独立资源包提供;先完成资源准备,再进入游戏,不需要把其他组件或 TS 复制到页面目录。8 份共享 TS 的唯一位置为 uni_modules/lizhao-forest-guard/static/game/,表现配置在其中的 presentation.ts 维护。按本章平台配置示例为复制后的页面设置方向与系统栏,配置中的页面路径须换成自己的注册路径;这些设置只作用于该页面。

UTS 业务 API 仍只从插件根目录导入。以下适用于 uni-app x 页面脚本;计时器由页面持有。全部配置显式传入,避免未传参数与空值在桥接时产生歧义。woodland 是第一张地图,standard 为标准模式。

import { createGameSync, dispatchGameActionSync, getGameSnapshotSync, disposeGameSync } from '@/uni_modules/lizhao-forest-guard'
import type { GameRules, GameAction } from '@/uni_modules/lizhao-forest-guard'

const rules: GameRules = { defaultTargetPriority: 'front' }
const game = createGameSync({ levelId: 'woodland', mode: 'standard', seed: 20261107, rules: rules })
const built = dispatchGameActionSync(game.sessionId, {
  type: 'build', slotId: 1, towerId: 'arrow', value: 0
})
if (!built.ok) console.log(built.errSubject, built.errCode, built.errMsg)
const strategy: GameAction = { type: 'towerPriority', slotId: 1, towerId: '', value: 0, priority: 'strong' }
const selected = dispatchGameActionSync(game.sessionId, strategy)
if (!selected.ok) console.log(selected.errSubject, selected.errCode, selected.errMsg)
const started = dispatchGameActionSync(game.sessionId, {
  type: 'startWave', slotId: 0, towerId: '', value: 0
})
if (!started.ok) console.log(started.errCode, started.errMsg)
console.log(getGameSnapshotSync(game.sessionId))
console.log(disposeGameSync(game.sessionId))

创建、读取及推进的参数或会话错误会抛出带 errSubject/errCode/errMsg 的异常,页面应在最外层 try/catch 显示真实错误;派发与释放以 GameResult 返回业务结果。上段只展示初始化和操作,不自行启动循环。

使用完整uni-app x游戏时,在uni_modules/lizhao-forest-guard/static/game/presentation.ts的现有GAME_PRESENTATION中设置rendererRecovery、rendererRetryLimit与rendererStartupTimeoutMs,完整形状见下方模板配置;不传给UTS规则API。下面的 alias 引入可在任意已注册页面脚本内独立核对同一校验器的默认恢复参数。默认失败后由玩家选择,不自动重试。

import { normalizeRendererRecoveryConfig } from '@/uni_modules/lizhao-forest-guard/static/game/renderer-recovery'
const recovery = normalizeRendererRecoveryConfig({ enabled: true, retryLimit: 2, startupTimeoutMs: 20000 })
console.log(recovery.config, recovery.issues)

高级示例

通过公开配置创建自定义游戏

优先从根API获取完整目录副本再修改,通过catalog与rules传入创建参数。catalog是完整替换,不是局部深合并:必须保留四个既有塔行为ID且各出现一次,关卡可替换为自己的1..32项。rules只覆盖填写的字段,其余使用默认值。以下uni-app x脚本覆盖关卡、塔属性、原规则与四项陷阱规则,使用完释放会话。

import { getGameCatalogSync, createGameSync, getGameSnapshotSync, dispatchGameActionSync, disposeGameSync } from '@/uni_modules/lizhao-forest-guard'
import type { GameRules, GameAction } from '@/uni_modules/lizhao-forest-guard'

const catalog = getGameCatalogSync()
const practice = catalog.levels[0]
practice.id = 'practice-garden'
practice.name = '练习花园'
practice.subtitle = '学习布防与技能时机'
practice.difficulty = '练习'
practice.description = '自定义短关卡,以较多金币练习组合。'
practice.startingGold = 650
practice.waves = 6
practice.enemyHealthMultiplier = 1.2
practice.route = [{ x: 0, y: 180 }, { x: 500, y: 180 }, { x: 500, y: 480 }, { x: 1000, y: 480 }]
practice.slots = [{ id: 1, x: 180, y: 280 }, { id: 2, x: 650, y: 350 }]
practice.trapSites = [{ id: 1, x: 110, y: 180 }, { id: 2, x: 500, y: 300 }]
practice.rescueTargets = [{ id: 1, name: '练***灵', x: 180, y: 350, hp: 120, rewardGold: 90 }]
catalog.levels = [practice]
const archer = catalog.towers[0]
archer.name = '训练哨塔'
archer.role = '练习 · 单体'
archer.description = '降低价格以便尝试布防。'
archer.color = '#65b98a'
archer.cost = 60
archer.damage = 20
archer.range = 240
archer.intervalMs = 700
const rules: GameRules = { defaultTargetPriority: 'near', startingLives: 30, enemyHealthMultiplier: 0.8, enemySpeedMultiplier: 0.9, upgradeDamageMultiplier: 1.8, sellRefundRatio: 0.6, meteorCooldownMs: 20000, blizzardCooldownMs: 24000, trapCost: 80, trapDamage: 100, trapRadius: 95, trapSlowMs: 2400 }
let sessionId = 0
try {
  const game = createGameSync({ levelId: 'practice-garden', mode: 'standard', seed: 42, catalog: catalog, rules: rules })
  sessionId = game.sessionId
  catalog.levels[0].startingGold = 1
  rules.startingLives = 1
  // 创建时逐层复制,外部修改不污染已创建的局:仍为650金币、30生命。
  const snapshot = getGameSnapshotSync(sessionId)
  console.log(snapshot.gold, snapshot.maxLives)
  const built = dispatchGameActionSync(sessionId, { type: 'build', slotId: 1, towerId: 'arrow', value: 0 })
  if (!built.ok) console.log(built.errSubject, built.errCode, built.errMsg)
  const strategy: GameAction = { type: 'towerPriority', slotId: 1, towerId: '', value: 0, priority: 'strong' }
  const selected = dispatchGameActionSync(sessionId, strategy)
  if (!selected.ok) console.log(selected.errSubject, selected.errCode, selected.errMsg)
  console.log(getGameSnapshotSync(sessionId).towers[0].priority) // 以真实快照为准
} catch (error) {
  console.log(error)
} finally {
  if (sessionId > 0) console.log(disposeGameSync(sessionId))
}
// 非法配置会在创建前抛出 errSubject=lizhao-forest-guard、errCode=9101001。
try { createGameSync({ levelId: 'woodland', mode: 'standard', seed: 42, rules: { startingLives: 0 } }) }
catch (error) { console.log(error) }

此脚本验证规则配置,不自动生成practice-garden的背景、投影和主页关卡入口。自己的游戏显示层应保存对应目录、配置资源映射并校准路线;getGameCatalogSync()始终返回内置默认目录副本,不作为已创建自定义会话的配置查询。uni_modules/lizhao-forest-guard/example/uniapp/index.vue的“自定义配置开局”按钮保留内置地图几何,仅改变金币/波数/塔价格/规则,能直接观察真实状态变化;同一按钮可恢复默认。

战局导出、恢复与本机继续

import { createGameSync, getGameSaveSync, restoreGameSync, disposeGameSync } from '@/uni_modules/lizhao-forest-guard'
const original = createGameSync({ levelId: 'woodland', mode: 'standard', seed: 42 })
try {
  const serialized = getGameSaveSync(original.sessionId)
  const restored = restoreGameSync(serialized)
  console.log(restored.sessionId, restored.state) // 新会话;本例ready仍为ready
  disposeGameSync(restored.sessionId)
} catch (error) { console.log(error.errSubject, error.errCode, error.errMsg) }
finally { disposeGameSync(original.sessionId) }
try { restoreGameSync('{"version":999}') }
catch (error) { console.log(error.errCode, error.errMsg) } // 真实9101001

新导出存档version=1、engineFormat=2;自包含完整catalog、归一化rules、快照和runtime(RNG状态、tick、nextId、固定步进余量accumulator、出生计时spawnTimer/已出生数及待出生余量)。保存真实敌人/塔/技能冷却/救援/陷阱/目标与波次队列进度,不以动作重放猜测当前局;瞬态shots清空,伤害已经结算,不会恢复后重复伤害。running恢复为paused,原paused保持暂停并保留恢复来源,ready仍为ready;不按墙钟推进离线时间。恢复不复用存档sessionId,不释放原局,失败不注册半个会话;调用方负责释放不需要的旧局。未知格式拒绝,没有跨未来格式迁移承诺。

格式2保存会话默认索敌策略及每塔策略,坏值(含null或缺字段)严格拒绝,不回退。恢复格式1时,仅缺少rules.defaultTargetPriority及各塔priority的旧档迁移为front;格式1夹带任一新字段(即使为null)作为混合档拒绝。旧引擎拒绝格式2,不能降级后丢掉策略。外层双槽容器与键、原catalog及宿主原始GAME_RULES内容指纹保持不变;格式迁移由Core校验完成。策略成功更改即标脏并立即尝试检查点保存,失败按真实提示重试;升级保留策略,出售后重建回会话默认值。

导出与解析共用归档校验:字符串最多1048576个UTF-16代码单元;塔≤64、敌人≤1024、陷阱≤16、技能恰好2,救援与关卡目标数量一致。增长预算:金币/得分≤10^12,tick/ID/击杀≤2147483647,elapsedMs≤107374182350且为50ms整数倍,无尽波次≤1000000。超预算活动局仍可运行,但导出失败,不截断状态或伪报保存成功。坏档/损坏/不一致为9101001,终态不能续玩为9101003,无效活动会话为9101002,恢复与创建共用最多8个活动会话预算9101008。

宿主uni_modules/lizhao-forest-guard/static/game/battle-save.ts使用命名空间内仅两个键<namespace>-a-v1/<namespace>-b-v1轮流写检查点;容器有代数、保存时间、内容指纹与意外损坏校验。FNV-1a hash是非安全校验,不防作弊;读取/写入/写后读回失败保留真实错误,不能只凭setStorageSync未抛错宣称成功。内容配置不匹配拒绝续玩;规则档仍由插件再次完整校验。正常结束/明确弃局写双墓碑,避免单槽坏掉时复活旧局;删除失败也必须如实报告。该存储不是云存档,不同步设备。

重要操作、返回主页、切后台及卸载保存;战斗中按配置节流检查点。系统强杀、存储异常、事件未送达时最多回到最近成功检查点,不保证绝对每2秒落盘。关闭battleSaveEnabled保留旧档,不删除成绩或旧局。uni-app选项式验证页另有导出、恢复、非法档按钮,仅内存保存字符串,不冒充完整游戏双槽持久化。

模板表现配置

规则/内容通过公开GameOptions配置;现有完整游戏的表现通过uni_modules/lizhao-forest-guard/static/game/presentation.ts中的GAME_PRESENTATION配置。下面是该文件可用的完整形状,修改后重新构建生效。它不是运行时任意换肤或用户JSON接口。

import type { EnemyIntelProfileOverride } from '@/uni_modules/lizhao-forest-guard/static/game/wave-intel-model'
import type { GameNoticeInput } from '@/uni_modules/lizhao-forest-guard/static/game/notice-model'
// GameArtworkOptions在实际presentation.ts中声明,见下方六字段表。

export const GAME_PRESENTATION = {
  brandName: '森境守卫',
  tagline: '守住微光,直到破晓',
  assetBase: '/uni_modules/lizhao-forest-guard/static/art/',
  landscapeBackground: 'grove-landscape-v1.png',
  artwork: {},
  battleSaveEnabled: true,
  battleSaveIntervalMs: 2000,
  battleSaveNamespace: 'grove-battle',
  announcementEnabled: true,
  announcements: undefined as GameNoticeInput[] | undefined,
  allowEndless: true,
  initialSound: false,
  soundVolume: 0.25,
  battleAnnouncements: true,
  bossHealthBar: true,
  waveIntel: true,
  enemyTargeting: true,
  towerStrategies: true,
  enemyIntelProfiles: [] as EnemyIntelProfileOverride[],
  firstPlayGuide: true,
  countdownSeconds: 3,
  countdownEveryWave: false,
  autoWaveEnabled: true,
  autoWaveDefault: false,
  autoWaveDelayMs: 5000,
  motionEnabled: true,
  adventureMedals: true,
  levelObjectives: true,
  levelUnlockMode: 'sequential',
  resultAnimationMs: 1800,
  renderer: 'phaser',
  rendererRecovery: true,
  rendererRetryLimit: 2,
  rendererStartupTimeoutMs: 20000,
  renderQuality: 'balanced',
  renderFps: 60,
  bridgeHz: 10,
  particles: true,
  particleLimit: 120,
  cameraShake: true
}
// 同一文件导出,UI陷阱费用与创建UTS会话共用,不另复制价格常量。
export const GAME_RULES = { trapCost: 80, trapDamage: 100, trapRadius: 95, trapSlowMs: 2400 }

以下新增表现项在修改配置并重建、重新加载页面后生效,均不改变规则;非法值记录诊断并按对应默认回退。

参数 类型 必填 说明 默认值 可选参数
battleSaveEnabled boolean 否 启用本机自动检查点及主页恢复入口 true true / false
battleSaveIntervalMs number 否 检查点节流间隔,整数毫秒;重要操作另触发 2000 500..10000
battleSaveNamespace string 否 两槽键前缀,不包含用户身份;跨产品自行隔离 grove-battle ^[a-z][a-z0-9_-]{0,47}$
announcementEnabled boolean 否 公告入口开关;非远程活动、法规或领奖能力 true true / false
announcements GameNoticeInput[] 否 本地原创公告,数组完整替换,最多8项 undefined使用3条默认 []明确隐藏;非数组回默认
announcements[].id string 是 唯一标识;重复整项忽略 无 ^[a-zA-Z0-9][a-zA-Z0-9_-]{0,31}$
announcements[].label string 是 非空,校验前Unicode字符数≤6,输出trim 无 合法短标签
announcements[].title string 是 非空,校验前Unicode字符数≤24,输出trim 无 合法标题
announcements[].paragraphs string[] 是 1..12段,每段非空且≤600个Unicode字符,保留段内换行 无 合法正文
artwork GameArtworkOptions 否 assetBase内六项PNG部分覆盖,不注册行为 {}使用下表默认 未知字段忽略并诊断

公告无效项整项忽略;超过8项只取前8并诊断;非空输入全部无效时回默认3条,[]保持空。公告按实际安全区剩余纸面宽高分页,宽按15px字列、正文高按26px行预算,段落换行/空行保留,前后页固定操作;不截成省略号。标题与标签仍需随实际字体和设备复验。

// 在uni_modules/lizhao-forest-guard/static/game/presentation.ts中合入GAME_PRESENTATION;只覆盖开发者需要的项。
Object.assign(GAME_PRESENTATION, {
announcementEnabled: true,
announcements: [{ id: 'local-guide', label: '攻略', title: '营地布防手册', paragraphs: ['先点可建地,再点工具,下方费用来自当前规则。', '返回主页后可继续上次成功保存的防线。'] }],
battleSaveEnabled: true,
battleSaveIntervalMs: 2000,
battleSaveNamespace: 'my-grove',
artwork: { tutorialHand: 'tutorial-glove-v1.png', rescueCage: 'rescue-cage-v1.png', rescueSpirit: 'rescue-spirit-v1.png', countdownGuide: 'countdown-guide-v1.png', cannonBase: 'cannon-base-v1.png', cannonHead: 'cannon-head-v1.png' }
})
参数 类型 必填 说明 默认值 可选参数
artwork.tutorialHand string 否 手背朝上的立体手套指引 tutorial-glove-v1.png 安全PNG名
artwork.rescueCage string 否 木笼与受困芽灵 rescue-cage-v1.png 安全PNG名
artwork.rescueSpirit string 否 同一芽灵的获救态 rescue-spirit-v1.png 安全PNG名
artwork.countdownGuide string 否 开场场记板 countdown-guide-v1.png 安全PNG名
artwork.cannonBase string 否 固定炮底,仅cannon分层 cannon-base-v1.png 安全PNG名
artwork.cannonHead string 否 独立炮头,仅cannon分层 cannon-head-v1.png 安全PNG名

六项均为≤64字符、字母/数字开头、后续字母数字下划线连字符、小写.png后缀的basename;禁止路径/URL/查询串。非法字段逐项回默认并诊断,缺项用默认。资源加载失败按实际组件回退并诊断;炮底/炮头缺图回原完整炮台。默认无常驻“+”塔位;点可建地→工具浮层→下方真实费用→点工具即建,44dp命中不随视觉缩放。对应素材位于外置资源包的 art/,素材使用范围见随附许可。

炮头使用TowerState可选的完整四字段targetEnemyId/targetRescueId/aimX/aimY(实际出手时由引擎一起更新);活目标取同一ID角色在画面中的实际插值位置,目标死亡保留末次朝向,不由页面重新索敌。仅cannon采用固定底座与独立炮头,炮头沿自身轴线后坐,弹道从炮口发出,不旋转整座建筑。motionEnabled=false仍保留必要方向,暂停冻结;缺四字段兼容旧快照,任一分层图片缺失时回退原完整炮台。ShotState可选targetRescueId只指真实救援弹道,末击后仍保留,不按终点坐标猜测救援事件。

uni_modules/lizhao-forest-guard/example/uniappx/front-scene.uvue的FrontScene组件接收brandName、tagline、assetBase、landscapeBackground、allowEndless同名props,根页面读取资源路径和声音设置。initialSound用于没有已保存偏好时的初始设置,已有本地设置按宿主逻辑恢复;默认静音,用户操作后才播放。allowEndless控制菜单入口,不删除插件本身的无尽能力。未提供任意字体、颜色和素材键的运行时配置,不能把修改模板源码声称为这类API。

森境采用横屏全屏前场,暖光森林营地围绕中央关卡沙盘,主菜单/选关以真实游戏按钮和关卡交互组织,不使用App式面板。landscapeBackground与assetBase拼接,默认grove-landscape-v1.png用于启动、主页和选关,原月夜战场与竖屏素材保留;它不是新路线图,不改变UTS规则。修改素材须按实际尺寸、左右安全区和配置覆盖逐元素复验。

也可直接在宿主pages.json的pages数组注册以下插件页面,无需复制到宿主目录;首页通过uni.navigateTo({ url: '/uni_modules/lizhao-forest-guard/example/uniappx/index' })打开。若选择复制页面,将path与跳转地址改为自己的注册路径。以下样式只作用于森境页面,保留其他页面和全局方向设置,不把单游戏横屏要求变成整个应用的方向锁:

{
  "path": "uni_modules/lizhao-forest-guard/example/uniappx/index",
  "style": {
    "navigationStyle": "custom",
    "pageOrientation": "landscape",
    "hideStatusBar": true,
    "hideBottomNavigationIndicator": true,
    "disableScroll": true
  }
}

启动资源由真实image组件的load/error事件确认,同时最多3项加载,30秒超时,可手动重试;仅成功项进入进度。每批探测图先以空src挂载,在nextTick后仅启动本批捕获的key,避免缓存完成早于事件绑定;完成/失败处理核对started、加载代际和key,卸载或重试后旧回调不计数。即使实体机启动到达100%,也仅表示该阶段资源事件完成;启动小图探测不等于Phaser纹理或画布战场已就绪,战场仍等待独立ready事件。各阶段Web与实体机证据单独记录,不以先前竖屏/浏览器证据代替未验原生场景。

Web 端在真实源提交后才挂载 WebView,避免 H5 解析空源;APP本地WebView先以空字符串 src 挂载,mounted后的nextTick先取得WebView context并设置启动超时,再赋本地URL。启动阶段每400ms发送一次有界probe,受startupTimeoutMs约束;渲染器仅补发同一session已真实完成的ready,不模拟资源完成。消息继续校验实例/session,点选继续受session/epoch/enabled门禁;同轮重复ready幂等,不重发输入门禁以打断在途点选。就绪、失败或卸载停止probe与相关计时器,无常驻轮询,也不推进规则时间。此机制的专项检查与最终Native全流程分别验收。

battleAnnouncements与bossHealthBar是开发期表现开关,均默认true,创建/加载页面时应用;修改主源并重新构建、加载页面生效,不提供局中热更新接口,也不改变UTS规则。波次操作成功开始后才显示开波提示,每4波预警首领将至;首领真正进入game.enemies后才显示其真实hp/maxHp与slowMs对应寒霜状态,不把预警当作已进场。非最终波清空回到布阵时显示清场提示,最终胜负由结算界面承接。关闭播报不关闭正常操作/营地受击反馈;关闭首领血条只隐藏对应HUD,不改变敌人生命、伤害或减速。

firstPlayGuide启用可跳过的首次手势引导,完成标记是宿主本地grove-tutorial-v2。countdownSeconds只接受0..5有限整数秒,默认3;0表示不开倒计时,默认只在首波,countdownEveryWave为true才每波启用。后台、退出、菜单、重开或换会话会取消倒计时,旧回调不启动新局。motionEnabled现贯通前场/引导/弹框动效与绘制包options.motionEnabled,默认true且只接受boolean;active/前后台与该开关共同控制动画。关闭装饰动效仍保留必要HP、命中和弹道,不停止规则、不隐藏真实伤害。

连续迎敌与保存偏好

三项配置在uni_modules/lizhao-forest-guard/static/game/presentation.ts中修改,重建并重新加载页面后取得独立配置值,外部后续修改不污染当前控制器;不提供局中热更新。缺项用默认值,非法项各自回默认并记录诊断,其他合法项保留。例如只修改以下三项即可让首次未保存偏好的玩家默认开启、整备8秒;已有保存偏好优先:

// 合入uni_modules/lizhao-forest-guard/static/game/presentation.ts的GAME_PRESENTATION,随后重建页面。
Object.assign(GAME_PRESENTATION, {
  autoWaveEnabled: true,
  autoWaveDefault: true,
  autoWaveDelayMs: 8000
})

暂停菜单底部复用运行诊断/保存旁的小开关,三项各88×44dp目标、32dp顶面;下一波按钮原位显示“连战 5秒”等倒数,不增加常驻大面板。默认手动开波,第一波始终手动;标准模式最后一波和任何胜败终态不计时,无尽可继续后续波次。等待只在前台战场、画面就绪且ready时成立:菜单、引导、布防、塔待落位、选塔升级、陷阱整备或手动开场倒计时均清除等待,结束整备后重新等待完整时长。实际地图操作也重置等待。计时复用宿主50ms循环,与1×/2×规则倍速无关,ready规则时钟不变;自动整备到期直接发起下一波,不叠加开场倒计时,手动开波仍遵守countdownSeconds/countdownEveryWave。

后台、返回主页与恢复旧档均进入hold保护,回来不自行开波;玩家通过主页继续、暂停菜单“继续守卫”、暂停横幅“继续守卫”或手动下一波显式继续后才解除保护。暂停/查看敌情不重建当前局,关闭整备再继续从完整等待开始。同一ready周期至多发起一次,换局/退出清理;启动失败显示真实错误并hold,不在50ms循环内反复重试。

偏好使用battleSaveNamespace + '-auto-wave-v1'单独保存严格boolean,默认键为grove-battle-auto-wave-v1。只有确认键不存在才使用autoWaveDefault;存储读取异常或已有值非boolean一律安全关闭,即使autoWaveDefault=true,也不能当成缺键采用默认。切换时写入并读回核验,失败保留当前选择在本次页面生效,暂停副标题及诊断显示真实失败,可点“重试保存”重试,不伪报落盘。autoWaveEnabled=false既不读写/删除旧偏好,也不进行连战计时;不保存剩余时间,不修改双槽战局内容指纹或归档格式。配置校验回默认与存储异常安全关闭是两个独立策略。

waveIntel默认true,仅控制顶部波次牌侦察入口;false保留静态波次牌,快照敌情和规则照常。非法非boolean值记录诊断并默认true。倒计时期间入口层级位于计数遮罩之上且真实可点;打开取消倒计时、收起浮层并暂停,关闭回暂停菜单,由玩家继续,不自动开波/恢复,同一session的塔、金币与目标保留。每次展示一类怪物,最多四枚44dp头像章,长提示完整分页、头尾固定。旧快照缺字段明确显示情报不可用,不用页面公式猜测;核对匹配联编产物。

enemyIntelProfiles默认[],按sprout/runner/brute/boss部分覆盖name/tip/art,缺项用原默认值,不注册新怪物行为。name/art与旧怪物图鉴共用;tip仅作为侦察战术提示并完整分页,旧图鉴简介取同一默认模型表的原短简介,不受长tip覆盖。侦察及图鉴图片缺失时均提供同组占位回退和真实诊断,不新增启动阻塞。非数组、非普通对象、未知/重复kind或未知字段均有定位诊断;重复保留首项,非法字段单独回默认,其他有效字段保留。修改后重建、加载页面生效,不热改活动局。

在同一presentation.ts中可只覆盖一类,自备my-boss.png放入assetBase目录并记录许可:

GAME_PRESENTATION.waveIntel = true
GAME_PRESENTATION.enemyIntelProfiles = [
  // name/art也用于图鉴;tip只进入侦察战术提示,图鉴保留默认短简介。
  { kind: 'boss', name: '古木守望者', tip: '提前布置交叉火力,留意技能冷却。', art: 'my-boss.png' }
]

adventureMedals默认true,控制印记入口、结果新增印记演出与新的救援收藏记录;关闭不删除旧印记,正常最高星级/最佳分仍记录。levelObjectives默认true,只控制本关目标入口与前场预览,不改变UTS波次/伤害/救援规则;关闭目标不关闭印记,关闭印记也不删除目标规则。两字段仅接受boolean,非法值分别记录诊断并使用默认true,不抛规则API错误。修改开发期GAME_PRESENTATION后重建、加载页面生效。

印记分三类:clear由本章最高stars>0导出,tristar由stars=3导出(三星是剩余生命≥最大生命90%,不是无伤);rescue仅在standard胜利、救援目标总数>0且所有目标实际freed时记录。失败或无尽不发冒险印记;零救援目标隐藏对应目标与印记。旧星级只能证明前两枚,不能推断救援历史。新增grove-rescue-medal-{id}数值0/1,只有本章实际获得时进入脏键;成功读旧值后取max、失败暂存并重试,不写未知0或覆盖未参与他章。存储失败时本局收藏保留,保存重试复用真实待写集合,不重复发印记。

当局目标来自本局真实快照,与历史收藏分开:解救后未赢显示“已救援x/y,通关后记录”,解救后失败不记录,新局目标重置而收藏保留。前场、暂停和结果共用AdventureBook,每章一页最多三枚。前场关闭回原前场,暂停关闭回暂停;战斗直接查看先暂停,关闭也回暂停,不擅自恢复规则/倒计时。结果开册保留ResultScene实例并静态收束,关闭回结果不重演。暂停六工具使用短字幕、完整ARIA及44dp命中。

levelUnlockMode默认sequential,按真实通关星级依次开放章节;open开放目录关卡供自由试玩。历史上已完成后章的通路不会反锁。非法模式记录诊断并降级为sequential。resultAnimationMs接受0..4000有限毫秒,默认1800;非法值记录诊断并降级1800,不抛规则API错误。修改后重建并加载页面生效。motionEnabled=false或时长0立即展示完整结果,其他情况下按舞台入场、逐星、战绩/纪录/解锁逐段揭示,支持跳过;active/后台、换局和卸载取消旧计时,主动作无需等演出结束。

GameButton及角色、关卡、塔位、技能、救援和陷阱等普通操作入口覆盖hover/focus/press,反馈只移动内部高光/图形或顶面,外部44dp命中固定;disabled/冷却不显示成功反馈,动作不等待动画。接入时需核对目标设备的触控、键盘和焦点反馈。

本地成绩由宿主uni_modules/lizhao-forest-guard/static/game/progression.ts纯计算与页面存储维护,属于示例而非新增UTS API。胜利标准模式按剩余生命/最大生命≥90%得3星、≥50%得2星,否则1星;20最大生命对应原18/10阈值,自定义最大生命同样按比例。失败/无尽不获标准星,但仍可记录对应模式最佳。每会话至多结算一次,重玩只保留最高星级/最佳分,星章总计不重复累加;newBest、新章和全章完成均来自真实记录,全部目录关卡实际获星才算全章完成。最后一章回选关或重玩,不绕回首章。仅放陷阱或产生真实花费也能从主页续玩;续玩优先保留内存当前局;开启battleSaveEnabled时,主页还提供“继续上次防线”,从最近成功本机检查点恢复中途战斗,详见战局保存合同。

存储兼容数值键grove-stars-{id}与grove-best-{id}-{mode},没有迁移到不兼容的新格式;最高记录响应更新到主页/选关。写失败仍保留会话战绩,结果舞台提示暂存本局并提供“重试保存”,重试只幂等写回最高记录,不再次发星。不承诺多键存储事务或失败后跨重启保留未写记录;没有货币领取、账号或联网奖励。

紧凑弹框按四边safeArea与每类footer预算固定头/体/尾,文字不裁成半行,主动作与close不随正文滚走。暂停牌匾宽328dp、主CTA宽204dp;GameButton compact顶面32dp、round面28dp,外target保持44dp且不scale,按压只移动内面约2dp。HUD圆面28dp/图标16dp/倍速字12dp,资源数字与石台另按层级显示,石台约29dp而命中仍44。所有弹框统一游戏道具材质/标题/厚度/阴影,接入时需核对实际安全区和文字尺寸。

小圆close放在弹框根层角标right:-16dp/top:-8dp,不挂会clip的标题父容器,仍须保证完整44dp命中在安全区内。升级/回收简化文字并成组,ARIA保留完整费用;长标题/数字单位可按显示策略换行或单位化,但不改真实值。图鉴8条、帮助8条(含波次侦察)采用完整分页,诊断独立textarea与固定复制操作,不能漏条或滚走主动作。

替换字体或文案后,应检查标题、编号、费用、正文和固定操作区的完整显示,并保留诊断正文滚动及固定复制入口。

GAME_RULES是页面创建会话时传给createGameSync({ rules: GAME_RULES })的真实规则配置,陷阱按钮读取同一对象的trapCost。修改规则后重建会话生效,不热改活动局;费用、范围和校验见下方规则表。

Phaser 承载组件位于 uni_modules/lizhao-forest-guard/components/lizhao-forest-guard/lizhao-forest-guard.uvue,通过 easycom 同名标签解析。渲染入口为 uni_modules/lizhao-forest-guard/static/renderer/index.html;图像和音频从准备后的外置资源根加载。

主页操作与同组浮雕图标

横屏主页开始/继续按钮同一行各156×44dp、间隔12dp,存档提示单独下一行;无续局时开始按钮居中,竖屏保留适合狭窄宽度的纵列。角色与按钮共用安全区预算,静态14dp净距另留6dp动效余量。左右入口96×44dp、32dp顶面,顶角44dp命中/28dp圆面;按钮缩小外观仍保留命中。续局画面显示“继续防线”,Web可访问名称保留完整来源说明,实际仍进入原当前局或最近成功检查点。

GameIcon现用同一24单位连续圆润轮廓、左上高光和下沿厚度的原创玩具浮雕组,覆盖25类功能名称。默认与实际预设色使用72×72透明PNG,在16/18/24逻辑像素等比显示;书脊、地图折线、音效开关、已获/未获星级有独立形状。紧凑HUD按16px层级显示,图标本身不接收输入。图标位于外置包的 ui-icons-v2/,实际文件由资源客户端解析;图标解析和缺图几何回退代码保留在插件内。

以下是已随完整示例复制的页面表现组件用法,不新增UTS业务API。name为下表名称,未知名称回退help;size为调用者提供的正逻辑像素数(默认24,建议16/18/24),颜色默认#c7ecea。精确预设色才用PNG,其他当前平台支持的合法CSS颜色保留原值并使用同轮廓代码浮雕,不近似选色;组件不负责验证任意非法CSS输入。缺图保留轮廓并按路径去重,最多16条告警;恢复正确资源并重新挂载可重试。

<script setup>
import GameIcon from '@/uni_modules/lizhao-forest-guard/example/uniappx/game-icon.uvue'
import GameButton from '@/uni_modules/lizhao-forest-guard/example/uniappx/game-button.uvue'
</script>
<template>
  <GameIcon name="book" :size="18" color="#fff3c6" />
  <GameButton label="查看图鉴" icon="book" variant="mint" compact :style="{ width: '96px', height: '44px' }" :fontSize="12" :iconSize="16" />
</template>
参数 类型 必填 说明 默认值 可选参数
name string 是 GameIcon功能轮廓,未知名称显示help 无 play / pause / close / back / next / sound / muted / announcement / help / book / infinity / star / empty-star / coin / health / plus / upgrade / home / restart / map / display / target / snow / spark / alert
size number 否 GameIcon逻辑像素;调用者提供正数,不改变按钮命中区 24 推荐16 / 18 / 24
color string 否 GameIcon合法CSS颜色,精确预设色用PNG,其他合法色原值回退 #c7ecea 例如#fff3c6 / #714218 / 自定义合法颜色

GameButton默认gold/wood采用可可色#714218,mint/danger/ghost采用奶油色#fff3c6,显式color优先。分开顶面外观与至少44px触控,按压仅面动,禁用真实阻止动作;Web提供名称与Enter/Space操作,原生不传不支持的aria属性。APP图标每代空src挂载,mounted后的nextTick再提交真实源,正常load后移除回退图元;source+generation隔离换图、A→B→A和卸载后的旧事件,Web保持直接src。上述仅改变表现,不改变规则、存档格式或Core;插画等比显示并补偿透明留白,更改尺寸/文案后仍按文字完整性与命中标准复验。

assetBase 须以 / 结尾,保留现有素材逻辑路径,实际文件由资源客户端解析到准备后的 art/ 根目录。替换插画后需同时核对 uni_modules/lizhao-forest-guard/static/scene-projection.js 的道路锚点、触控及射程。

Phaser组件与绘制包接入

下面是可放入uni-app x页面的最小静态布阵画面,使用390×844竖屏兼容尺寸说明帧接口;横屏主场景以完整页面实现为准。创建ready规则会话并发布首包,不自动推进波次。完整游戏的唯一50ms规则时钟在uni_modules/lizhao-forest-guard/example/uniappx/index.uvue维护,页面与模块分担表现与流程,Phaser不重复计算规则。

<template>
  <view style="width:390px;height:844px;position:relative">
    <lizhao-forest-guard v-if="resourcesReady" :resources="resourcePacket" :frame="renderFrame" :active="true" :foreground="true" :hostEpoch="0" :startupTimeoutMs="20000"
      :inputEnabled="false" :inputEpoch="0" :tapRequest="''"
      @ready="renderState = '就绪:' + $event"
      @loading="renderState = '加载:' + $event"
      @failure="renderState = '失败:' + $event"
      @diagnostics="renderStats = $event"
      @startup="startupReport = $event"
      @enemyTap="enemyTapResult = $event" />
    <text>{{ renderState }}</text><text>{{ renderStats }}</text><text>{{ startupReport }}</text>
  </view>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { createGameSync, disposeGameSync } from '@/uni_modules/lizhao-forest-guard'
import { createResourceSession, getResourceMap } from '@/uni_modules/lizhao-forest-guard/static/resources/client'
import { createRenderPublisher, normalizeRenderOptions } from '@/uni_modules/lizhao-forest-guard/static/renderer/frame.js'
const resources = createResourceSession()
const resourcesReady = ref(false)
const resourcePacket = ref('')
let alive = true
const renderFrame = ref('')
const renderState = ref('等待绘制')
const renderStats = ref('')
const startupReport = ref('')
const enemyTapResult = ref('')
const game = createGameSync({ levelId: 'woodland', mode: 'standard', seed: 42 })
const bridgeHz = 10
const options = normalizeRenderOptions({ quality: 'balanced', fps: 60, particles: true, particleLimit: 120, cameraShake: true, motionEnabled: true, interpolationMs: 1000 / bridgeHz })
const publisher = createRenderPublisher(frame => { renderFrame.value = JSON.stringify(frame) }, { hz: bridgeHz })
onMounted(async () => {
  try {
    const result = await resources.prepare(progress => { if (alive) renderState.value = progress.message })
    if (!alive) return
    resourcePacket.value = JSON.stringify({ format: 1, version: result.version, files: getResourceMap('art/') })
    publisher.push(game, { portrait: true, width: 390, height: 844, board: { x: 0, y: 100, width: 390, height: 629 }, assetBase: '/uni_modules/lizhao-forest-guard/static/art/', selectedSlot: 0, options }, Date.now(), true)
    resourcesReady.value = true
  } catch (error) { if (alive) renderState.value = '素材准备失败:' + String(error) }
})
onBeforeUnmount(() => { alive = false; publisher.reset(); disposeGameSync(game.sessionId); resources.release() })
</script>

组件只是绘图层,触控、HUD和错误后基础显示仍由宿主实现。上段仅显示事件内容,不提供完整恢复流程。完整游戏以当前epoch/session/instance匹配的startup报告管理状态,失败时暂停当前局、取消开波等待并尝试保存检查点,再提供“重试增强”“兼容继续”与返回暂停。重试只重建Renderer,准备好后仍暂停,由玩家明确继续。renderer: 'native'主动选择基础显示,玩家修复入口不会覆盖开发者选择;静态库仍会打包,不能把开关称为减包方案。

发布器默认以10Hz发送小快照,50ms规则快照先收集短寿命弹道并按ID去重;动作、暂停、状态或尺寸变化可强制即时同步。绘制包不包含完整目录、日志、规则或存档,位置按0.1逻辑单位量化。页面隐藏/菜单暂停时关闭绘制活动;active=false仍允许前台加载,后台由foreground=false挂起准备预算与探测。恢复前台可补静态帧,不推进规则;失败与手动修复后不自动继续。返回主页、卸载或更换会话销毁旧Phaser实例、纹理、监听和计时器。不得把目标渲染帧率当成实际设备FPS。

同局画面修复与诊断

rendererRecovery为boolean,默认true;rendererRetryLimit为0..3整数,默认2次,指首次尝试以外的手动重试数;rendererStartupTimeoutMs为3000..60000整数毫秒,默认20000。省略用默认,非法项逐项记录诊断并独立回默认;重建并加载页面取得配置副本,不热改当前尝试。默认不自动重试,0次仍保留兼容继续。rendererRecovery=false沿用失败后兼容回退流程并保留真实诊断,不显示修复模块。

暂停牌左上“画面修复”为44dp命中、28dp圆面、16dp图标,打开局部精灵画板,不常驻战场。失败时取消连战和开场倒计时,暂停原Core会话并尝试检查点;保存失败仍按原保存合同提示,不能冒称落盘。重试只更换组件key=sessionId:hostEpoch,不重建Core、恢复归档或重复奖励,金币、波次、塔策略、救援与目标保留。ready后仍暂停,“增强继续”或“兼容继续”均由玩家明确选择;关闭回暂停。每次进入战场重新给手动次数预算,达到上限后不再创建实例。兼容选择仅本次页面,不持久化为永久偏好,之后仍可从暂停入口尝试增强;开发者renderer=native时不主动挂增强组件。

同一未完成准备周期只消耗前台预算;重复loading/bridge-ready/probe不重新获得20秒。ready后真实新资源loading才新建周期。foreground=false暂停预算与启动探测,foreground=true补当前frame/active/probe并继续剩余预算,不解除规则暂停。active仅控制绘制活动,与前后台分开。

完整接入复用uni_modules/lizhao-forest-guard/static/game/renderer-recovery.ts与uni_modules/lizhao-forest-guard/example/uniappx/index.uvue:startup校验后复制,仅接受当前hostEpoch/sessionId/instance,旧实例或旧session不能污染新尝试。失败报告冻结,最近最多四份在诊断中保留,不被后续成功或dispose抹掉。失败先走专用幂等dispose,不能因failed门禁跳过释放通知;这修正的是已确认的通知缺口,不代表已证实原生泄漏或定位原偶发冷启超时。

真实救援与一次性道路陷阱

内置每关提供两个道路陷阱站点和一个救援目标。两个新动作仍走dispatchGameActionSync,slotId在各自独立ID空间取值,towerId传空串、value传0。以下uni-app x脚本可以验证扣费、转火和返回值,最后释放会话:

import { createGameSync, dispatchGameActionSync, advanceGameSync, getGameSnapshotSync, disposeGameSync } from '@/uni_modules/lizhao-forest-guard'
const game = createGameSync({ levelId: 'woodland', mode: 'standard', seed: 42, rules: { trapCost: 80, trapDamage: 100, trapRadius: 95, trapSlowMs: 2400 } })
const id = game.sessionId
try {
  const built = dispatchGameActionSync(id, { type: 'build', slotId: 2, towerId: 'arrow', value: 0 })
  if (!built.ok) console.log(built.errSubject, built.errCode, built.errMsg)
  const placed = dispatchGameActionSync(id, { type: 'placeTrap', slotId: 1, towerId: '', value: 0 })
  if (!placed.ok) console.log(placed.errCode, placed.errMsg)
  const targeted = dispatchGameActionSync(id, { type: 'targetRescue', slotId: 1, towerId: '', value: 0 })
  if (!targeted.ok) console.log(targeted.errCode, targeted.errMsg)
  const started = dispatchGameActionSync(id, { type: 'startWave', slotId: 0, towerId: '', value: 0 })
  if (!started.ok) console.log(started.errCode, started.errMsg)
  let current = getGameSnapshotSync(id)
  for (let tick = 0; tick < 300 && current.state === 'running' && !current.rescues[0].freed; tick++) {
    current = advanceGameSync(id, 50)
  }
  console.log(current.gold, current.traps, current.rescues, current.rescueTargetId)
  const defend = dispatchGameActionSync(id, { type: 'targetRescue', slotId: 0, towerId: '', value: 0 })
  if (!defend.ok) console.log(defend.errCode, defend.errMsg)
} finally { disposeGameSync(id) }

放置每枚陷阱即时扣费,已有武装陷阱的站点拒绝重复放置;敌人进入半径后,对范围内敌人扣血并附加减速,触发一次后移除,可再次付费布置。救援动作本身不收费,须有至少一塔在目标射程内;选中后射程内塔优先攻击牢笼,其余塔继续防守。只有running时推进攻击,击破后freed=true,奖励金币一次并增加奖励金币×10的分数,目标自动清为0;传0可取消转火。暂停时这两个动作都返回9101003,非法/占用站点、已解救目标或无射程塔返回9101005,金币不足返回9101004。救援和陷阱是可选支线,不是通关前置,不阻止按正常波次胜利。

每塔索敌与入口开关

GameRules.defaultTargetPriority?: string在创建时校验并复制;省略或null取front,其他值仅接受front/strong/near,不能热改活动会话。TowerState.priority?: string保留旧快照兼容,当前 Core 的每座已建塔实际必返合法策略;旧快照缺字段时完整页面隐藏策略选择器,不猜测已生效。

towerPriority复用已有动作,slotId为已建塔的塔位ID,towerId:''、value:0,priority虽然是可选类型字段,此动作必须传合法枚举。ready/running/paused均可免费、幂等切换;不推进时钟、冷却、随机,不改金币、生命、得分、集火/救援目标或暂停状态。升级保留;出售重建按会话默认。无塔9101005、缺失/null/坏策略9101001、终态9101003、无效会话9101002,均以真实GameResult处理。

三策略只比较本塔射程内存活敌人:front取路线progress最大;strong取maxHp最大(不是当前剩余HP);near取塔到怪当前逻辑坐标距离平方最小(平方逻辑距离单位,不是屏幕像素)。主比较平局先progress大、再敌人ID小。有效手动集火或救援仍优先,目标在本塔射程外时按该塔策略攻击其他敌人;二者原互斥关系不变。策略在下一次真实选敌时生效,不立即开炮或重置攻击间隔;Renderer只消费引擎真实目标和出手朝向,不能另行索敌。

// 完整游戏主源 uni_modules/lizhao-forest-guard/static/game/presentation.ts 的 GAME_PRESENTATION 内:
  towerStrategies: true,

默认true;false或非法非boolean值隐藏已建塔紧凑浮层入口,非法值记录诊断,不删除已保存策略、不禁用公开动作或改变规则。修改后重新构建加载页面生效。该入口在升级/回收之后展示前线、强敌、近身三枚64×44dp按钮,当前色以Core成功回执和真实快照为准;失活、后台、终态、倒计时或覆盖菜单不可操作。切换取消当前连战整备等待,关闭浮层后重新等待完整时长,不自动恢复暂停。普通uni-app接入页独立提供规则按钮及每塔真实策略列表,不继承完整Host入口与存储流程。

点怪集火与取消

targetEnemy复用dispatchGameActionSync,slotId取当前快照的存活敌人ID,towerId为空串、value为0。正ID只在running允许,可提前锁定尚未进入射程的活怪;每座塔独立检查射程,目标在本塔射程外时继续本塔配置的索敌策略,不能跨范围伤害或闲置等待。重复设置同ID是幂等动作,模板负责“再点同一只取消”的交互。不存在、已离场或无效状态的选择失败,原目标保持。

以下uni-app x脚本仅演示真实规则调用,不启动页面计时器;从默认目录建造、开波并读取实际出生ID,处理错误后释放会话:

import { createGameSync, dispatchGameActionSync, advanceGameSync, getGameSnapshotSync, disposeGameSync } from '@/uni_modules/lizhao-forest-guard'
const game = createGameSync({ levelId: 'woodland', mode: 'standard', seed: 42 })
const id = game.sessionId
try {
  const built = dispatchGameActionSync(id, { type: 'build', slotId: 2, towerId: 'arrow', value: 0 })
  if (!built.ok) throw new Error(built.errMsg)
  const started = dispatchGameActionSync(id, { type: 'startWave', slotId: 0, towerId: '', value: 0 })
  if (!started.ok) throw new Error(started.errMsg)
  const current = advanceGameSync(id, 50)
  if (current.enemies.length > 0) {
    const selected = dispatchGameActionSync(id, { type: 'targetEnemy', slotId: current.enemies[0].id, towerId: '', value: 0 })
    if (!selected.ok) throw new Error(selected.errMsg)
    console.log('实际目标', getGameSnapshotSync(id).enemyTargetId ?? 0)
    const paused = dispatchGameActionSync(id, { type: 'pause', slotId: 0, towerId: '', value: 0 })
    if (!paused.ok) throw new Error(paused.errMsg)
    const cleared = dispatchGameActionSync(id, { type: 'targetEnemy', slotId: 0, towerId: '', value: 0 })
    if (!cleared.ok) throw new Error(cleared.errMsg)
    console.log('取消后仍暂停', getGameSnapshotSync(id).state)
  }
} finally {
  disposeGameSync(id)
}

slotId:0在ready/running/paused清除怪物优先,不恢复规则时钟,也不清独立的救援目标;won/lost拒绝。正怪物目标成功后才清救援,正救援成功后才清怪物目标;失败选择均不改变另一目标,targetRescue(0)只清救援并保留其原暂停拒绝合同。暂停保留有效目标,死亡、漏怪、换波、新会话和终态清除怪物目标,随后恢复自动索敌。旧快照缺少enemyTargetId时按0消费,不能伪造已锁定状态。

在共享配置 uni_modules/lizhao-forest-guard/static/game/presentation.ts 中设置,宿主与分发示例读取同一文件:

GAME_PRESENTATION.enemyTargeting = true
// 关闭仅停用场景轻点及战场键盘选择,不禁止调用targetEnemy规则动作。
GAME_PRESENTATION.enemyTargeting = false

默认true,非boolean记录诊断并回默认true;修改后重建并加载页面生效。API指定的真实目标仍显示必要标记、名称/HP和取消入口。名称/头像复用enemyIntelProfiles的既有四类配置,不注册新行为,不增加图片、依赖或SDK。模板组件位于 uni_modules/lizhao-forest-guard/example/uniappx/enemy-target.uvue;计算模块唯一位置为 uni_modules/lizhao-forest-guard/static/game/enemy-target-model.ts,通过 alias 共享,不是新增公开 UTS API。

场景轻点先经过塔位、救援、陷阱、技能和弹框的点击优先级;拖动、长按与跨门禁手势不发送。Phaser按实际显示的插值sprite包围盒,以至少44dp范围做确定近邻选择;只在渲染器本地保留最多16帧/250ms历史,按轻点时间选已显示帧,缺少有效历史时拒绝,不拿最新逻辑坐标猜测。密度/摄影机转换后使用宿主视口CSS逻辑像素;基础显示按自身实际位置使用同一命中算法。只有轻点时传一次请求与结果,不逐帧跨桥回传位置。

经济、技能与控制组合

下面的 uni-app x 脚本完整展示三张地图、两种模式、四类塔、两种技能、经济操作、速度与生命周期。不同场景分别创建会话,再立即释放不用的会话;不要在每帧创建。关卡不设账号或线上解锁条件。技能仅在正在运行的波次使用。

import { getGameCatalogSync, createGameSync, dispatchGameActionSync, advanceGameSync, getGameSnapshotSync, getGameDiagnosticsSync, disposeGameSync } from '@/uni_modules/lizhao-forest-guard'

const catalog = getGameCatalogSync()
for (const level of catalog.levels) {
  for (const mode of ['standard', 'endless']) {
    const preview = createGameSync({ levelId: level.id, mode: mode, seed: 42 })
    disposeGameSync(preview.sessionId)
  }
}
const game = createGameSync({ levelId: 'creek', mode: 'endless', seed: 42 })
const id = game.sessionId
function action(type: string, slotId: number, towerId: string, value: number) {
  const result = dispatchGameActionSync(id, { type: type, slotId: slotId, towerId: towerId, value: value })
  if (!result.ok) console.log(result.errSubject, result.errCode, result.errMsg)
}
action('build', 1, 'arrow', 0)
action('build', 2, 'cannon', 0)
action('build', 3, 'frost', 0)
action('build', 4, 'arcane', 0)
// 金币不足会返回真实失败;每次操作后读取实际状态。
action('upgrade', 1, '', 0)
action('sell', 1, '', 0)
action('startWave', 0, '', 0)
action('speed', 0, '', 2)
advanceGameSync(id, 50)
action('skill', 0, 'meteor', 0)
action('skill', 0, 'blizzard', 0)
action('pause', 0, '', 0)
console.log(getGameDiagnosticsSync(id))
action('resume', 0, '', 0)
action('speed', 0, '', 1)
console.log(getGameSnapshotSync(id))
console.log(disposeGameSync(id))

扩展地图优先使用上述公开catalog入口,配置路线、塔位、起始金币与波数;将自己的横竖场景放入实际资源目录,并在宿主显示层校准两种方向道路锚点。现有示例的投影辅助文件为uni_modules/lizhao-forest-guard/static/scene-projection.js,新关卡不会自动获得对应美术。四个塔IDarrow/cannon/frost/arcane固定,可修改属性与说明,不能注入攻击脚本;新增敌人类型、塔行为或技能机制才需要维护内部实现、公开合同及对应测试。页面仍只从插件根导入UTS规则API。

可配置范围不包含敌人种类、每波敌人组成/生成规律、技能伤害/持续时间;它们仍由固定行为实现。不要把可改关卡波数、敌血倍率或技能冷却宣传为任意波次/技能编辑器。完整界面的四塔价格与图鉴读取目录,但默认规则/波次预览按模板默认设计;修改内容后需同步自己的预览与说明,不能假定模板是通用内容或皮肤引擎。

外置素材部署与缓存

完整游戏页面已接入资源准备流程:导入完整插件、部署素材并填写资源地址后,复制对应 example/uniappx/index.uvue 到已注册页面即可使用。下面的辅助方法也可用于自己的 Vue 3 页面,它们位于 uni_modules/lizhao-forest-guard/static/resources/client.ts,属于前端资源模块,不增加 UTS 规则 API,也不替代游戏规则、存档或 Phaser 生命周期。

部署与目录

将 deliverables/game-assets/lizhao-forest-guard/ 内的内容按原层级上传到自己的公开 HTTPS 根目录,并将该目录设为 RESOURCE_CONFIG.baseUrl。该资源目录只承载 PNG、WAV 和资源索引 JSON,不承载 JavaScript、UTS、HTML 或其他可执行代码。上传内容保持以下布局:

latest.json
releases/<资源版本>/manifest.json
files/<sha256>.png
files/<sha256>.wav

art/ 与 ui-icons-v2/ 是清单中的逻辑路径,文件名需要保持稳定;云端 files/ 使用内容摘要命名,不能只上传原图目录或把逻辑文件名当作内容地址。先上传新素材及对应版本清单,再更新 latest.json。预置根地址为 https://env-00jxu7ha8amh.normal.cloudstatic.cn/lizhao-forest-guard/;该配置不表示资源已经上传或该公网地址已可用,使用前需完成实际部署。

Web 使用 CacheStorage 保存文件,页面应运行在 HTTPS 安全上下文,云存储需允许实际页面来源的跨域 GET 请求。App 使用 uni.env.USER_DATA_PATH 下的持久目录,不把下载临时路径当作最终素材。清理 App 数据、浏览器站点缓存或被系统回收缓存后,需要重新下载;首次没有完整缓存时无法离线进入。资源请求不上传游戏成绩或本地存档。

App 清单通过有大小与取消门禁的临时文件读取原始 UTF-8,随后执行既有摘要和结构校验;不会将已解析对象重新序列化作为原文。持久资源的 unifile 标识经宿主官方接口转换为实际文件地址后供图片和本地 WebView 使用,转换失败明确报错。需要包含相关内置模块的匹配基座。

公开配置

在 uni_modules/lizhao-forest-guard/static/resources/config.ts 中维护:

export const RESOURCE_CONFIG = {
  baseUrl: 'https://env-00jxu7ha8amh.normal.cloudstatic.cn/lizhao-forest-guard/',
  updatePolicy: 'check' as 'check' | 'pinned',
  pinnedVersion: '',
  timeoutMs: 20000,
  concurrency: 4,
  allowOfflineFallback: true
}
参数 类型 必填 说明 默认值 可选参数
baseUrl string 是 公开 HTTPS 目录,最长 512 字符;不能包含凭据、查询参数或父路径,尾部规范为 / 上方对应插件根地址 自有 HTTPS 资源根
updatePolicy 'check' | 'pinned' 是 冷启动的版本选择策略 check check / pinned
pinnedVersion string 固定模式必填 必须取实际已部署的资源版本,格式为 assets- 后接 12 位小写十六进制摘要;属于资源版本 空字符串 版本清单中的有效值
timeoutMs number 是 每项资源请求超时,整数,单位毫秒 20000 3000..60000
concurrency number 是 同时校验或准备文件的并发上限,整数 4 1..4
allowOfflineFallback boolean 是 更新失败后是否使用已完整校验的旧缓存;固定模式仅允许同一固定版本 true true / false

配置在 createResourceSession() 时复制,需在创建资源会话、启动游戏之前设置。所有活跃资源会话释放后的首次准备属于冷启动;同一活动期共享已就绪字典,不在正在进行的战斗中热换素材。

check 每次冷启动先校验本地包,再请求较小的 latest.json;版本、清单摘要及字节一致时复用缓存,不下载图片和声音。有新清单时只下载内容摘要发生变化或本地校验失败的文件,相同内容复用缓存。pinned 使用指定版本;完整有效的同版本缓存命中时不发网络请求,不请求 latest.json,缺失时请求指定版本清单。固定模式不回退到其他版本。

需要固定部署版本时,在创建会话前传入真实资源版本:

import { RESOURCE_CONFIG } from '@/uni_modules/lizhao-forest-guard/static/resources/config'

function selectPinnedResources(version: string) {
  if (!/^assets-[a-f0-9]{12}$/.test(version)) throw new Error('请传入已部署清单中的资源版本')
  RESOURCE_CONFIG.updatePolicy = 'pinned'
  RESOURCE_CONFIG.pinnedVersion = version
}
自己的页面如何准备资源

以下为 Vue 3 / TypeScript 页面示例。加载期间只显示文字,准备成功后才挂载图片;离页时释放会话。prepare() 成功后仍需保留资源会话,不能立即 release(),否则最后一个所有者释放时 Web Blob 地址会回收。

<template>
  <view>
    <text>{{ progress.message }}</text>
    <text v-if="progress.total > 0">已处理 {{ progress.completed }}/{{ progress.total }} 项,校验 {{ progress.verifiedBytes }}/{{ progress.totalBytes }} 字节</text>
    <text v-if="errorText !== ''">{{ errorText }}</text>
    <text v-if="warning !== ''">{{ warning }}</text>
    <button v-if="errorText !== ''" :disabled="working" style="min-height:44px" @click="prepare">重新准备素材</button>
    <image v-if="ready && imageSource !== ''" :src="imageSource" style="width:160px;height:160px" mode="aspectFit" />
  </view>
</template>
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { createResourceSession, getAssetSource, getResourceMap, getResourceDiagnostics } from '@/uni_modules/lizhao-forest-guard/static/resources/client'
import type { ResourceProgress } from '@/uni_modules/lizhao-forest-guard/static/resources/client'
import { ResourceError } from '@/uni_modules/lizhao-forest-guard/static/resources/core'

const resources = createResourceSession()
const progress = ref<ResourceProgress>({ phase: 'idle', completed: 0, total: 0, verifiedBytes: 0, totalBytes: 0, downloadedBytes: 0, message: '等待准备素材' })
const ready = ref(false)
const working = ref(false)
const imageSource = ref('')
const errorText = ref('')
const warning = ref('')
let alive = true

async function prepare() {
  if (!alive || working.value) return
  working.value = true
  errorText.value = ''
  try {
    const result = await resources.prepare(value => { if (alive) progress.value = value })
    if (!alive) return
    imageSource.value = getAssetSource('art/arrow-moon.png')
    warning.value = result.warning
    ready.value = true
    const artFiles = getResourceMap('art/')
    console.log('可用素材条目', Object.keys(artFiles).length)
    console.log('资源诊断', getResourceDiagnostics())
  } catch (error) {
    if (alive) errorText.value = error instanceof ResourceError
      ? error.errSubject + ' / ' + error.errCode + ' / ' + error.code + ':' + error.errMsg
      : String(error)
  } finally {
    if (alive) working.value = false
  }
}
onMounted(async () => { await prepare() })
onBeforeUnmount(() => { alive = false; resources.release() })
</script>

createResourceSession(options?: { assetBase?: string }) 返回 prepare(onProgress): Promise<ResourceReady>、cancel() 和 release()。自定义 assetBase 仅注册旧素材逻辑根的别名,仍需将自定义文件放进资源包清单;它不会单独下载该目录。cancel() 取消当前所有者的等待与迟到回调,可在返回前台后重新 prepare();release() 为幂等终止,该会话不可再准备。当仍有其他所有者等待时,共享任务继续。

getAssetSource(input: string): string 解析 art/文件名、ui-icons-v2/文件名 或 /uni_modules/lizhao-forest-guard/static/... 兼容逻辑路径,返回本地 file 地址或 Web Blob URL;未准备、缺项时返回空字符串并记入有界诊断,不回退到外网原图。已有图形片段也需先准备资源,最终图片 src、图片解码及音频地址均使用解析后的值。

getResourceMap(prefix: string): Record<string, string> 返回当前字典的独立子映射;例如 getResourceMap('art/') 的键为文件名,值为解析后的地址。getResourceDiagnostics() 返回当前真实版本、来源、阶段、文件/字节进度、warning、错误和缺失逻辑路径。它不返回规则快照,也不修改游戏状态。

ResourceReady 为 { version, source, warning, files },source 取 cache / download / offline,files 是逻辑路径到本地地址的映射。download 表示采用新资源清单,不代表所有文件都重新下载;本次成功下载并校验的素材内容字节以 downloadedBytes 为准,不包含索引请求、HTTP 头或失败重试的流量。ResourceProgress 含 phase / completed / total / verifiedBytes / totalBytes / downloadedBytes / message;阶段为本地校验、版本检查、文件准备及就绪,字节按实际完成文件累计,不是网络速度或虚拟加载进度。

校验与失败语义

清单须为格式 1、对应插件 ID、1..512 个不重复且按逻辑路径排序的文件;清单正文最多 1 MiB,latest.json 最多 8 KiB。逻辑路径仅允许 art/、ui/ 或 ui-icons-v2/ 加单层安全文件名:字母或数字开头,名称主体最多 96 字符,仅含 ASCII 字母、数字、点、下划线与连字符,扩展名为小写 .png / .wav,禁止连续双点、父目录、URL 或查询串。对应文件必须覆盖插件资源合同中的所有必需路径。

每项字节为正整数,单文件不超过 16 MiB,总量不超过 128 MiB;PNG 的 MIME 必须为 image/png,WAV 为 audio/wav。SHA-256 为 64 位小写十六进制,内容地址必须与摘要及扩展名一致;资源版本必须与排序文件清单的内容摘要一致。下载及持久保存后核对真实字节和摘要,完整包校验成功才切换活动版本。校验成功仍不等于目标平台已完成图片或声音解码,完整游戏另保留真实解码加载流程。

坏清单、缺文件、超限、下载、持久化或校验失败均报告真实错误。allowOfflineFallback=true 且存在完整已验证缓存时,可返回 source: 'offline' 与非空 warning;没有完整缓存时拒绝启动,不拼接不完整新旧包,也不伪报更新成功。该配置不改变活动战斗的规则、随机状态、战绩或存档。

完整示例

下面是可放入 uni-app x .uvue 页面的完整 API 调用流程;模板按钮分别触发 build、wave、toggle、copyLog,此精简代码用于说明接口,不演示产品的启动页、主页和独立选关流程。全屏游戏流程、HUD、失败回退与其他操作见表内 uni-app x 页面。uni-app使用其选项式接入验证示例,不直接复制组合式脚本,也不将验证界面等同于完整游戏UI。

<template>
  <view>
    <text>{{ status }}</text>
    <button @click="build">建造弓塔</button>
    <button @click="prioritize">本塔优先强敌</button>
    <button @click="wave">开始下一波</button>
    <button @click="toggle">暂停 / 继续</button>
    <button @click="copyLog">复制本局诊断</button>
    <textarea v-if="report.length > 0" :value="report" :maxlength="-1" />
  </view>
</template>
<script setup lang="ts">
import { createGameSync, dispatchGameActionSync, advanceGameSync, getGameSnapshotSync, getGameDiagnosticsSync, disposeGameSync } from '@/uni_modules/lizhao-forest-guard'
import type { GameRules, GameAction } from '@/uni_modules/lizhao-forest-guard'
const rules: GameRules = { defaultTargetPriority: 'front' }
const status = ref('等待初始化')
const report = ref('')
let id = 0
let timer: ReturnType<typeof setInterval> | null = null
function stop() {
  if (timer != null) { clearInterval(timer); timer = null }
}
function send(type: string, towerId: string) {
  try {
    const result = dispatchGameActionSync(id, { type: type, slotId: 1, towerId: towerId, value: 0 })
    status.value = result.ok ? getGameSnapshotSync(id).state : result.errMsg
  } catch (error) { status.value = String(error) }
}
function build() { send('build', 'arrow') }
function prioritize() {
  try {
    const action: GameAction = { type: 'towerPriority', slotId: 1, towerId: '', value: 0, priority: 'strong' }
    const result = dispatchGameActionSync(id, action)
    const tower = getGameSnapshotSync(id).towers.find((item) => item.slotId == 1)
    status.value = result.ok ? '实际策略:' + (tower?.priority ?? '旧快照不可用') : result.errMsg
  } catch (error) { status.value = String(error) }
}
function wave() { send('startWave', '') }
function toggle() { send(getGameSnapshotSync(id).state == 'paused' ? 'resume' : 'pause', '') }
function copyLog() {
  try {
    report.value = JSON.stringify(getGameDiagnosticsSync(id))
    uni.setClipboardData({ data: report.value, fail: (error) => { status.value = error.errMsg } })
  } catch (error) { status.value = String(error) }
}
function run() {
  if (id == 0 || timer != null) return
  timer = setInterval(() => {
    try {
      const current = advanceGameSync(id, 50)
      status.value = '波次 ' + current.wave + ' · ' + current.state
    } catch (error) { stop(); status.value = String(error) }
  }, 50)
}
onLoad(() => {
  try { id = createGameSync({ levelId: 'woodland', mode: 'standard', seed: 42, rules: rules }).sessionId; run() }
  catch (error) { status.value = String(error) }
})
onShow(() => { run() })
onHide(() => { stop(); if (id > 0 && getGameSnapshotSync(id).state == 'running') send('pause', '') })
onUnload(() => { stop(); if (id > 0) { disposeGameSync(id); id = 0 } })
</script>

uni-app x全屏游戏将最高成绩和星级存于宿主本地,并默认提供双槽战局检查点;离线关闭后可从主页继续最近成功保存的防线,保存范围与失败语义见“战局导出、恢复与本机继续”。横竖屏实际战场覆盖可用视口,地图、塔怪、弹道和触控共用投影,不把逻辑地图缩在中央。布防菜单默认收起,点击有效可建地后显示守卫与下方真实费用,选择即建造;也可从边缘布防入口进入陷阱模式。横竖屏均使用避让塔位的顶部/边缘HUD。首次手势引导可跳过,准备好后倒计时启动首波;后台/重开/退出取消倒计时。点击已建塔升级/回收,点击牢笼可转火解救;救援/陷阱不作为通关前置。菜单提供地图、图鉴、手册、音效、重开与诊断,已有局换关需确认重置。

分类 / 公共区域 能力 / API 测试方法
uni-app API示例自定义开局 getGameCatalogSync、createGameSync({ catalog, rules }) 点击自定义配置开局,观察650金币、30生命、6波与弓塔60金币;确认后可恢复默认;无尽模式仍逐波继续
启动页 / 全屏主菜单 / 独立选关 宿主资源加载、当前局入口、目录选择与创建会话 资源准备失败可重试,开始/选关后创建战局,回主页保留当前局
全屏战场 / 顶部 HUD createGameSync、advanceGameSync、快照读取 建塔后开始波次,观察敌人行进、攻击、金币、生命及波次
横竖屏收起式边缘布防 / 塔浮层 build、upgrade、sell 点击有效可建地后选守卫,核对下方费用与实际扣款、菜单收起和HUD避让;已建塔可升级/回收
已建塔索敌 / uni-app策略按钮 towerPriority、TowerState.priority、rules.defaultTargetPriority 建塔后切换三策略,核对真实快照、暂停可改、升级保留及导出恢复;原生另验
横竖屏边缘操作 / 双技能 startWave、skill 准备阶段开始下一波,检查技能冷却、暂停冻结与首领波
首次引导 / 倒计时 firstPlayGuide/countdownSeconds/countdownEveryWave 可跳过,取消/后台/重开不残留计时或启动旧局
陷阱站点 / 救援目标 placeTrap、targetRescue、traps/rescues 验证真实扣费/一次触发/转火/一次奖励、暂停拒绝及不阻止通关
地图选怪 / 紧凑目标条 targetEnemy、enemyTargetId、enemyTargeting及受控命中桥 真实弹道/HP证明集火,检查各塔射程回退、救援互斥、取消不恢复、离场清理与旧输入拒绝
顶部控制 / 暂停菜单 pause、resume、speed 暂停后位置/冷却不推进,恢复后继续;切后台再回来
暂停菜单内地图 / 图鉴 / 手册 getGameCatalogSync 核对路线、建造点与四塔说明,切图不绕过重置提示
暂停左上画面修复 / 精灵画板 rendererRecovery、有限手动重试与startup阶段报告 真实资源失败后同session暂停;恢复资源重试后仍暂停,明确继续或兼容;次数耗尽、旧实例与后台分别验证,不用合成成功代替真实loader
暂停菜单公共诊断 / uni-app 示例底部 getGameDiagnosticsSync、释放 复制固定报告,剪贴板拒绝时手动回退,退出后重新进入
全屏胜负舞台 真实终态、本地战绩与星差 标准模式胜利或生命归零后一次结算,可跳过演出;尾关不回绕,保存异常可重试

API 用途速查

资源缓存辅助方法见第五章,属于独立前端模块;下列 UTS 规则 API 数量与调用入口保持不变。

同步方法

方法 用途 返回 / 失败
getGameCatalogSync() 获取地图与塔目录的独立副本 GameCatalog
createGameSync(options) 从默认或自定义目录/规则创建隔离会话,初始为 ready GameSnapshot;非法配置9101001或会话上限抛错
dispatchGameActionSync(sessionId, action) 派发建造、控制、技能等动作 GameResult;业务错误以 ok=false 返回
advanceGameSync(sessionId, deltaMs) 由宿主推进固定步进模拟 GameSnapshot;非法步长/会话抛错
getGameSnapshotSync(sessionId) 获取独立的状态副本 GameSnapshot;无效会话抛错
getGameDiagnosticsSync(sessionId) 获取有界操作日志、步数和资源数 GameDiagnostics;无效会话抛错
getGameSaveSync(sessionId) 导出非终态战局的自包含JSON字符串 string;无会话9101002、终态9101003、归档超限9101001抛错
restoreGameSync(serialized) 校验后创建独立新会话;不覆盖原活动局 GameSnapshot;坏档9101001、终态9101003、8会话上限9101008抛错
disposeGameSync(sessionId) 释放会话及其内部资源 GameResult;重复释放已知会话幂等

调用均为同步,不提供 success/fail/complete、监听或后台线程。不要从多个线程同时推进同一会话;页面/宿主串行调用。返回快照可渲染、不可用作修改引擎状态的入口。

创建、推进与动作参数

参数 类型 必填 说明 默认值 可选参数
options.levelId string 是 内置地图标识 无 woodland / creek / ruins
options.mode string 是 标准通关 / 无尽递增 无 standard / endless
options.seed number 是 可复现战斗种子;同配置与动作顺序使用同一值,非密码学随机 无 整数 0..2147483646,示例 42 / 20261107
options.catalog GameCatalog 否 完整目录替换;创建时逐层校验复制,非局部合并 内置四塔三关 见下方目录限制
options.rules GameRules 否 按会话覆盖填写的规则字段,未填写使用默认 下方各项默认值 见下方规则范围
serialized string restore时是 getGameSaveSync返回的完整字符串;非空、最多1048576个UTF-16代码单元(1Mi长度预算,非UTF-8字节上限) 无 仅受支持格式
sessionId number 是 创建或恢复时返回的本进程新会话编号,不跨进程复用 无 有效活动会话编号
deltaMs number 是 本次逻辑经过时间;内部 50ms 固定步进,小余量累计 无 0..250 毫秒有限数
action.type string 是 操作标识;动作扩展不增加API数量 无 build / upgrade / sell / startWave / pause / resume / speed / skill / placeTrap / targetRescue / targetEnemy / towerPriority
action.slotId number 是 塔动作(含towerPriority)取已建塔塔位ID(build可取空塔位);placeTrap取陷阱站点ID;targetRescue取救援ID或0;targetEnemy取当前活怪ID或0取消;其他传0 无 各自ID空间中的有效整数
action.towerId string 是 建造时为塔种;技能时为技能标识;其他传空串 无 arrow / cannon / frost / arcane;meteor / blizzard;''
action.value number 是 speed 动作设定倍速,其他动作传 0 无 1 / 2,其他动作 0

| action.priority | string | towerPriority时是 | 其他动作可省略;本动作无单位、成功后作用于本塔下一次选敌;不消耗金币或重置冷却 | 无,不传拒绝 | front / strong / near |

自定义规则与目录限制

以下数值均须有限;标记整数的字段不得传小数。配置一旦创建不支持热更新,重新创建会话才能使用新值;失败不应留下部分会话。非法配置统一抛9101001。默认目录、调用方输入和每个活动会话互相隔离,不会因修改一个对象影响另一局。

参数 类型 必填 说明 默认值 可选参数
rules.defaultTargetPriority string 否 创建会话时校验隔离;省略/null取默认,新建及出售重建的塔使用,无单位 front front / strong / near
rules.startingLives number 否 初始/最大生命,整数 20 1..999
rules.enemyHealthMultiplier number 否 敌人生命倍率 1 0.1..10
rules.enemySpeedMultiplier number 否 敌人速度倍率 1 0.25..4
rules.upgradeDamageMultiplier number 否 每次升级伤害倍率,结果按实现取整 1.65 1..5
rules.sellRefundRatio number 否 累计投入回收比例,金额向下取整 0.7 0..1
rules.meteorCooldownMs number 否 雷击冷却,整数毫秒 25000 1000..120000
rules.blizzardCooldownMs number 否 寒霜冷却,整数毫秒 30000 1000..120000
rules.trapCost number 否 每枚陷阱费用,整数;UI与规则用同一配置 80 1..1000000
rules.trapDamage number 否 触发时范围内各敌人伤害,整数 100 1..1000000
rules.trapRadius number 否 触发和伤害的逻辑半径 95 有限1..300
rules.trapSlowMs number 否 触发后减速时长,整数毫秒;0表示无持续减速 2400 0..30000
catalog.towers TowerDefinition[] catalog内是 必须恰好四项,以下四ID各一次,不可自定义行为脚本 内置四塔 arrow / cannon / frost / arcane
tower.id/name/role/description/color string 是 均非空;长度上限分别32/64/64/300/32;color仅校验非空和长度,显示层使用合法颜色 内置值 ID固定;其余文本可改
tower.cost/damage number 是 正整数 内置值 1..1000000
tower.range number 是 逻辑距离 内置值 1..2000
tower.intervalMs number 是 攻击间隔,整数毫秒 内置值 50..120000
catalog.levels LevelDefinition[] catalog内是 完整替换关卡列表 内置三关 1..32项
level.id/name/subtitle/difficulty/description string 是 均非空;长度上限32/64/100/32/300;关卡ID唯一 内置值 自定义字符串
level.startingGold number 是 初始金币,整数 内置值 0..10000000
level.waves number 是 标准模式目标波数,整数;无尽不因此结束 内置12 1..200
level.enemyHealthMultiplier number 否 关卡敌血倍率,与全局rules倍率相乘;不由关卡ID隐式决定 缺省1;内置林地1/溪谷1.1/遗庭1.2 有限0.1..10
level.route GamePoint[] 是 相邻点不得重合,坐标有限 内置折线 2..64点;x为0..1000,y为0..620
level.slots BuildSlot[] 是 ID为本关唯一正整数,坐标有限 内置塔位 1..64项;id为1..1000000,x为0..1000,y为0..620
level.trapSites BuildSlot[] 否 ID在陷阱站点内唯一,与塔位ID空间分离;必须在路线1逻辑单位误差内 省略为空;内置每关2项 0..16项;id为1..1000000整数,x为0..1000/y为0..620有限数
level.rescueTargets RescueDefinition[] 否 救援目标ID独立唯一,坐标有限 省略为空;内置每关1项 0..8项;id为1..1000000整数,x为0..1000/y为0..620
rescue.name string 是 非空目标名 无 1..64字符
rescue.hp number 是 正整数目标生命 无 1..1000000
rescue.rewardGold number 是 解救一次奖励金币,整数 无 0..1000000

敌人生命为基础生命×波次成长×关卡倍率×全局rules.enemyHealthMultiplier,四舍五入且至少1。改变关卡ID不会额外改变难度。路线可以有对角线;校验保证上述范围与相邻点不重合,不代替关卡可通关性、塔位道路间距或素材许可验收。目录本体须为对象,towers/levels/route/slots必须真实数组、文本字段必须字符串;畸形输入同样返回9101001。外部JSON须先按明确类型与边界解析,不传任意动态对象或代码;本API没有远程脚本、规则回调或存档迁移能力。自定义配置对应的资源、文案主题与本地存储隔离由自己的宿主维护。

模板表现参数

此表对应开发期GAME_PRESENTATION,不属于九个规则API参数。文字布局与资源正确性由接入者在目标手机视口验收,模板没有对文本长度/资源存在作规则层验证。

参数 类型 必填 说明 默认值 可选参数
brandName string 是 启动页/主页/弹层品牌文案,修改后复核排版 森境守卫 简短非空文案
tagline string 是 主菜单副标题,紧凑布局可能隐藏 守住微光,直到破晓 自定义文案
assetBase string 是 素材逻辑根目录,须以/结尾;由资源客户端解析,更换素材需复核道路投影 /uni_modules/lizhao-forest-guard/static/art/ 自己的合法静态目录
landscapeBackground string 是 与assetBase拼接的横屏启动/主页/选关背景文件名,加载时验证可读取 grove-landscape-v1.png 同目录内自己的合法背景文件名
allowEndless boolean 是 无尽模式菜单入口是否显示 true true / false
initialSound boolean 是 无本地偏好时初始音效开关;不是强制覆盖已有偏好 false true / false
soundVolume number 是 音量;应传有限0..1,现有播放层对数值钳制 0.25 0..1
battleAnnouncements boolean 是 开波成功提示、每4波首领预警、进场与清场播报;仅开发期页面表现配置 true true / false
bossHealthBar boolean 是 首领实际在场时显示真实hp/maxHp与寒霜状态;仅控制对应HUD,不改规则 true true / false
firstPlayGuide boolean 是 首次手势引导,可跳过;本地完成标记grove-tutorial-v2 true true / false
countdownSeconds number 是 开波前准备秒数,只接受有限整数;0跳过,非法值不启动波次 3 0..5
countdownEveryWave boolean 是 是否每波倒计时;false只首波 false true / false
autoWaveEnabled boolean 否 连续迎敌功能可用;false隐藏开关且不计时,保留旧偏好;非法逐项诊断回默认 true true / false
autoWaveDefault boolean 否 仅确认偏好键不存在时的初值,不覆盖保存值;读取异常或非boolean安全关闭;非法逐项诊断回默认 false true / false
autoWaveDelayMs number 否 自动整备等待,整数毫秒,与规则倍速无关;非法逐项诊断回默认 5000 1000..15000且为50的整数倍
motionEnabled boolean 是 配合active控制页面/引导/弹框动效,并传入绘制包;关闭装饰动作仍保留必要HP/弹道,不改变规则 true true / false
adventureMedals boolean 是 印记入口/演出和新的救援收藏开关;关掉保留旧档、正常星级;非法值诊断并默认true true true / false
levelObjectives boolean 是 仅控制目标入口与前场预览,不改变规则或印记条件;非法值诊断并默认true true true / false
waveIntel boolean 是 顶部侦察入口开关;不改快照/规则;非法值诊断并默认true true true / false
towerStrategies boolean 否 仅完整游戏已建塔浮层策略入口;false/非法非boolean隐藏,非法诊断,不改规则或归档;重建页面生效 true true / false
enemyTargeting boolean 是 场景轻点/战场键盘选怪开关;不禁用API,API目标仍可见并可取消;非法值诊断并默认true true true / false
enemyIntelProfiles EnemyIntelProfileOverride[] 是 按kind部分覆盖,页面加载时校验、逐字段回退并诊断 [] 既有四类
levelUnlockMode string 是 章节顺序解锁/开放;非法值记录诊断并降级sequential;历史后章通路保留 sequential sequential / open
resultAnimationMs number 是 结算演出有限毫秒;非法值记录诊断并降级1800;0或关闭动效立即完整显示 1800 0..4000
renderer string 是 仅改变显示方式;非法值记录真实配置错误并回退基础显示 phaser phaser / native
rendererRecovery boolean 否 完整uni-app x页面画面修复开关;false保留诊断并沿用兼容回退;非法逐项诊断回默认,重建页面生效 true true / false
rendererRetryLimit number 否 每次进入战场的额外手动重试次数,无单位;0仍可兼容继续;非法逐项诊断回默认,重建页面生效 2 整数0..3
rendererStartupTimeoutMs number 否 同一准备周期的前台预算,整数毫秒;后台暂停,重复loading不续命;非法逐项诊断回默认,重建页面生效 20000 整数3000..60000
renderQuality string 是 传入绘制包options.quality;low为1倍物理画布,balanced/high随设备DPR最高2倍,逻辑坐标不变 balanced low / balanced / high
renderFps number 是 传入options.fps的目标帧率,不是性能保证 60 30 / 60
bridgeHz number 是 发布器刷新率,有限数值;动作/状态变化可立即强制刷新 10 1..20 Hz
particles boolean 是 是否启用粒子表现,不改变实际伤害 true true / false
particleLimit number 是 活动粒子数量上限,整数 120 0..300
cameraShake boolean 是 是否启用技能镜头震动 true true / false
frame.options.interpolationMs number 绘制包内是 插值时长;当前模板由1000 / bridgeHz推导,不是独立GAME_PRESENTATION字段 100 50..1000有限毫秒
frame.options.motionEnabled boolean 否 normalizeRenderOptions白名单字段,根页面由presentation.motionEnabled传入;非boolean抛TypeError true true / false

normalizeRenderOptions对白名单类型/范围抛出真实TypeError/RangeError,根页面捕获后回退基础显示并写入运行诊断;这属于表现配置错误,不冒充规则API的9101001。不同质量档和粒子上限仍须结合设备实测,不承诺60FPS。

敌情表现覆盖项由宿主uni_modules/lizhao-forest-guard/static/game/wave-intel-model.ts定义,不是UTS业务API:

参数 类型 必填 说明 默认值 可选参数
kind string 是 既有怪物;未知忽略,重复保留首项并诊断 无 sprout / runner / brute / boss
name string 否 trim后1..12个Unicode字符;非法回默认 对应默认名称 合法文字
tip string 否 仅侦察战术提示,trim后1..120个Unicode字符并完整分页;不覆盖图鉴短简介 对应默认提示 合法文字
art string 否 ≤64字符ASCII安全basename,字母/数字开头,其后可含下划线/连字符,小写.png后缀;禁止路径、URL、查询串 kind-moon.png 自备合法PNG名

easycom组件与帧协议

组件名为lizhao-forest-guard,路径为uni_modules/lizhao-forest-guard/components/lizhao-forest-guard/lizhao-forest-guard.uvue。全屏宿主容器自行提供尺寸,组件位于底层且不接管触控。

参数 类型 必填 说明 默认值 可选参数
frame string 是 JSON序列化的绘制包v1;空串不发送,长度超过262144字符触发failure 无 使用createRenderPublisher生成
resources string 默认素材必填 JSON 字符串 {format:1,version,files},files 为 art/ 文件名到已解析地址的映射;最多 196608 字符,活动渲染实例保持固定 空字符串 JSON.stringify({format:1,version,files:getResourceMap('art/')})
active boolean 否 控制Phaser绘制活动,不替代UTS规则暂停 true true / false
hostEpoch number 否 宿主非负安全整数代际,组件setup固定捕获;重试用新key创建新实例,不原位改代际 0 非负安全整数,无单位
foreground boolean 否 前后台门禁;false停止准备预算/探测及输入,恢复补静态帧不推进规则;active=false且前台仍可加载 true true / false
startupTimeoutMs number 否 同周期前台准备预算,毫秒;有限值钳制到3000..60000,非有限值默认;重复loading不重置,ready后新资源loading新周期 20000 3000..60000;完整Host仅接受整数
inputEnabled boolean 否 宿主允许本次场景命中;组件还检查active、running和当前会话ready能力 false true / false
inputEpoch number 否 宿主单调递增输入代际;同局暂停/弹框/后台/布局/后端改变时同步失效旧输入 0 非负安全整数
tapRequest string 否 JSON序列化EnemyHitRequest;空串不发送,超过512字符或格式/门禁不符直接丢弃 空串 当前session/epoch及严格递增requestId
ready事件 string 事件 JSON字符串,含sessionId、renderer、version、textures及可选enemyHitTest;只有enemyHitTest===true声明本次命中能力 无 实际本地渲染就绪
enemyTap事件 string 事件 JSON序列化EnemyTapResult;只转发当前门禁下尚未消费的最新请求结果,enemyId为0表示有效空白 无 当前session/epoch/requestId及非负enemyId
loading事件 string 事件 JSON字符串,含sessionId;保持旧事件合同,同一未完成周期不重置准备预算 无 初次及旋转/地图纹理加载
failure事件 string 事件 最多300字符真实错误;同一组件实例至多一次失败终态 无 资源/脚本/超时/WebView错误等
diagnostics事件 string 事件 JSON统计字符串,来自stats,追加固定hostEpoch/instance及当前sessionId并拒绝错session;不当作规则状态 无 实际renderer、frames、packets、粒子/实体/拒包等计数
startup事件 string 事件 结构版本1的有界阶段JSON;仅真实阶段首次发送,重复只计数,不逐帧发送;完整Host按三身份严格接收 无 下述白名单字段;失败终态冻结

宿主到本地页使用固定信封{ protocol: 'forest-renderer-v1', instance, type, payload },消息 type 为 resources/frame/active/dispose/probe 及 enemyInput/enemyHitTest;本地页回报 resources-ready/bridge-ready/loading/ready/error/stats/startup 及 enemyTap。素材字典有独立握手,不塞入普通高频绘制帧,也不重置输入门禁。Web验证同源、消息来源窗口、protocol和实例标识,App仅调用固定本地入口,消息不允许指定任意宿主方法或执行脚本。

startup对象字段为version:1、hostEpoch、instance、sessionId、cycleId、phase、budgetMs、elapsedMs、wallElapsedMs、remainingMs、foreground、phases、renderer、capability、message。计时均为毫秒:elapsedMs是前台消耗,wallElapsedMs是本周期墙钟经过时间,remainingMs是剩余预算;不作规则时钟。phases最多12项,每项{stage,atMs,count}保存本周期首次阶段时间及有界计数。阶段为context/source/load/bridge-ready/first-frame/loading/assets-ready/ready/failure/disposed/suspended/resumed;允许真实乱序,first-frame来自Renderer接受首帧ACK,assets-ready来自真实loader完成,不把sendFrame当ACK。

renderer含visibility、hidden、hostActive、sceneCreated、loading、generation、assetsReady、sampledAtMs;visibility未知为unknown,其余不能取得的状态/数字为null。sampledAtMs是收到最后真实采样时的本周期墙钟毫秒,旧采样不冒充失败瞬间状态。capability含enemyHitTest、renderer(unknown/Canvas/WebGL)、version(未知为unknown);message最多300字符。Host拒绝超过8192字符或白名单类型/范围不符的startup字符串,不接收完整frame或任意动态对象。公开ready/loading/failure等旧事件仍可用于既有接入,完整游戏以startup为准备状态权威,不能将diagnostics计数当成规则或ready证明。

enemyInput载荷为{sessionId,inputEpoch,enabled},请求为{sessionId,inputEpoch,requestId,x,y,timeMs},结果为{sessionId,inputEpoch,requestId,enemyId}。sessionId/requestId是正安全整数,inputEpoch/时间戳/结果ID是非负安全整数,x/y为0..8192有限CSS逻辑像素;timeMs取轻点时Date.now毫秒,不是规则elapsedMs。组件在ready接收enemyHitTest能力后才发送;缺能力的旧渲染器只关闭选怪,不吞塔位/HUD操作。宿主在组件之外再次校验当前前台、battle/running、无弹框或倒计时、就绪状态、session/epoch和最新requestId,随后引擎再验证活怪,旧/重复/乱序结果不改变目标。加载、卸载、旋转和失效门禁均清待处理请求;普通绘制帧变化不提高epoch。上面的最小布阵示例显式关闭命中,不实现地图输入;完整接入须复用全屏页面的手势与门禁实现,不能仅把inputEnabled写true。

绘制包含version:1、sessionId、单调sequence、state/timeMs/levelId、portrait/width/height/board、assetBase/selectedSlot、towers/enemies/shots/effects/options,现补充traps/rescues/rescueTargetId/enemyTargetId。塔含id/slotId/towerId/level/x/y/range及可选真实出手aim四字段;敌人含id/kind/x/y/hp/maxHp/slowMs;弹道含起终坐标/类型/寿命,effects为id/kind/targets。陷阱/救援按快照真实状态绘制,不是页面自行发奖。旧会话、旧序号和旧组件实例消息不可覆盖新状态。createRenderPublisher有push(snapshot, context, now, force)、effect(kind, targets)、reset()和getStats(),属于静态表现辅助模块,不增加九个UTS业务API;每个发布器属于单一宿主实例。队列默认最多256弹道/32效果,丢弃数量进入统计,reset清会话而保留累计诊断计数。

状态与结果

ready 表示准备/上一波结清,可布防与开始下一波;running 表示当前波运行;paused 表示手动或宿主暂停,恢复回暂停前阶段;won/lost 是不可继续推进战斗的终态。标准模式清完最后一波胜利,生命耗尽失败;无尽模式不产生通关胜利。

参数 类型 必填 说明 默认值 可选参数
GameResult.ok boolean 返回 是否成功 不适用 true / false
errSubject string 返回 固定插件错误主题 lizhao-forest-guard 固定值
errCode number 返回 成功为 0,失败见错误表 不适用 0、9101001..9101008
errMsg string 返回 真实业务结果说明 不适用 字符串
GameSnapshot.state string 返回 当前战斗状态 ready 上述五状态
sessionId/levelId/mode/seed number / string 返回 会话和配置身份 创建值 见创建参数
wave/totalWaves number 返回 当前波和目标波数 创建配置 标准模式依地图目录
gold/lives/maxLives/kills/score number 返回 金币、生命、击杀和得分 创建配置 非负数
elapsedMs/speed/spawnRemaining number 返回 逻辑经过时间、倍速、当前波待刷怪数量 0 / 1 / 0 毫秒、1或2、非负整数
towers[].priority string 新Core必返,类型可选 每塔实际策略;缺字段的旧快照隐藏选择器,不伪造默认 会话默认策略 front / strong / near
towers TowerState[] 返回 建造点、等级、坐标、伤害、射程、冷却、累计花费、升级费用与出售金额 空数组 以每次快照为准
enemies EnemyState[] 返回 类型、位置、生命、进度、速度、奖励与减速剩余毫秒 空数组 sprout / runner / brute / boss
shots ShotState[] 返回 起终点与剩余显示毫秒,攻击伤害已在规则内结算 空数组 仅渲染信息
skills SkillState[] 返回 技能名、当前/总冷却毫秒;暂停不会消耗冷却 创建配置 雷击、冻结
traps TrapState[] 返回 活动陷阱id/siteId/x/y,触发后移除;非站点目录 空数组 站点只允许一枚待触发陷阱
rescues RescueState[] 返回 id/name/x/y/hp/maxHp/rewardGold/freed;奖励仅由击破终态发放一次 创建自目录 freed后不能再次选中领奖
rescueTargetId number 返回 当前转火救援目标ID;0表示未指定救援,仍可能有怪物集火 0 有效目标ID或0
enemyTargetId number 可选返回 怪物优先目标ID;旧快照缺失按0,新引擎始终返回0或当前有效ID 0 活怪ID或0
waveIntel WaveIntelPreview 可选返回 独立只读敌情副本;旧快照可缺失,先判空 新引擎创建时提供 upcoming / current / complete
GameDiagnostics 对象 返回 sessionId、state、ticks、activeEnemies、logDropped、logs 不适用 每项以当前快照为准
logs GameLog[] 返回 timeMs、level、action、message;有界环形保留 空数组 logDropped 记录丢弃条数

WaveIntelGroup与WaveIntelPreview从插件根导出,通过原有快照方法读取,不新增第八个方法:

import { createGameSync, getGameSnapshotSync, disposeGameSync } from '@/uni_modules/lizhao-forest-guard'
import type { WaveIntelGroup, WaveIntelPreview } from '@/uni_modules/lizhao-forest-guard'
const game = createGameSync({ levelId: 'woodland', mode: 'standard', seed: 42 })
try {
  const intel: WaveIntelPreview | undefined = getGameSnapshotSync(game.sessionId).waveIntel
  if (intel != null) {
    const groups: WaveIntelGroup[] = intel.groups
    console.log(intel.status, intel.wave, intel.totalEnemies, groups)
  } else {
    console.log('情报不可用,请核对匹配联编产物')
  }
} finally {
  disposeGameSync(game.sessionId)
}
参数 类型 必填 说明 默认值 可选参数
WaveIntelPreview.status string 返回 upcoming下一波,current整波计划,complete本局结束 创建为upcoming upcoming / current / complete
wave number 返回 预告/计划波次;complete保留实际结束波 创建为1 正整数
totalEnemies number 返回 整波计划总量,不是在场或剩余 引擎计算 complete为0
spawnIntervalMs number 返回 出生定时器逻辑毫秒间隔,实际按50ms tick向上量化,非墙钟保证 引擎计算 complete为0
groups WaveIntelGroup[] 返回 至多四组的独立副本;complete为空 当前计划 sprout / runner / brute / boss顺序
WaveIntelGroup.kind/count string / number 返回 怪物种类与该类整波计划数量 引擎计算 既有四类 / 正整数
maxHp number 返回 基础生命,含活动会话关卡/规则倍率及原四舍五入 引擎计算 至少1
speed number 返回 1×且未减速的基础逻辑速度,单位逻辑坐标/秒 引擎计算 正数
reward number 返回 每只被击败的真实金币奖励,不由侦察发放 引擎计算 非负数

创建和每次结波回ready缓存下一波upcoming,开波切current;pause/resume保留来源阶段。current.groups表示整波编队,实时在场与待入场分别取enemies.length和spawnRemaining。胜/败均complete空组,失败不能称全部击败。预测与实际出生共用数量、RNG和属性计算,只推进局部随机,不消耗会话RNG、ID、逻辑时间、tick或日志;只在波次边界一次构建,高频get/advance最多深拷贝四组,不每50ms重算,也不为侦察把无尽限制到标准200波。修改返回对象/groups不会回写会话。

UI 应使用 upgradeCost、sellValue 与目录中的真实价格,不复制一份经济公式;所有坐标为逻辑坐标,距离为同单位欧氏距离,速度为逻辑单位/秒。shots 生命周期不参与命中裁决。暂停、终态及停止驱动期间不根据真实墙钟补算时间。

战斗数值与限制

参数 类型 必填 说明 默认值 可选参数
弓塔 arrow TowerDefinition 内置 伤害 / 射程 / 攻击间隔 19 / 215 / 650ms,80金币 三等级
炮塔 cannon TowerDefinition 内置 伤害 / 射程 / 攻击间隔,溅射半径85 39 / 230 / 1500ms,130金币 三等级
冰塔 frost TowerDefinition 内置 减速45%、持续1800ms 12 / 205 / 900ms,100金币 三等级
奥术塔 arcane TowerDefinition 内置 高伤害单体 65 / 255 / 1350ms,150金币 三等级
升级 动作 按需 最高3级;伤害倍率1.65四舍五入,每级射程+15;实际费用看快照 首次为底价80%,下次×1.5 1→2→3
出售 动作 按需 累计投入70%向下取整,实际金额看快照 无 已建造塔
雷击 meteor 技能 按需 当前全部敌人受180+波次×10伤害 冷却25000ms running时使用
冰封 blizzard 技能 按需 当前全部敌人减速45%,持续5000ms 冷却30000ms running时使用
生命 number 内置 普通敌人漏怪扣1,首领扣5;首领每4波出现 20 到0失败
日志条数 number 内置 超限丢弃最旧条,计入logDropped 80 不逐帧记录
会话数 number 内置 同一进程同时活动上限 8 退出释放

技能空放也消耗冷却。无敌人时请等待下一波或保留技能。标准模式与无尽模式各自独立创建会话,不在局内改变模式。

错误码说明

错误主题均为 lizhao-forest-guard。没有取消、超时或网络结果未知的错误码,因为该核心没有异步请求;页面清理计时器和释放会话就是停止本地任务。

错误码 含义 处理建议
9101001 非法配置、数值、未知动作/标识、towerPriority缺失/null/坏策略,或坏档/混合格式/未知格式/归档超限 检查配置与完整存档;不截断或静默改写坏档
9101002 会话不存在或已释放 重新创建会话,不使用上一局编号
9101003 当前状态不允许操作,包括暂停时放陷阱/切换救援目标,towerPriority终态拒绝,或导出/恢复终态战局 读取快照;终态重新开局,不能当作续局恢复
9101004 金币不足 等待击杀/波次收益或出售防御塔
9101005 塔位/陷阱站点无效或占用、towerPriority塔位尚未建塔、救援目标无效/已解救,或没有射程内守卫 按动作使用正确ID空间;先在目标附近建塔,不能重复领救援奖励
9101006 防御塔已满级 保留当前塔或在其他点建造
9101007 技能尚在冷却 使用快照倒计时,等待模拟时间推进
9101008 创建/恢复超过8个活动会话 释放不用的会话再创建或恢复

前端资源缓存错误

资源辅助模块使用独立的 ResourceError;errSubject 固定为 lizhao-forest-guard,含 errCode、字符串 code 和真实 errMsg。prepare() 可能以 PREPARE 包装下层请求、存储或校验错误,详情保留在 errMsg;成功使用旧缓存时从 ResourceReady.warning 读取原因。这些错误不占用规则 API 的错误编号。

错误码 code 说明
9301001 MANIFEST 配置、清单、版本、路径或必需资源合同不合法
9301002 PREPARE 素材准备失败,且没有可用的允许回退缓存
9301003 HTTP / DOWNLOAD / REQUEST 资源服务状态或请求、下载失败
9301004 SIZE 远端内容超过读取大小上限
9301005 STORAGE / FILE 持久缓存、文件读取或保存失败
9301006 CHECKSUM 素材内容摘要或字节校验失败
9301007 CANCELLED 当前准备已取消
9301008 RELEASED 资源会话已释放
9301009 PLATFORM 当前平台未提供持久素材缓存
9301099 其他 code 资源模块未归入以上类别的真实错误

注意事项

宿主与平台

宿主 / 平台 接入方式 限制
uni-app x Vue 3 / Vapor / TypeScript 完整示例,HBuilderX 5.34 系列 其他版本与渲染模式需单独适配
Web 同源 WebView 承载 Phaser,图像和声音使用准备后的资源根 浏览器音频手势、资源跨域与存储策略由宿主处理
Android Vapor 宿主、UTS 规则与本地 WebView / Canvas 表现 需要匹配的 UTS 编译产物、模块注册配置与基座;实际设备的触控、声音和剪贴板需分别确认
uni-app Vue 2 / Vue 3 选项式 API 接入页 独立宿主编译和运行尚未验证,不包含完整 uni-app x 游戏表现
iOS / HarmonyOS 共享规则源码 未完成独立原生编译、渲染和设备验证,不声明完整支持
小程序 当前完整游戏模板未适配 需要适配承载组件、模板能力与资源加载后再验证

App 使用与当前 UTS 实现和归档格式匹配的产物。UTS、原生依赖或配置改变后,应通过正式构建流程更新匹配产物及同批模块注册信息;固化旧 UTS 的自定义基座需重新生成,WGT 无法补入缺失的原生能力。普通页面、样式与文档变化通常无需重打原生基座。Web 不使用原生基座。

Web与Android本地渲染后端

Web 使用 Phaser.AUTO;Android 本地 file 页面使用 classic bundle、HTMLImageElement 资源加载与 Phaser.CANVAS,以适配本地纹理加载限制。Canvas 保留基础粒子和 Graphics 绘制,tint 等视觉可能与 WebGL 不同,不承诺全部光效一致或固定帧率。

Phaser4.2.1不读取GameConfig.resolution,本实现以物理画布尺寸、CSS显示尺寸和摄像机缩放实现高清。low固定1倍,balanced/high按DPR限制在1至2倍;不重复缩放塔位或触控。2倍的像素数及基础像素缓冲约为1倍的4倍,不增加素材文件,也不表示固定帧率。诊断提供backingWidth/backingHeight、logicalWidth/logicalHeight及pixelRatio。依据:固定版本配置源码、缩放管理器源码。

Phaser4.2.1仍含Canvas,但官方已将其标为deprecated;未来升级前必须核对该后端是否保留,并复验Android file加载、粒子/Graphics与视觉差异,不能只验证WebGL后直接升级。依据:Phaser官方渲染器说明。

外置资源与逻辑路径

图像与音频源位于 game-assets/lizhao-forest-guard/runtime/,按 art/ 和 ui-icons-v2/ 组织;发布目录为 deliverables/game-assets/lizhao-forest-guard/。这些素材不放入插件目录。文中 /uni_modules/lizhao-forest-guard/static/art/ 等旧资源根是兼容逻辑标识,不能作为物理文件存在的依据;页面通过资源客户端取得准备后的文件地址。替换素材须保持逻辑文件名、许可和道路投影一致。

渲染依赖、许可与包体

固定本地Phaser 4.2.1,并附DCloud uni.webview 1.5.5。默认没有运行时CDN请求,不需要新增系统权限。来源、固定哈希与原始字节见uni_modules/lizhao-forest-guard/static/renderer/vendor.json;插件自有代码许可不覆盖第三方的独立许可义务。

本地库 来源与许可 随附文件 原始文件大小
Phaser 官方发布库,MIT uni_modules/lizhao-forest-guard/static/renderer/phaser.min.js、uni_modules/lizhao-forest-guard/static/renderer/PHASER-LICENSE.txt 1375976字节
DCloud uni.webview 固定官方仓库提交,Apache-2.0,原库未修改 uni_modules/lizhao-forest-guard/static/renderer/uni.webview.1.5.5.js、uni_modules/lizhao-forest-guard/static/renderer/DCLOUD-LICENSE.txt 6146字节

美术由原目录引用,未复制第二套;粒子纹理在渲染层生成。上述原始文件大小不是APK/AAB/IPA增量,也不含平台压缩、分包、架构或基座差异。设置renderer: 'native'只改变显示,静态库仍会打包;本次没有生成或上传发布包,不声称该开关减少安装包体积。

外置资源包提供同组浮雕功能图标、场景、角色、塔怪、评级、印记和音效,图像保持原文件名与透明通道。GameStar 使用 rating-star-filled-v1.png / rating-star-empty-v1.png;印记使用 medal-clear-v1.png、medal-tristar-v1.png、medal-rescue-v1.png,领奖台为 award-podium-v1.png。缺图按各组件的真实回退逻辑处理。插件代码与素材可用范围见随附许可,第三方库遵守各自独立许可;不授予其他游戏角色或商标的使用权。

资源与生命周期

  • 森境横屏优先,扣除四边安全区后决定紧凑布局;保留竖屏兼容。主要触控至少 44×44,空塔位、已建塔、浮层与 HUD 需要避让,长图鉴独立分页或滚动;方向与系统栏只配置自己的游戏页面。
  • 规则坐标固定为1000×620,左上为原点,距离与命中在该空间计算。显示层使用 uni_modules/lizhao-forest-guard/static/scene-projection.js 对三张地图的横竖场景分别设置道路锚点,按区间线性投影到归一化画面坐标。塔位、敌人、弹道与射程轮廓共享投影,不把逻辑圆形射程简单画成等比屏幕圆;竖屏也不是仅交换坐标或拉伸横屏图。扩展地图需同时校准横竖素材和投影。安全区、旋转与触控仍需在实际设备核验。
  • 核心没有计时器、输入监听、音频、纹理或网络资源;宿主拥有并清理它们。素材附有原创合成提示音 外置包中的 art/chime.wav,由界面按设置播放,不是规则依赖,不需要麦克风权限。
  • 计时器建议 50ms 调用一次。宿主前后台切换先停止定时器并暂停,返回后由玩家继续;不要追补后台经过的真实时间。
  • 系统可能丢弃WebView的Canvas缓冲。可见恢复时即便宿主仍暂停,也补绘一帧静态地图再休眠;该帧不推进敌人、冷却或规则时间,隐藏期间不持续绘制。
  • 一局一个 sessionId;退出页面先停止计时器再释放。重新开始用新编号,旧编号不能写入新局。
  • Phaser组件拥有自己的画布、纹理、粒子、监听与准备预算;返回主页或卸载时销毁,不销毁宿主共有资源。失败先冻结阶段报告并走专用幂等释放通知,终态停止准备计时与探测。纯UTS规则仍只受唯一50ms时钟驱动;Phaser每帧插值和特效不重复执行规则。恢复模块启用时失败先暂停,玩家选兼容后才继续;模块关闭沿原兼容回退,回退仍可真实建造/扣款。
  • 资源包保留 -moon.png 等现有文件名,名称是兼容标识。自备素材应保持配置引用一致,并自行确认使用许可、道路位置、透明边界和点击范围。
  • 本地成绩与设置由宿主页维护。核心没有云存档、在线排行、支付、奖励发放或防作弊承诺。
  • 不逐帧打印日志;日志有界并记录丢弃数量。快照与渲染频率会影响性能,尚无真实设备性能结论。
  • 页面、引导、弹框和渲染装饰动作受active/motionEnabled控制;四类攻击、到达爆点、受击短停/回弹、死亡/解救/陷阱按真实事件反馈,关闭装饰仍保留必要HP/弹道。规则暂停冻结战斗动效,不以飘字替代伤害。替换表现资源后需分别检查 Canvas 与 WebGL 的实际效果。

诊断与隐私

uni-app x 全屏界面的公共诊断入口位于暂停菜单,包含“一键复制日志”和报告框;uni-app API 验证示例仍在页面底部提供同类入口。报告包含生成时间、报告编号、插件真实 package 元数据来源、宿主/可取得设备字段、状态快照、操作日志与释放结果。不读取账号、Token、文件或个人信息,不上传。不能获取的 HBuilderX/原生基座构建版本标为 unknown;开发电脑的版本不能冒充安装包构建版本。

画面启动诊断包含当前 session/epoch/instance、准备周期、剩余前台预算、真实阶段与计数、最后 Renderer 采样、剩余手动次数和最近最多四份失败快照。失败后释放或成功重试不会覆盖历史失败原因,旧实例的 startup/stats 被拒绝。重试保留同局塔、策略、经济和规则时钟,准备好后仍等待玩家明确继续。

增强诊断包含实际渲染器、版本、绘制与桥接/丢弃计数,以及是否使用基础显示;这些信息不代表固定帧率承诺。Web 提示音主动取消与真实播放失败分别处理并保留诊断,Native 使用 uni 音频能力。

长报告从同一个固定快照分段复制,成功后才推进分段;复制失败显示真实错误并提供文本手动复制。每次点击重新生成会创建新报告。原生剪贴板和跨平台分享需在实际设备验收。

作者系列 UTS 插件

以下为作者其他 UTS 插件的功能索引,具体平台和接入条件以各插件页面为准。

插件 能力方向 插件市场
lizhao-alipay-kit 支付宝授权登录、App 支付与脱敏诊断 市场详情
lizhao-app-keepalive 应用保活、唤醒、自愈与报告 市场详情
lizhao-bg-audio 背景音频播放、队列、倍速与事件 市场详情
lizhao-ble BLE 扫描、连接、读写、通知与自动重连 市场详情
lizhao-call-kit 电话、短信、通讯录原生能力 市场详情
lizhao-camera-pro 原生相机、拍照录像、水印与媒体保存 市场详情
lizhao-cast-screen DLNA 投屏、AirPlay 路由入口 市场详情
lizhao-choose-file 原生文件选择、上传、进度与取消 市场详情
lizhao-device-id 设备标识、隐私策略与诊断 市场详情
lizhao-doc-corrector 文档扫描、矫正、增强与识别 市场详情
lizhao-emu-detect 模拟器环境检测、风险评分与证据 市场详情
lizhao-float-window 悬浮窗、画中画、权限与诊断 市场详情
lizhao-gallery-pro 相册媒体分页、筛选、缩略图与导出 市场详情
lizhao-hce-card NFC 虚拟卡、APDU 交互与 NDEF 标签模拟 市场详情
lizhao-health 健康数据授权、查询、统计与写入 市场详情
lizhao-http-server 本地 HTTP 服务、文件传输与实时通信 市场详情
lizhao-icon-pro SVG 图标组件、多主题与缓存 市场详情
lizhao-id-photo 证件照制作、尺寸换算、换底色与模板换装 市场详情
lizhao-img-eraser 图片去水印、局部修复与原生编辑器 市场详情
lizhao-live-activity 实时活动、系统胶囊与普通通知降级 市场详情
lizhao-nfc-pro NFC 标签读写、NDEF、IsoDep 与诊断 市场详情
lizhao-notify-pro 本地通知、点击动作、进度与定时提醒 市场详情
lizhao-novel-reader 原生小说阅读、仿真翻页与段落评论 市场详情
lizhao-office-view Office 与 PDF 文件预览、进度与缓存管理 市场详情
lizhao-pdf-pro PDF 阅读、签批、真实写回与页面处理 市场详情
lizhao-scan-pro 原生扫码、连续扫码、相册识别 市场详情
lizhao-serial-port 路径串口、USB 串口、多会话收发与诊断 市场详情
lizhao-share-plus 系统分享、远程文件下载后分享 市场详情
lizhao-smart-tts 系统 TTS、云端合成、听书方案 市场详情
lizhao-sqlite-pro 原生 SQLite、迁移、备份与诊断 市场详情
lizhao-sse-pro SSE、Line、JSONL 与 Raw 流式请求 市场详情
lizhao-tcp-pro TCP 客户端、服务端、多连接与诊断 市场详情
lizhao-usb-storage U 盘、移动硬盘文件浏览、读写与批量复制 市场详情
lizhao-video-editor 视频裁剪、压缩、取帧与 FFmpeg/FFprobe 市场详情
lizhao-video-feed 短视频上下滑、短剧选集与分页加载 市场详情
lizhao-video-player 原生视频播放器、清晰度与播放交互 市场详情
lizhao-video-thumb 视频封面、批量取帧与 Base64 返回 市场详情
lizhao-vpn-pro 企业 VPN、IKEv2、安全接入与脱敏诊断 市场详情
lizhao-wechat-kit 微信登录、分享、支付、小程序与客服 市场详情

隐私、权限声明

1. 本插件需要申请的系统权限列表:

默认本地运行无需新增系统权限;内置Phaser与DCloud uni.webview第三方JavaScript,随附许可,不使用运行时CDN。

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

默认本地运行,不采集、不上传数据;示例仅在本地保存成绩和设置。

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

无广告

暂无用户评论。