evomeme-dev 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/README.md +247 -0
  2. package/bin/evomeme +28 -0
  3. package/dist/canvas-public/app.js +5857 -0
  4. package/dist/canvas-public/cycle-detect.js +166 -0
  5. package/dist/canvas-public/index.html +395 -0
  6. package/dist/canvas-public/sequence-sheet.js +59 -0
  7. package/dist/canvas-public/smart-split.js +185 -0
  8. package/dist/canvas-public/styles.css +2276 -0
  9. package/dist/canvas-public/vendor/painterro.min.js +3 -0
  10. package/dist/index.js +25586 -0
  11. package/package.json +69 -0
  12. package/skills/evomeme-cloud-fs/SKILL.md +176 -0
  13. package/skills/evomeme-cloud-fs/agents/openai.yaml +7 -0
  14. package/skills/evomeme-cover/SKILL.md +132 -0
  15. package/skills/evomeme-cover/agents/openai.yaml +7 -0
  16. package/skills/evomeme-game-maker/SKILL.md +214 -0
  17. package/skills/evomeme-game-maker/agents/openai.yaml +4 -0
  18. package/skills/evomeme-login/SKILL.md +92 -0
  19. package/skills/evomeme-login/agents/openai.yaml +7 -0
  20. package/skills/evomeme-native-bridge-sdk/SKILL.md +286 -0
  21. package/skills/evomeme-native-bridge-sdk/agents/openai.yaml +7 -0
  22. package/skills/evomeme-tos-upload/SKILL.md +46 -0
  23. package/skills/evomeme-tos-upload/agents/openai.yaml +4 -0
  24. package/skills/game-art/SKILL.md +121 -0
  25. package/skills/game-art/agents/openai.yaml +7 -0
  26. package/skills/game-asset-image-generator/SKILL.md +104 -0
  27. package/skills/game-asset-image-generator/agents/openai.yaml +7 -0
  28. package/skills/game-asset-image-generator/references/background.md +32 -0
  29. package/skills/game-asset-image-generator/references/static-game-assets.md +38 -0
  30. package/skills/game-audio/SKILL.md +82 -0
  31. package/skills/game-audio/agents/openai.yaml +4 -0
  32. package/skills/game-audio/references/bgm-cdn.md +127 -0
  33. package/skills/game-audio/references/sfx-cdn.md +77 -0
  34. package/skills/game-demo/SKILL.md +103 -0
  35. package/skills/game-demo/agents/openai.yaml +7 -0
  36. package/skills/game-maker/SKILL.md +111 -0
  37. package/skills/game-maker/agents/openai.yaml +4 -0
  38. package/skills/game-test/SKILL.md +58 -0
  39. package/skills/game-test/agents/openai.yaml +7 -0
  40. package/skills/game-test/references/checklists/playtest-qa.md +12 -0
  41. package/skills/game-ui/SKILL.md +169 -0
  42. package/skills/game-ui/agents/openai.yaml +4 -0
  43. package/skills/game-ui/references/checklists/game-ui-quality.md +14 -0
  44. package/skills/game-ui/references/checklists/hud-readability.md +12 -0
  45. package/skills/game-ui/references/checklists/mobile-input.md +12 -0
  46. package/skills/game-ui/references/checklists/responsive-ui-fit.md +12 -0
  47. package/skills/game-ui/references/ui-patterns.md +140 -0
  48. package/skills/game-ui/references/ui-prompt-templates.md +63 -0
  49. package/skills/phaser-2d-game/SKILL.md +127 -0
  50. package/skills/phaser-2d-game/agents/openai.yaml +7 -0
  51. package/skills/phaser-2d-game/references/engine-performance.md +64 -0
  52. package/skills/phaser-2d-game/references/engine-physics.md +139 -0
  53. package/skills/phaser-2d-game/references/engine-runtime.md +129 -0
  54. package/skills/phaser-2d-game/references/engine-spritesheets.md +99 -0
  55. package/skills/phaser-2d-game/references/engine-tilemaps.md +80 -0
  56. package/skills/phaser-2d-game/references/file-structure.md +94 -0
  57. package/skills/phaser-2d-graphics-builder/SKILL.md +68 -0
  58. package/skills/phaser-2d-graphics-builder/agents/openai.yaml +7 -0
  59. package/skills/phaser-2d-graphics-builder/assets/scorecard-anchors/scene-1.jpeg +0 -0
  60. package/skills/phaser-2d-graphics-builder/assets/scorecard-anchors/scene-2.jpeg +0 -0
  61. package/skills/phaser-2d-graphics-builder/assets/scorecard-anchors/scene-3.jpg +0 -0
  62. package/skills/phaser-2d-graphics-builder/references/checklists/compose-quality.md +10 -0
  63. package/skills/phaser-2d-graphics-builder/references/checklists/performance-safe-visual-detail.md +9 -0
  64. package/skills/phaser-2d-graphics-builder/references/checklists/premium-game-quality-gate.md +15 -0
  65. package/skills/phaser-2d-graphics-builder/references/checklists/sprite-quality.md +10 -0
  66. package/skills/phaser-2d-graphics-builder/references/checklists/technical-art-quality.md +9 -0
  67. package/skills/phaser-2d-graphics-builder/references/checklists/visual-scorecard.md +9 -0
  68. package/skills/phaser-2d-graphics-builder/references/compose-recipes.md +71 -0
  69. package/skills/phaser-2d-graphics-builder/references/graphics-prompt-templates.md +33 -0
  70. package/skills/phaser-2d-graphics-builder/references/implementation-blueprint.md +82 -0
  71. package/skills/phaser-2d-graphics-builder/references/sprite-recipes.md +90 -0
  72. package/skills/phaser-2d-graphics-builder/references/technical-art.md +67 -0
  73. package/skills/phaser-2d-graphics-builder/references/vfx-recipes.md +67 -0
  74. package/skills/phaser-2d-graphics-builder/references/visual-scorecard.md +129 -0
  75. package/skills/threejs-3d-game/SKILL.md +113 -0
  76. package/skills/threejs-3d-game/agents/openai.yaml +7 -0
  77. package/skills/threejs-3d-game/references/engine-asset-pipeline.md +116 -0
  78. package/skills/threejs-3d-game/references/engine-audio.md +70 -0
  79. package/skills/threejs-3d-game/references/engine-input-camera.md +84 -0
  80. package/skills/threejs-3d-game/references/engine-performance.md +96 -0
  81. package/skills/threejs-3d-game/references/engine-physics.md +142 -0
  82. package/skills/threejs-3d-game/references/engine-runtime.md +199 -0
  83. package/skills/threejs-3d-game/references/file-structure.md +353 -0
  84. package/skills/threejs-aaa-graphics-builder/SKILL.md +62 -0
  85. package/skills/threejs-aaa-graphics-builder/agents/openai.yaml +7 -0
  86. package/skills/threejs-aaa-graphics-builder/assets/scorecard-anchors/scene-1.jpg +0 -0
  87. package/skills/threejs-aaa-graphics-builder/assets/scorecard-anchors/scene-2.jpg +0 -0
  88. package/skills/threejs-aaa-graphics-builder/assets/scorecard-anchors/scene-3.jpg +0 -0
  89. package/skills/threejs-aaa-graphics-builder/references/checklists/aaa-game-quality-gate.md +23 -0
  90. package/skills/threejs-aaa-graphics-builder/references/checklists/aaa-visual-scorecard.md +19 -0
  91. package/skills/threejs-aaa-graphics-builder/references/checklists/material-lighting-quality.md +14 -0
  92. package/skills/threejs-aaa-graphics-builder/references/checklists/performance-safe-visual-detail.md +14 -0
  93. package/skills/threejs-aaa-graphics-builder/references/checklists/procedural-model-quality.md +15 -0
  94. package/skills/threejs-aaa-graphics-builder/references/checklists/technical-art-quality.md +17 -0
  95. package/skills/threejs-aaa-graphics-builder/references/graphics-prompt-templates.md +236 -0
  96. package/skills/threejs-aaa-graphics-builder/references/implementation-blueprint.md +161 -0
  97. package/skills/threejs-aaa-graphics-builder/references/model-recipes.md +146 -0
  98. package/skills/threejs-aaa-graphics-builder/references/render-recipes.md +90 -0
  99. package/skills/threejs-aaa-graphics-builder/references/shader-cookbook.md +292 -0
  100. package/skills/threejs-aaa-graphics-builder/references/technical-art.md +167 -0
  101. package/skills/threejs-aaa-graphics-builder/references/visual-scorecard.md +147 -0
@@ -0,0 +1,127 @@
1
+ ---
2
+ name: phaser-2d-game
3
+ description: 用 Phaser、TypeScript 与 Vite 实现 2D 浏览器游戏。在需要场景、玩法系统、摄像机、精灵动画、Arcade 物理、tilemap、DOM 覆盖层 HUD 或竖屏触控时使用。
4
+ ---
5
+
6
+ # Phaser 2D 游戏实现
7
+
8
+ ## 概述
9
+
10
+ 本技能用于 2D 浏览器游戏的具体实现阶段。
11
+
12
+ 技术栈:**Phaser 3 + TypeScript + Vite + pnpm**,正式 HUD/菜单以 **DOM 覆盖层**(通常 React)叠在 Canvas 上。
13
+
14
+ ## 架构原则
15
+
16
+ 1. **系统与场景分离**
17
+ - 系统(System)拥有游戏规则、回合顺序、移动、战斗、背包、目标和进度逻辑。(与 3D 技能的 `game/simulation` 对位:规则真相层)
18
+ - Phaser Scene 只将系统状态映射为精灵位置、摄像机运动、动画播放和特效,不持有游戏真相。
19
+
20
+ 2. **场景保持轻量**
21
+ - Boot Scene:配置初始化与资产预加载
22
+ - Menu Scene:主菜单或壳层(复杂菜单仍可走 DOM)
23
+ - Gameplay Scene:主游戏循环视图
24
+ - 可选:调试并行 Scene(不替代正式 HUD)
25
+
26
+ 3. **渲染对象可丢弃**
27
+ - 精灵容器、粒子、Tween、摄像机索具是视图状态,不是数据源。
28
+
29
+ 4. **资产键稳定**
30
+ - 通过 manifest / `public/config.json` 引用资产,业务代码不硬编码散落 URL。
31
+
32
+ ## 实现指导
33
+
34
+ - Scene 经单一边界读 System,并把输入意图回传 System。
35
+ - 优先确定性系统更新;避免在 `update` 里堆完整规则。
36
+ - 文字密、状态复杂的 HUD/菜单用 DOM,不用 Canvas 密文。
37
+ - 动画状态从游戏状态派生。
38
+ - **视口缩放只用 Phaser Scale Manager**,禁止 CSS/`transform` 手搓缩放(见 `references/engine-runtime.md`)。
39
+ - **spritesheet 先量图再写 loader**(见 `references/engine-spritesheets.md`)。
40
+
41
+ ## 引擎参考(按需加载)
42
+
43
+ 写/改 Phaser 运行时代码时,在 `file-structure.md` 之外按任务加载,勿一次性预读全部:
44
+
45
+ | 任务 | 加载 |
46
+ | --- | --- |
47
+ | 场景生命周期、Scale、delta、切场景 | `references/engine-runtime.md` |
48
+ | Arcade/Matter 选型、碰撞、对象池 | `references/engine-physics.md` |
49
+ | 任意 spritesheet / 图集 / 九宫 | `references/engine-spritesheets.md`(加载 sheet **之前**) |
50
+ | Tiled 地图、碰撞层、物件刷怪 | `references/engine-tilemaps.md` |
51
+ | 卡顿、池化、裁剪、update 分配 | `references/engine-performance.md` |
52
+
53
+ ## 覆盖的 2D 游戏类型
54
+
55
+ - 回合制格子与战棋
56
+ - 俯视探索地图
57
+ - 横版动作平台
58
+ - 角色动作战斗(精灵动画帧)
59
+ - 轻量经营或卡牌/指令对战场景
60
+
61
+ ## 摄像机与表现
62
+
63
+ - 早期确定摄像机模型:锁定、跟随、房间切换、战术平移。
64
+ - 摄像机逻辑与游戏规则完全分离。
65
+ - 震动、顿帧、视差须提升可读性,不能挡关键信息。
66
+ - 大地图:`cameras.setBounds` 与 `physics.world.setBounds` 对齐。
67
+
68
+ ## UI 集成
69
+
70
+ - HUD、指令菜单、设置与叙事用 DOM 覆盖层。
71
+ - Canvas 负责游戏世界、战斗可读性与运动表现。
72
+ - 除非项目明确要求,不在 Phaser 内渲染密集文字或复杂设置 UI。
73
+
74
+ ## 资产目录规范
75
+
76
+ ```
77
+ assets/
78
+ characters/ 精灵、帧动画
79
+ environment/ 背景、地块、场景件
80
+ ui/ HUD 图片、图标、按钮
81
+ fx/ 粒子、特效
82
+ audio/ BGM、SFX
83
+ data/ 关卡配置、对话数据、Tiled JSON
84
+ ```
85
+
86
+ ## 脚手架与配置
87
+
88
+ 新项目入口:`index.html`、`src/main.ts`、`public/config.json`。包管理器为 **pnpm**。构建产物含 `dist/index.html` 与 `dist/config.json`。目录与 config schema 以 `references/file-structure.md` 为唯一规范来源。
89
+
90
+ ## 常见反模式
91
+
92
+ React 与 Phaser 共存时,在 `root.render()` 后立即调用 `createGame()` 会形成启动竞态:React 尚未提交 `#game-container`,Phaser 便可能将 Canvas 挂到错误层级并遮住菜单,而游戏仍停留在 `menu` 或 `inputLocked` 状态,表现为画面可见但无法操作。应使用 `flushSync`、`useLayoutEffect`、回调 ref 或明确的容器就绪信号,按“React 容器提交完成 → 容器存在且尺寸有效 → 创建 Phaser”的顺序启动,并在初始化前检查容器和 Canvas 挂载关系;遇到点击无效时先确认界面状态、输入锁和 DOM 结构,再调整事件路径。
93
+
94
+ React 开发模式会执行一次额外的挂载清理与重新启动。如果旧 Phaser Scene 被销毁时没有注销其事件监听,按钮虽然收到了点击,事件却可能先命中已经销毁的旧 Scene,随后抛错并中断新 Scene 的点击处理。禁止只销毁 Phaser 实例却遗留 Scene 注册在输入系统、DOM、`window`、共享 EventEmitter 或 React 桥接层上的监听;每次 `on`、`addEventListener` 或订阅都必须有对应的 `off`、`removeEventListener` 或取消订阅,并在 Scene 的 `SHUTDOWN`/`DESTROY` 与 React effect cleanup 中完成清理。开发模式下必须验证重复“创建 → 清理 → 创建”后只剩当前 Scene 响应一次点击。
95
+
96
+ - 游戏规则写在 Scene `update` 里,没有系统边界
97
+ - Scene 间靠 `window` 可变全局传状态
98
+ - 用 CSS 缩放 Canvas 代替 Scale Manager
99
+ - 未测量就猜 spritesheet 的 frameWidth/Height
100
+ - 简单 AABB 却上 Matter
101
+ - 子弹/敌人无池化狂建销毁
102
+ - 只为方便把正式 HUD 画在 Canvas
103
+ - 资产路径硬编码多处
104
+ - 在游戏 UI 套通用 React 仪表盘模式
105
+ - 用 CRA / Next.js / npm-only 脚手架替换本规范(除非用户明确要求)
106
+
107
+ ## References
108
+
109
+ **引擎(本技能)**
110
+ - 文件结构与分层:`references/file-structure.md`
111
+ - 运行时 / 缩放:`references/engine-runtime.md`
112
+ - 物理与对象池:`references/engine-physics.md`
113
+ - Spritesheet / 图集:`references/engine-spritesheets.md`
114
+ - Tilemap:`references/engine-tilemaps.md`
115
+ - 性能:`references/engine-performance.md`
116
+
117
+ **跨技能**
118
+ - 美术风格:`../game-art/references/art-styles.md`
119
+ - 空间构图范式:`../game-art/references/scene-profiles.md`
120
+ - 2D 画面提质:`../phaser-2d-graphics-builder/SKILL.md`
121
+ - 动效规范:`../game-art/references/animation-specs.md`
122
+ - UI 风格:`../game-ui/references/ui-styles.md`
123
+ - 手感:`../game-designer/references/game-feel.md`
124
+ - 关卡设计:`../game-designer/references/game-design-level-design.md`
125
+ - 新游戏 DoD:`../game-designer/references/checklists/new-game-definition-of-done.md`
126
+ - 手感清单:`../game-designer/references/checklists/game-feel.md`
127
+ - 关卡清单:`../game-designer/references/checklists/game-design-level-design.md`
@@ -0,0 +1,7 @@
1
+ interface:
2
+ display_name: "Phaser 2D Game"
3
+ short_description: "搭建结构清晰的二维浏览器游戏,处理场景、玩法、输入与界面集成"
4
+ default_prompt: "请使用 $phaser-2d-game 根据我的需求实现这个二维浏览器游戏,并保持场景、玩法系统和界面边界清晰。"
5
+
6
+ policy:
7
+ allow_implicit_invocation: true
@@ -0,0 +1,64 @@
1
+ # 引擎:性能
2
+
3
+ 卡顿、掉帧、生成尖峰时加载。
4
+
5
+ ## 优先做的几件事
6
+
7
+ 1. **对象池**:子弹、敌人、飘字、短效粒子载体 — 见 `engine-physics.md`
8
+ 2. **图集**:同屏尽量同一 atlas,减少贴图切换
9
+ 3. **少碰撞对**:只挂需要的 collider/overlap;关闭屏外 body
10
+ 4. **update 不分配**:不在每帧 `{}` / `new Vector2`;复用临时向量
11
+ 5. **时间用 delta**:`delta/1000`;AI/寻路可降频
12
+
13
+ ## 物理
14
+
15
+ ```ts
16
+ // 屏外可关 body
17
+ enemy.body.enable = cam.worldView.contains(enemy.x, enemy.y);
18
+
19
+ // 圆形碰撞往往比大矩形便宜
20
+ sprite.body.setCircle(16);
21
+ ```
22
+
23
+ 大量动态体时评估 `arcade.useTree` / `maxEntries`;>5000 再考虑关 tree(按实测)。
24
+
25
+ ## 渲染
26
+
27
+ - 背景用 `tileSprite` 或静态图,勿每帧重绘大图
28
+ - 慎用 ADD/MULTIPLY 等混合(易拆 batch)
29
+ - 粒子设 `maxParticles` / `frequency`
30
+ - 相机外精灵默认会 cull;`scrollFactor 0` 的固定 UI 若在 Canvas 上需有意为之(正式 HUD 仍用 DOM)
31
+
32
+ ## 内存与切场景
33
+
34
+ ```ts
35
+ shutdown() {
36
+ this.enemies?.clear(true, true);
37
+ // 按需 this.textures.remove('only-this-level');
38
+ }
39
+ ```
40
+
41
+ 切关卸载仅本关大图/tilemap;公共 atlas 可留。
42
+
43
+ ## 降频贵逻辑
44
+
45
+ ```ts
46
+ if (time - this.lastAiAt > 100) {
47
+ this.lastAiAt = time;
48
+ this.updateEnemyAi(); // System 侧亦可
49
+ }
50
+ ```
51
+
52
+ 移动/相机每帧;AI、寻路、清理扫描可 5–10Hz。
53
+
54
+ ## 快检表
55
+
56
+ | 症状 | 常因 | 处理 |
57
+ | --- | --- | --- |
58
+ | 越玩越慢 | 泄漏未 destroy | 查池与 shutdown |
59
+ | 周期性顿 | GC | 池化、减 update 分配 |
60
+ | 一直低帧 | 对象/绘制过多 | 裁剪、图集、减粒子 |
61
+ | 生成尖峰 | 当场 create | 预池 |
62
+ | 碰撞卡 | 检查对数爆炸 | 减对、简化 shape |
63
+
64
+ 开发可看 `this.game.loop.actualFps`;发布关掉物理 debug 与密集 FPS 文本(或仅 DOM 调试开关)。
@@ -0,0 +1,139 @@
1
+ # 引擎:Arcade 物理与对象池
2
+
3
+ 玩法数值仍归 System / `config.json`;本文件只管 Phaser 物理 API 与常见坑。
4
+
5
+ 改碰撞、平台、子弹池、击退、单向板时加载。
6
+
7
+ ## 世界配置(摘录)
8
+
9
+ ```ts
10
+ physics: {
11
+ default: 'arcade',
12
+ arcade: {
13
+ gravity: { x: 0, y: 300 }, // 可乘 config gravity_scale
14
+ debug: false, // 发布关闭
15
+ fps: 60,
16
+ overlapBias: 4,
17
+ tileBias: 16,
18
+ useTree: true, // 超大量动态体再评估 false
19
+ },
20
+ }
21
+ ```
22
+
23
+ ## Body 类型
24
+
25
+ - **Dynamic**:速度、重力、碰撞响应(玩家、敌人、子弹)。
26
+ - **Static**:不动平台;改尺度/位置后调用 `refreshBody()` / group `refresh()`。
27
+
28
+ ```ts
29
+ const player = this.physics.add.sprite(100, 100, 'player');
30
+ player.body.setCollideWorldBounds(true);
31
+ player.body.setSize(24, 40, true);
32
+ player.body.setOffset(4, 8);
33
+ player.body.setMaxVelocity(300, 400);
34
+ player.body.setDrag(100, 0);
35
+ ```
36
+
37
+ 圆体:`setCircle(radius, offsetX, offsetY)`。视觉 mesh 可大于 body;**不要**用整张大图当碰撞盒。
38
+
39
+ ## Collider vs Overlap
40
+
41
+ ```ts
42
+ // 物理分离
43
+ this.physics.add.collider(player, platforms);
44
+ this.physics.add.collider(player, enemies, onHit, processCb, this);
45
+
46
+ // 只检测重叠(拾取、触发器)
47
+ this.physics.add.overlap(player, coins, onCollect, undefined, this);
48
+ ```
49
+
50
+ `process` 回调返回 `false` 可跳过本次碰撞(无敌帧、单向板)。
51
+
52
+ ### 触地 / 贴墙
53
+
54
+ ```ts
55
+ if (player.body.blocked.down) { /* 着地 */ }
56
+ if (player.body.touching.down) { /* 踩在某 body 上 */ }
57
+ if (player.body.wasTouching.down && !player.body.touching.down) { /* 刚离地 */ }
58
+ ```
59
+
60
+ ### 世界边界
61
+
62
+ ```ts
63
+ this.physics.world.setBounds(0, 0, mapWidth, mapHeight);
64
+ this.cameras.main.setBounds(0, 0, mapWidth, mapHeight);
65
+ this.cameras.main.startFollow(player, true, 0.08, 0.08);
66
+ ```
67
+
68
+ ## 对象池(高频生成必用)
69
+
70
+ ```ts
71
+ this.bullets = this.physics.add.group({
72
+ defaultKey: 'bullet',
73
+ maxSize: 100,
74
+ });
75
+
76
+ function fire(x: number, y: number, vx: number, vy: number) {
77
+ const b = this.bullets.get(x, y);
78
+ if (!b) return;
79
+ b.setActive(true).setVisible(true);
80
+ b.body.enable = true;
81
+ b.body.reset(x, y);
82
+ b.setVelocity(vx, vy);
83
+ }
84
+
85
+ function kill(b: Phaser.Physics.Arcade.Sprite) {
86
+ b.setActive(false).setVisible(false);
87
+ b.body.enable = false;
88
+ b.body.stop();
89
+ }
90
+ ```
91
+
92
+ 禁止在热路径每帧 `new` / `destroy` 子弹与粒子载体。
93
+
94
+ ## 常用模式
95
+
96
+ ### 平台跳
97
+
98
+ ```ts
99
+ if (jumpPressed && player.body.blocked.down) {
100
+ player.setVelocityY(-330); // 高度用 config
101
+ }
102
+ ```
103
+
104
+ ### 加速度移动
105
+
106
+ ```ts
107
+ player.body.setMaxVelocity(maxSpeed);
108
+ player.body.setDrag(drag, 0);
109
+ player.body.setAccelerationX(left ? -accel : right ? accel : 0);
110
+ ```
111
+
112
+ ### 单向板
113
+
114
+ ```ts
115
+ function oneWay(
116
+ player: Phaser.Physics.Arcade.Sprite,
117
+ platform: Phaser.Physics.Arcade.Sprite,
118
+ ) {
119
+ return (
120
+ player.body.velocity.y > 0 &&
121
+ player.body.bottom <= platform.body.top + 10
122
+ );
123
+ }
124
+ this.physics.add.collider(player, platforms, undefined, oneWay, this);
125
+ ```
126
+
127
+ ### 击退
128
+
129
+ 改速度后由 System 记无敌;Scene 只播反馈。`setVelocity` 方向由相对位置决定。
130
+
131
+ ## 与 System 分层
132
+
133
+ - 碰撞回调里:**先**把事件交给 System(受伤、拾取),再改视图(闪白、禁用 sprite)。
134
+ - 不要在回调里散落胜负规则副本。
135
+ - `debug: true` 仅开发;发布与截图前关闭。
136
+
137
+ ## Matter?
138
+
139
+ 仅当 Arcade AABB 不够(复杂多边形、关节、布娃娃)。菜单/卡牌不要开物理。细节需求再查 Phaser Matter 文档;默认路径保持 Arcade。
@@ -0,0 +1,129 @@
1
+ # 引擎运行时(Phaser 3)
2
+
3
+ **System 持规则真相、Scene 只做视图、正式 HUD 用 DOM**。目录与 config 以 `file-structure.md` 为准。
4
+
5
+ 写/改场景生命周期、缩放、帧循环、场景切换时加载本文件。
6
+
7
+ ## 与本项目分层的对应
8
+
9
+ | Phaser 概念 | 本项目落点 |
10
+ | --- | --- |
11
+ | Boot / preload | Boot Scene:读 `config.json`、按 manifest 预加载 |
12
+ | Gameplay Scene | 读 System 状态 → 精灵/相机/特效;输入意图回传 System |
13
+ | 正式 HUD / 菜单 | React DOM 覆盖层(非 Canvas 密文 UI) |
14
+ | 可选并行 Scene | 仅调试 / 极轻量世界内指示;不替代正式 HUD |
15
+ | 可调数值 | `public/config.json`,禁止魔法数散落 |
16
+
17
+ ## 场景结构(推荐)
18
+
19
+ ```text
20
+ scenes/
21
+ ├── BootScene.ts # 配置与资产预加载、进度
22
+ ├── MenuScene.ts # 壳层(可很薄;复杂菜单仍可走 DOM)
23
+ ├── GameScene.ts # 主循环视图
24
+ └──(可选)DebugScene # 并行调试,勿塞正式 HUD
25
+ ```
26
+
27
+ 切换:
28
+
29
+ ```ts
30
+ this.scene.start('GameScene', { level: 1 }); // 停当前,启新
31
+ this.scene.launch('DebugScene'); // 并行
32
+ this.scene.pause('GameScene');
33
+ this.scene.stop('DebugScene');
34
+ ```
35
+
36
+ 场景间状态用 **init 数据 / registry / System 门面**,禁止挂可变全局到 `window`。
37
+
38
+ ## 场景生命周期
39
+
40
+ ```ts
41
+ class GameScene extends Phaser.Scene {
42
+ init(data: unknown) {} // 接收上一场景数据
43
+ preload() {} // 仅加载;正式项目优先 Boot 集中加载
44
+ create() {} // 对象、物理、输入绑定;接上 System
45
+ update(time: number, delta: number) {} // delta 单位 ms
46
+ }
47
+ ```
48
+
49
+ 规则:
50
+
51
+ - 资产在 `preload` / Boot,不在 `create` 里才开始 `load` 却立刻引用。
52
+ - `update` **映射** System 结果并采样输入;核心规则在 System,避免「巨型 Scene 上帝类」。
53
+ - 动画/精灵状态从 System 派生,不用随机 sprite flag 当真相。
54
+
55
+ ## 帧率无关运动
56
+
57
+ Phaser `update` 的 `delta` 是**毫秒**:
58
+
59
+ ```ts
60
+ // 正确
61
+ this.viewX += speedPxPerSec * (delta / 1000);
62
+
63
+ // 错误:跟帧率绑死
64
+ this.viewX += speedPxPerSec;
65
+ ```
66
+
67
+ 物理体优先用 Arcade `setVelocity` / 加速度;手写位移必须乘 `delta/1000`。
68
+
69
+ ## 视口缩放(Scale Manager 唯一正道)
70
+
71
+ **必须用 Phaser Scale Manager**;禁止用 CSS/`transform`/手写 `resize` 去缩放 canvas(会破坏坐标、输入与物理)。
72
+
73
+ ```ts
74
+ const config: Phaser.Types.Core.GameConfig = {
75
+ type: Phaser.AUTO,
76
+ width: 720,
77
+ height: 1280,
78
+ scale: {
79
+ mode: Phaser.Scale.FIT,
80
+ autoCenter: Phaser.Scale.CENTER_BOTH,
81
+ parent: 'game-container',
82
+ width: 720,
83
+ height: 1280,
84
+ },
85
+ // physics / scene ...
86
+ };
87
+ ```
88
+
89
+ | 模式 | 何时用 |
90
+ | --- | --- |
91
+ | `FIT` | 默认:保比例,可能有边距 |
92
+ | `ENVELOP` | 铺满裁切(需接受裁边) |
93
+ | `RESIZE` | 布局随视口变(要自己重排世界/UI) |
94
+ | `NONE` | 固定桌面尺寸 |
95
+
96
+ 响应:
97
+
98
+ ```ts
99
+ this.scale.on('resize', (gameSize: Phaser.Structs.Size) => {
100
+ // 按需调相机 / 世界边界;正式 HUD 由 DOM 自己响应式
101
+ });
102
+ ```
103
+
104
+ ### 反模式(禁止)
105
+
106
+ ```ts
107
+ // 禁止
108
+ canvas.style.width = '75%';
109
+ canvas.style.transform = 'scale(0.75)';
110
+ window.addEventListener('resize', () => { /* 手改 container 像素去「模拟」缩放 */ });
111
+ ```
112
+
113
+ ## 物理系统选型(早定)
114
+
115
+ 默认 **Arcade**;Matter 仅刚体/关节场景;菜单/卡牌可不启物理。选型、碰撞与对象池见 `engine-physics.md`。
116
+
117
+ ## 引擎反模式
118
+
119
+ | 反模式 | 问题 | 做法 |
120
+ | --- | --- | --- |
121
+ | 手写 CSS 缩放 Canvas | 输入/物理错位 | Scale Manager |
122
+ | 规则全写在 `update` | 难测、难复用 | System + Scene 映射 |
123
+ | `window` 全局状态 | 切场景损坏 | registry / System |
124
+ | 在 `create` 才 load 即用 | 资源未就绪 | Boot / preload |
125
+ | 按帧计数当时间 | 掉帧变速 | `delta/1000` |
126
+ | 简单碰撞上 Matter | 过重 | Arcade |
127
+ | 正式 HUD 塞进 Scene 密文 | 难适配竖屏/安全区 | DOM 覆盖层 |
128
+ | 魔法数 | 难调平衡 | `config.json` |
129
+ | 子弹/敌人狂 create/destroy | GC 卡顿 | 对象池(见 physics / performance) |
@@ -0,0 +1,99 @@
1
+ # 引擎:Spritesheet 与图集
2
+
3
+ **加载任何 spritesheet 之前先读本文件。** 帧尺寸差几像素会静默错位,后面全坏。
4
+
5
+ 正式 HUD 默认走 DOM(`game-ui`);九宫格 Canvas 面板仅在确需世界内/像素风面板时使用。
6
+
7
+ ## 强制:先量再写 loader
8
+
9
+ 1. 打开图片,记下总宽高
10
+ 2. 数清行列
11
+ 3. 量一格真实宽高(像素尺)
12
+ 4. 看格间是否有 gap → `spacing`
13
+ 5. 看整图外圈是否有 padding → `margin`
14
+ 6. 用公式验算必须整除
15
+
16
+ ```text
17
+ imageWidth = frameWidth × cols + spacing × (cols - 1) + margin × 2
18
+ imageHeight = frameHeight × rows + spacing × (rows - 1) + margin × 2
19
+ ```
20
+
21
+ ### 角色帧优先试正方形
22
+
23
+ 算出 `frameWidth` 后,**先试 `frameHeight = frameWidth`**,再看高度能否整除。不要一上来就按「行列数相同」瞎除。
24
+
25
+ ### 不同动画可能不同帧尺寸
26
+
27
+ 同一角色的 idle / run / attack 常常 **各自一张 sheet、各自 frame 尺寸**(跑姿更宽、挥砍更宽)。**每张独立测量**,禁止把 idle 的 fw/fh 复制到 attack。
28
+
29
+ ## Loader 示例
30
+
31
+ ```ts
32
+ this.load.spritesheet('player-idle', urlFromManifest, {
33
+ frameWidth: 64,
34
+ frameHeight: 64,
35
+ });
36
+
37
+ this.load.spritesheet('ui-wood', url, {
38
+ frameWidth: 144,
39
+ frameHeight: 144,
40
+ spacing: 8,
41
+ });
42
+
43
+ this.load.spritesheet('icons', url, {
44
+ frameWidth: 32,
45
+ frameHeight: 32,
46
+ margin: 4,
47
+ spacing: 2,
48
+ });
49
+ ```
50
+
51
+ 资产 URL 走 manifest / `config.json`,不在业务里硬编码散落路径。
52
+
53
+ ## 红旗
54
+
55
+ - 宽或高无法被帧数整除 / 算出小数
56
+ - 目测有缝但没写 `spacing`(第一帧对、后面全歪)
57
+ - 角色动画硬用不方形帧却未验证
58
+ - 假设行列数相同
59
+
60
+ ## 调试:先摊开看帧
61
+
62
+ ```ts
63
+ for (let i = 0; i < frameCount; i++) {
64
+ const col = i % 3;
65
+ const row = Math.floor(i / 3);
66
+ this.add.image(100 + col * 120, 100 + row * 120, key, i);
67
+ this.add.text(100 + col * 120, 150 + row * 120, String(i)).setOrigin(0.5);
68
+ }
69
+ ```
70
+
71
+ 单帧就错 → 先修 loader,再进玩法。多动画角色可用临时 AnimTest Scene / `?debug=anims` 左右键切换验证。
72
+
73
+ ## Texture Atlas
74
+
75
+ 多精灵合并图集,减 draw call 与请求:
76
+
77
+ ```ts
78
+ this.load.atlas('sprites', atlasPngUrl, atlasJsonUrl);
79
+ this.add.sprite(x, y, 'sprites', 'player-idle-1');
80
+ this.anims.create({
81
+ key: 'walk',
82
+ frames: this.anims.generateFrameNames('sprites', {
83
+ prefix: 'player-walk-',
84
+ start: 1,
85
+ end: 8,
86
+ zeroPad: 2,
87
+ }),
88
+ frameRate: 10,
89
+ repeat: -1,
90
+ });
91
+ ```
92
+
93
+ ## 九宫 / 三截条(仅 Canvas UI 需要时)
94
+
95
+ - 3×3:角不拉伸,边单轴拉,中心双轴拉;透明边需底色与 overlap 防缝。
96
+ - 丝带/横幅常是 **左帽 + 中段 + 右帽**,不要整图拉伸。
97
+ - 参数按资产配置,不写死一套。
98
+
99
+ 世界内装饰可用;**主菜单/设置/复杂 HUD 仍优先 DOM**。
@@ -0,0 +1,80 @@
1
+ # 引擎:Tilemap(Tiled → Phaser)
2
+
3
+ 横版/俯视用地图、碰撞层、物件层刷怪时加载。
4
+
5
+ ## Tiled 层建议(自上而下)
6
+
7
+ ```text
8
+ Foreground # 盖住玩家的装饰
9
+ Objects # 出生点、敌人、拾取、触发(Object Layer)
10
+ Ground # 主碰撞 Tile Layer
11
+ Background # 无碰撞装饰 / 视差
12
+ ```
13
+
14
+ 导出 **JSON**(推荐)。Tileset 注意 `margin` / `spacing`;防渗色可用 extruded tileset。
15
+
16
+ ## 加载与创建
17
+
18
+ ```ts
19
+ // preload / Boot
20
+ this.load.tilemapTiledJSON('level1', mapUrl);
21
+ this.load.image('tiles', tilesetUrl);
22
+
23
+ // create
24
+ const map = this.make.tilemap({ key: 'level1' });
25
+ const tileset = map.addTilesetImage('terrain', 'tiles'); // 名称对齐 Tiled
26
+ const ground = map.createLayer('Ground', tileset, 0, 0);
27
+ const fg = map.createLayer('Foreground', tileset, 0, 0);
28
+
29
+ ground?.setCollisionByProperty({ collides: true });
30
+ // 或 setCollisionByExclusion([-1]) / 按 index
31
+
32
+ this.physics.add.collider(player, ground!);
33
+ this.cameras.main.setBounds(0, 0, map.widthInPixels, map.heightInPixels);
34
+ this.physics.world.setBounds(0, 0, map.widthInPixels, map.heightInPixels);
35
+ ```
36
+
37
+ 多 tileset:每个 `addTilesetImage`,`createLayer` 可传数组。
38
+
39
+ ## GID 要点
40
+
41
+ - `0` = 空
42
+ - 多 tileset 靠 `firstgid`;本地 id = `gid - firstgid`
43
+ - 翻转存在高位 flag;手工解析时先清 `0xF0000000`
44
+
45
+ 一般优先用 Phaser API,少手撕 GID。
46
+
47
+ ## 物件层刷实体
48
+
49
+ ```ts
50
+ const objs = map.getObjectLayer('Objects');
51
+ objs?.objects.forEach((obj) => {
52
+ if (obj.type === 'spawn' || obj.name === 'player') {
53
+ // 交给 System 设逻辑位,Scene 只生成视图
54
+ }
55
+ if (obj.type === 'coin') {
56
+ // overlap 组 / 池
57
+ }
58
+ });
59
+ ```
60
+
61
+ Tiled 自定义属性映射到 config / content 数据,避免在 Scene 写死关卡数值。
62
+
63
+ ## 视差
64
+
65
+ 层在 Tiled 设 `parallaxx` / `parallaxy`,或 Phaser 侧 `setScrollFactor`。远景 factor &lt; 1。
66
+
67
+ ## 常见坑
68
+
69
+ | 现象 | 处理 |
70
+ | --- | --- |
71
+ | 缝隙渗色 | tileset extrude;检查 spacing/margin |
72
+ | 碰撞对不齐 | 确认 layer 名、tileset 名、缩放后 `setCollision*` |
73
+ | 物件坐标偏 | 注意 Tiled 原点与 Phaser origin;tile object vs point |
74
+ | CSV 图 | 必须在 `make.tilemap` 声明 tileWidth/Height;优先 JSON |
75
+
76
+ ## 与本规范
77
+
78
+ - 地图 JSON / 图块 URL 进 manifest 或 config,不写死多处路径。
79
+ - 碰撞结果 → System 事件;Scene 不持关卡进度真相。
80
+ - 大地图注意相机 bounds 与世界 bounds 一致。