@playcraft/cli 0.0.52 → 0.0.55
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.
- package/dist/commands/create.js +164 -98
- package/dist/index.js +4 -1
- package/dist/scaffold/templates.js +35 -0
- package/package.json +3 -3
- package/project-templates/playable-template-phaser/.playcraftignore +10 -0
- package/project-templates/playable-template-phaser/CLAUDE.md +178 -0
- package/project-templates/playable-template-phaser/PLAYCRAFT-MIGRATION.md +328 -0
- package/project-templates/playable-template-phaser/README.md +381 -0
- package/project-templates/playable-template-phaser/assets/brain.png +0 -0
- package/project-templates/playable-template-phaser/assets/button.png +0 -0
- package/project-templates/playable-template-phaser/assets/interact.png +0 -0
- package/project-templates/playable-template-phaser/assets/logo.webp +0 -0
- package/project-templates/playable-template-phaser/assets/warn_brain.png +0 -0
- package/project-templates/playable-template-phaser/builds.config.js +12 -0
- package/project-templates/playable-template-phaser/globals.d.ts +2 -0
- package/project-templates/playable-template-phaser/index.html +12 -0
- package/project-templates/playable-template-phaser/package.json +45 -0
- package/project-templates/playable-template-phaser/scripts/base64-to-mp3.js +340 -0
- package/project-templates/playable-template-phaser/scripts/convert-to-webp.js +370 -0
- package/project-templates/playable-template-phaser/src/Game.ts +154 -0
- package/project-templates/playable-template-phaser/src/config/LoadingConfig.ts +40 -0
- package/project-templates/playable-template-phaser/src/config/ThemeConfig.ts +81 -0
- package/project-templates/playable-template-phaser/src/index.css +18 -0
- package/project-templates/playable-template-phaser/src/index.html +9 -0
- package/project-templates/playable-template-phaser/src/index.ts +30 -0
- package/project-templates/playable-template-phaser/src/json5.d.ts +4 -0
- package/project-templates/playable-template-phaser/src/managers/AudioManager.ts +559 -0
- package/project-templates/playable-template-phaser/src/scenes/MainScene.ts +301 -0
- package/project-templates/playable-template-phaser/src/scenes/PreloadScene.ts +256 -0
- package/project-templates/playable-template-phaser/src/theme/README.md +194 -0
- package/project-templates/playable-template-phaser/src/theme/blue-theme/assets/.gitkeep +24 -0
- package/project-templates/playable-template-phaser/src/theme/blue-theme/index.ts +27 -0
- package/project-templates/playable-template-phaser/src/theme/blue-theme/theme.data.json5 +19 -0
- package/project-templates/playable-template-phaser/src/theme/green-theme/assets/.gitkeep +3 -0
- package/project-templates/playable-template-phaser/src/theme/green-theme/index.ts +20 -0
- package/project-templates/playable-template-phaser/src/theme/green-theme/theme.data.json5 +19 -0
- package/project-templates/playable-template-phaser/src/theme/index.ts +1 -0
- package/project-templates/playable-template-phaser/src/theme/red-theme/assets/.gitkeep +3 -0
- package/project-templates/playable-template-phaser/src/theme/red-theme/index.ts +20 -0
- package/project-templates/playable-template-phaser/src/theme/red-theme/theme.data.json5 +19 -0
- package/project-templates/playable-template-phaser/src/theme/theme.metadata.md +60 -0
- package/project-templates/playable-template-phaser/src/theme/theme.schema.json5 +149 -0
- package/project-templates/playable-template-phaser/src/ui/BrainAgeUI.ts +681 -0
- package/project-templates/playable-template-phaser/src/ui/CountdownUI.ts +565 -0
- package/project-templates/playable-template-phaser/src/ui/PlayButton.ts +51 -0
- package/project-templates/playable-template-phaser/src/ui/ScoreUI.ts +207 -0
- package/project-templates/playable-template-phaser/src/ui/SuccessUI.ts +43 -0
- package/project-templates/playable-template-phaser/src/ui/index.ts +15 -0
- package/project-templates/playable-template-phaser/tsconfig.json +26 -0
- package/project-templates/playable-template-phaser/vite.config.ts +64 -0
- package/project-templates/playable-template-phaser//346/226/260/346/211/213/345/274/200/345/217/221/346/214/207/345/215/227.md +209 -0
- package/project-templates/playable-template-three/README.md +795 -0
- package/project-templates/playable-template-three/assets/Stork.glb +0 -0
- package/project-templates/playable-template-three/assets/button.png +0 -0
- package/project-templates/playable-template-three/assets/logo.webp +0 -0
- package/project-templates/playable-template-three/build.json +7 -0
- package/project-templates/playable-template-three/builds.config.example.js +151 -0
- package/project-templates/playable-template-three/builds.config.js +158 -0
- package/project-templates/playable-template-three/package.json +36 -0
- package/project-templates/playable-template-three/scripts/convert-to-webp.js +370 -0
- package/project-templates/playable-template-three/scripts/theme-builds.js +514 -0
- package/project-templates/playable-template-three/src/Game.ts +215 -0
- package/project-templates/playable-template-three/src/config/LoadingConfig.ts +27 -0
- package/project-templates/playable-template-three/src/config/ThemeConfig.ts +36 -0
- package/project-templates/playable-template-three/src/global.d.ts +108 -0
- package/project-templates/playable-template-three/src/index.css +18 -0
- package/project-templates/playable-template-three/src/index.html +9 -0
- package/project-templates/playable-template-three/src/index.ts +20 -0
- package/project-templates/playable-template-three/src/managers/AudioManager.ts +538 -0
- package/project-templates/playable-template-three/src/scenes/PreloadScene.ts +305 -0
- package/project-templates/playable-template-three/src/theme/README.md +225 -0
- package/project-templates/playable-template-three/src/theme/blue-theme/assets/.gitkeep +28 -0
- package/project-templates/playable-template-three/src/theme/blue-theme/index.ts +45 -0
- package/project-templates/playable-template-three/src/theme/current.ts +12 -0
- package/project-templates/playable-template-three/src/theme/green-theme/assets/.gitkeep +3 -0
- package/project-templates/playable-template-three/src/theme/green-theme/index.ts +34 -0
- package/project-templates/playable-template-three/src/theme/red-theme/assets/.gitkeep +3 -0
- package/project-templates/playable-template-three/src/theme/red-theme/index.ts +34 -0
- package/project-templates/playable-template-three/tsconfig.json +24 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 积分UI配置接口
|
|
3
|
+
*/
|
|
4
|
+
export interface ScoreUIConfig {
|
|
5
|
+
fontSize?: number;
|
|
6
|
+
fontFamily?: string;
|
|
7
|
+
color?: string;
|
|
8
|
+
bgColor?: string;
|
|
9
|
+
paddingX?: number;
|
|
10
|
+
paddingY?: number;
|
|
11
|
+
prefix?: string;
|
|
12
|
+
scale?: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 完整配置类型(所有属性都必填)
|
|
17
|
+
*/
|
|
18
|
+
type FullScoreUIConfig = Required<ScoreUIConfig>;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 默认配置
|
|
22
|
+
*/
|
|
23
|
+
const DEFAULT_CONFIG: FullScoreUIConfig = {
|
|
24
|
+
fontSize: 32,
|
|
25
|
+
fontFamily: 'Arial, sans-serif',
|
|
26
|
+
color: '#ffff00',
|
|
27
|
+
bgColor: '#00000066',
|
|
28
|
+
paddingX: 16,
|
|
29
|
+
paddingY: 8,
|
|
30
|
+
prefix: 'Score: ',
|
|
31
|
+
scale: 1,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/** 推荐的默认每次匹配得分 */
|
|
35
|
+
export const DEFAULT_POINTS_PER_MATCH = 5;
|
|
36
|
+
|
|
37
|
+
/** 推荐的默认 X 坐标 */
|
|
38
|
+
export const DEFAULT_X = 40;
|
|
39
|
+
|
|
40
|
+
/** 推荐的默认 Y 坐标 */
|
|
41
|
+
export const DEFAULT_Y = 15;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 积分UI组件(纯DOM+CSS实现)
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export class ScoreUI {
|
|
48
|
+
private element!: HTMLDivElement;
|
|
49
|
+
private config: FullScoreUIConfig;
|
|
50
|
+
private score: number = 0;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @param x X 坐标(像素)
|
|
54
|
+
* @param y Y 坐标(像素)
|
|
55
|
+
* @param initialScore 初始分数
|
|
56
|
+
* @param config UI 配置
|
|
57
|
+
*/
|
|
58
|
+
constructor(x: number = DEFAULT_X, y: number = DEFAULT_Y, initialScore: number = 0, config?: ScoreUIConfig) {
|
|
59
|
+
this.score = initialScore;
|
|
60
|
+
this.config = this.mergeConfig(config);
|
|
61
|
+
this.create(x, y);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* 合并配置
|
|
66
|
+
*/
|
|
67
|
+
private mergeConfig(userConfig?: ScoreUIConfig): FullScoreUIConfig {
|
|
68
|
+
if (!userConfig) {
|
|
69
|
+
return { ...DEFAULT_CONFIG };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
fontSize: userConfig.fontSize ?? DEFAULT_CONFIG.fontSize,
|
|
74
|
+
fontFamily: userConfig.fontFamily ?? DEFAULT_CONFIG.fontFamily,
|
|
75
|
+
color: userConfig.color ?? DEFAULT_CONFIG.color,
|
|
76
|
+
bgColor: userConfig.bgColor ?? DEFAULT_CONFIG.bgColor,
|
|
77
|
+
paddingX: userConfig.paddingX ?? DEFAULT_CONFIG.paddingX,
|
|
78
|
+
paddingY: userConfig.paddingY ?? DEFAULT_CONFIG.paddingY,
|
|
79
|
+
prefix: userConfig.prefix ?? DEFAULT_CONFIG.prefix,
|
|
80
|
+
scale: userConfig.scale ?? DEFAULT_CONFIG.scale,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private create(x: number, y: number): void {
|
|
85
|
+
const { fontSize, fontFamily, color, bgColor, paddingX, paddingY, prefix, scale: s } = this.config;
|
|
86
|
+
const scaledFontSize = Math.round(fontSize * s);
|
|
87
|
+
const scaledPaddingX = Math.round(paddingX * s);
|
|
88
|
+
const scaledPaddingY = Math.round(paddingY * s);
|
|
89
|
+
|
|
90
|
+
// 创建 DOM 元素
|
|
91
|
+
this.element = document.createElement('div');
|
|
92
|
+
this.element.className = 'score-ui';
|
|
93
|
+
this.element.textContent = `${prefix}${this.score}`;
|
|
94
|
+
|
|
95
|
+
// 应用样式
|
|
96
|
+
Object.assign(this.element.style, {
|
|
97
|
+
position: 'fixed',
|
|
98
|
+
left: `${x}px`,
|
|
99
|
+
top: `${y}px`,
|
|
100
|
+
fontSize: `${scaledFontSize}px`,
|
|
101
|
+
fontFamily: fontFamily,
|
|
102
|
+
color: color,
|
|
103
|
+
fontWeight: 'bold',
|
|
104
|
+
backgroundColor: bgColor,
|
|
105
|
+
padding: `${scaledPaddingY}px ${scaledPaddingX}px`,
|
|
106
|
+
borderRadius: '4px',
|
|
107
|
+
zIndex: '100',
|
|
108
|
+
pointerEvents: 'none',
|
|
109
|
+
userSelect: 'none',
|
|
110
|
+
whiteSpace: 'nowrap',
|
|
111
|
+
// 响应式:根据视口宽度自动缩放
|
|
112
|
+
transform: 'scale(var(--score-ui-scale, 1))',
|
|
113
|
+
transformOrigin: 'top left',
|
|
114
|
+
} as CSSStyleDeclaration);
|
|
115
|
+
|
|
116
|
+
// 添加到 body
|
|
117
|
+
document.body.appendChild(this.element);
|
|
118
|
+
|
|
119
|
+
// 响应式处理
|
|
120
|
+
this.setupResponsive();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* 设置响应式缩放
|
|
125
|
+
* 移动端下自动放大,PC端保持原尺寸
|
|
126
|
+
*/
|
|
127
|
+
private setupResponsive(): void {
|
|
128
|
+
const updateScale = () => {
|
|
129
|
+
const currentWidth = window.innerWidth;
|
|
130
|
+
const currentHeight = window.innerHeight;
|
|
131
|
+
|
|
132
|
+
// 判断是否为移动设备(基于屏幕尺寸)
|
|
133
|
+
const isMobile = currentWidth < 768 || (currentWidth < 1024 && currentHeight < 768);
|
|
134
|
+
|
|
135
|
+
let scale: number;
|
|
136
|
+
if (isMobile) {
|
|
137
|
+
// 移动端:基于 375px 基准,最小 0.8 倍,最大 1.2 倍
|
|
138
|
+
const baseWidth = 375;
|
|
139
|
+
scale = Math.max(0.4, Math.min(currentWidth / baseWidth, 0.5));
|
|
140
|
+
} else {
|
|
141
|
+
// PC端:基于 1920px 基准,最小 0.6 倍,最大 1 倍
|
|
142
|
+
const baseWidth = 1920;
|
|
143
|
+
scale = Math.max(0.6, Math.min(currentWidth / baseWidth, 1));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
document.documentElement.style.setProperty('--score-ui-scale', scale.toString());
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
updateScale();
|
|
150
|
+
window.addEventListener('resize', updateScale);
|
|
151
|
+
|
|
152
|
+
// 保存清理函数
|
|
153
|
+
(this.element as any)._cleanupResize = () => {
|
|
154
|
+
window.removeEventListener('resize', updateScale);
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* 增加分数(默认使用 DEFAULT_POINTS_PER_MATCH)
|
|
160
|
+
*/
|
|
161
|
+
public add(points: number = DEFAULT_POINTS_PER_MATCH): void {
|
|
162
|
+
this.score += points;
|
|
163
|
+
this.refresh();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* 获取当前分数
|
|
168
|
+
*/
|
|
169
|
+
public getScore(): number {
|
|
170
|
+
return this.score;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* 直接设置分数
|
|
175
|
+
*/
|
|
176
|
+
public update(score: number): void {
|
|
177
|
+
this.score = score;
|
|
178
|
+
this.refresh();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
private refresh(): void {
|
|
182
|
+
if (this.element) {
|
|
183
|
+
this.element.textContent = `${this.config.prefix}${this.score}`;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* 获取配置(用于调试或外部读取)
|
|
189
|
+
*/
|
|
190
|
+
public getConfig(): FullScoreUIConfig {
|
|
191
|
+
return { ...this.config };
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* 销毁组件
|
|
196
|
+
*/
|
|
197
|
+
public destroy(): void {
|
|
198
|
+
if (this.element) {
|
|
199
|
+
// 清理响应式监听器
|
|
200
|
+
const cleanup = (this.element as any)._cleanupResize;
|
|
201
|
+
if (cleanup) cleanup();
|
|
202
|
+
|
|
203
|
+
// 从 DOM 移除
|
|
204
|
+
this.element.remove();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as Phaser from 'phaser';
|
|
2
|
+
import { PlayButton } from './PlayButton';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 通用成功 UI 组件
|
|
6
|
+
* 显示半透明遮罩 + "You Win!" + PlayButton
|
|
7
|
+
*
|
|
8
|
+
* 纹理依赖(间接通过 PlayButton):
|
|
9
|
+
* - interact 合图中的 playBtn 帧
|
|
10
|
+
*/
|
|
11
|
+
export class SuccessUI {
|
|
12
|
+
private scene: Phaser.Scene;
|
|
13
|
+
|
|
14
|
+
constructor(scene: Phaser.Scene) {
|
|
15
|
+
this.scene = scene;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 显示成功浮层
|
|
20
|
+
* @param depth 渲染层级(默认 300,遮罩层)
|
|
21
|
+
*/
|
|
22
|
+
public show(depth: number = 300): void {
|
|
23
|
+
const { width, height } = this.scene.scale;
|
|
24
|
+
|
|
25
|
+
// 半透明遮罩
|
|
26
|
+
const overlay = this.scene.add.graphics().setDepth(depth);
|
|
27
|
+
overlay.fillStyle(0x000000, 0.6);
|
|
28
|
+
overlay.fillRect(0, 0, width, height);
|
|
29
|
+
|
|
30
|
+
const contentDepth = depth + 1;
|
|
31
|
+
|
|
32
|
+
// "You Win!" 文字
|
|
33
|
+
this.scene.add.text(width / 2, height / 2 - 40, 'You Win!', {
|
|
34
|
+
fontFamily: 'Arial, sans-serif',
|
|
35
|
+
fontSize: '56px',
|
|
36
|
+
color: '#ffffff',
|
|
37
|
+
fontStyle: 'bold'
|
|
38
|
+
}).setOrigin(0.5).setDepth(contentDepth);
|
|
39
|
+
|
|
40
|
+
// Play 按钮
|
|
41
|
+
new PlayButton(this.scene).show(width / 2, height / 2 + 50, 0.45, contentDepth);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI 组件统一导出
|
|
3
|
+
*/
|
|
4
|
+
export { BrainAgeUI } from './BrainAgeUI';
|
|
5
|
+
export type { BrainAgeUIConfig, BrainAgeGameConfig } from './BrainAgeUI';
|
|
6
|
+
|
|
7
|
+
export { CountdownUI, DEFAULT_COUNTDOWN, DEFAULT_WARN_TIME } from './CountdownUI';
|
|
8
|
+
export type { CountdownUIConfig } from './CountdownUI';
|
|
9
|
+
|
|
10
|
+
export { ScoreUI, DEFAULT_POINTS_PER_MATCH, DEFAULT_X, DEFAULT_Y } from './ScoreUI';
|
|
11
|
+
export type { ScoreUIConfig } from './ScoreUI';
|
|
12
|
+
|
|
13
|
+
export { SuccessUI } from './SuccessUI';
|
|
14
|
+
|
|
15
|
+
export { PlayButton } from './PlayButton';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"outDir": "./dist",
|
|
4
|
+
"target": "es5",
|
|
5
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
6
|
+
"allowJs": true,
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"allowSyntheticDefaultImports": true,
|
|
10
|
+
"strict": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"noFallthroughCasesInSwitch": true,
|
|
13
|
+
"strictPropertyInitialization": false,
|
|
14
|
+
"module": "esnext",
|
|
15
|
+
"moduleResolution": "bundler",
|
|
16
|
+
"sourceMap": true,
|
|
17
|
+
"resolveJsonModule": true,
|
|
18
|
+
"isolatedModules": true,
|
|
19
|
+
"paths": {
|
|
20
|
+
"assets/*": ["./assets/*"],
|
|
21
|
+
"@/*": ["./src/*"],
|
|
22
|
+
"src/*": ["./src/*"]
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"exclude": ["node_modules", "tests"]
|
|
26
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { defineConfig } from "vite";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import JSON5 from "json5";
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
|
|
6
|
+
// 自定义 Vite 插件:支持 .json5 文件导入
|
|
7
|
+
function json5Plugin() {
|
|
8
|
+
return {
|
|
9
|
+
name: "vite-plugin-json5",
|
|
10
|
+
transform(code: string, id: string) {
|
|
11
|
+
if (id.endsWith(".json5")) {
|
|
12
|
+
const raw = fs.readFileSync(id, "utf-8");
|
|
13
|
+
const parsed = JSON5.parse(raw);
|
|
14
|
+
return {
|
|
15
|
+
code: `export default ${JSON.stringify(parsed)};`,
|
|
16
|
+
map: null,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default defineConfig({
|
|
24
|
+
// 项目根目录(index.html 所在位置)
|
|
25
|
+
root: ".",
|
|
26
|
+
|
|
27
|
+
// 路径别名,匹配 tsconfig 中的 paths 配置
|
|
28
|
+
resolve: {
|
|
29
|
+
alias: {
|
|
30
|
+
assets: path.resolve(__dirname, "assets"),
|
|
31
|
+
"@": path.resolve(__dirname, "src"),
|
|
32
|
+
src: path.resolve(__dirname, "src"),
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
plugins: [json5Plugin()],
|
|
37
|
+
|
|
38
|
+
// 全局常量定义,匹配 @playcraft/devkit 的 defines
|
|
39
|
+
define: {
|
|
40
|
+
__DEV__: JSON.stringify(true),
|
|
41
|
+
AD_NETWORK: JSON.stringify("preview"),
|
|
42
|
+
AD_PROTOCOL: JSON.stringify("none"),
|
|
43
|
+
GOOGLE_PLAY_URL: JSON.stringify("https://play.google.com/store/apps/details?id=com.nextinitiatives.minigames.mpp"),
|
|
44
|
+
APP_STORE_URL: JSON.stringify("https://apps.apple.com/app/id6758609907"),
|
|
45
|
+
APP: JSON.stringify("playable-template-phaser"),
|
|
46
|
+
NAME: JSON.stringify("Phaser Template"),
|
|
47
|
+
VERSION: JSON.stringify("1.0.0"),
|
|
48
|
+
LANGUAGE: JSON.stringify("auto"),
|
|
49
|
+
ORIENTATION: JSON.stringify("both"),
|
|
50
|
+
BUILD_HASH: JSON.stringify("dev"),
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
// 开发服务器配置
|
|
54
|
+
server: {
|
|
55
|
+
port: 3000,
|
|
56
|
+
open: true,
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
// 构建配置
|
|
60
|
+
build: {
|
|
61
|
+
outDir: "dist",
|
|
62
|
+
sourcemap: true,
|
|
63
|
+
},
|
|
64
|
+
});
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# 新手开发指南
|
|
2
|
+
|
|
3
|
+
欢迎使用 Phaser 可玩广告模板!本指南将帮助你快速上手。
|
|
4
|
+
|
|
5
|
+
## 第一步:安装依赖
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 第二步:启动开发服务器
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# 推荐:使用 Vite(速度快,支持 HMR)
|
|
15
|
+
npm run dev
|
|
16
|
+
|
|
17
|
+
# 或使用 playable-scripts(与构建环境一致)
|
|
18
|
+
npm run dev:wp
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
浏览器会自动打开 `http://localhost:3000`
|
|
22
|
+
|
|
23
|
+
## 第三步:修改主题配置
|
|
24
|
+
|
|
25
|
+
### 方式一:修改配置值
|
|
26
|
+
|
|
27
|
+
编辑 `src/theme/blue-theme/theme.data.json5`:
|
|
28
|
+
|
|
29
|
+
```json5
|
|
30
|
+
{
|
|
31
|
+
name: '我的主题',
|
|
32
|
+
id: 'my-theme',
|
|
33
|
+
|
|
34
|
+
visual: {
|
|
35
|
+
backgroundColor: 0x123456, // 修改背景色
|
|
36
|
+
primaryColor: 0x654321,
|
|
37
|
+
// ...
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
gameplay: {
|
|
41
|
+
difficulty: 8, // 修改难度
|
|
42
|
+
enableHints: false,
|
|
43
|
+
},
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 方式二:切换主题
|
|
48
|
+
|
|
49
|
+
编辑 `src/theme/index.ts`:
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
export { default } from './blue-theme'; // 蓝色主题
|
|
53
|
+
// export { default } from './green-theme'; // 绿色主题
|
|
54
|
+
// export { default } from './red-theme'; // 红色主题
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## 第四步:添加资源
|
|
58
|
+
|
|
59
|
+
### 添加公共资源
|
|
60
|
+
|
|
61
|
+
1. 将资源放到 `assets/` 目录
|
|
62
|
+
2. 在代码中 import:
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import myImage from 'assets/my-image.png';
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 添加主题特定资源
|
|
69
|
+
|
|
70
|
+
1. 将资源放到 `src/theme/blue-theme/assets/`
|
|
71
|
+
2. 在主题的 `index.ts` 中 import 并映射:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import myImage from './assets/my-image.png';
|
|
75
|
+
|
|
76
|
+
const assetRecordByPath: Record<string, string> = {
|
|
77
|
+
'./assets/my-image.png': myImage,
|
|
78
|
+
};
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
3. 在 `theme.schema.json5` 中定义:
|
|
82
|
+
|
|
83
|
+
```json5
|
|
84
|
+
assets: {
|
|
85
|
+
myImage: {
|
|
86
|
+
type: "string",
|
|
87
|
+
default: "./assets/my-image.png",
|
|
88
|
+
description: "我的图片",
|
|
89
|
+
xplatform: { value_type: "path", mime_type: "image/png" },
|
|
90
|
+
},
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
4. 在代码中使用:
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
import { GameThemeConfig } from './config/ThemeConfig';
|
|
98
|
+
const imageUrl = GameThemeConfig.ASSET_MY_IMAGE;
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## 第五步:修改游戏逻辑
|
|
102
|
+
|
|
103
|
+
编辑 `src/scenes/MainScene.ts`,这是主游戏场景。
|
|
104
|
+
|
|
105
|
+
### 读取配置
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
import { GameThemeConfig } from '../config/ThemeConfig';
|
|
109
|
+
|
|
110
|
+
// 读取配置
|
|
111
|
+
const difficulty = GameThemeConfig.DIFFICULTY;
|
|
112
|
+
const bgColor = GameThemeConfig.BACKGROUND_COLOR;
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### 添加游戏元素
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
create() {
|
|
119
|
+
// 添加精灵
|
|
120
|
+
const sprite = this.add.sprite(100, 100, 'myImage');
|
|
121
|
+
|
|
122
|
+
// 添加文本
|
|
123
|
+
const text = this.add.text(100, 200, 'Hello!', {
|
|
124
|
+
fontSize: '32px',
|
|
125
|
+
color: GameThemeConfig.TEXT_COLOR
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// 添加交互
|
|
129
|
+
sprite.setInteractive();
|
|
130
|
+
sprite.on('pointerdown', () => {
|
|
131
|
+
console.log('点击了精灵!');
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## 第六步:构建生产版本
|
|
137
|
+
|
|
138
|
+
### 构建单个渠道
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
npm run build -- google
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
输出在 `dist/` 目录。
|
|
145
|
+
|
|
146
|
+
### 批量构建所有渠道
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
npm run builds
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
输出在 `dist-all/` 目录。
|
|
153
|
+
|
|
154
|
+
## 常见任务
|
|
155
|
+
|
|
156
|
+
### 修改 Loading 页面
|
|
157
|
+
|
|
158
|
+
编辑 `src/theme/theme.schema.json5` 的 `loading` 部分:
|
|
159
|
+
|
|
160
|
+
```json5
|
|
161
|
+
loading: {
|
|
162
|
+
appTitle: {
|
|
163
|
+
type: "string",
|
|
164
|
+
default: "My Game",
|
|
165
|
+
description: "应用标题",
|
|
166
|
+
},
|
|
167
|
+
// ...
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### 添加音频
|
|
172
|
+
|
|
173
|
+
1. 将音频文件放到 `assets/`
|
|
174
|
+
2. 在 `src/scenes/PreloadScene.ts` 中加载:
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
this.load.audio('bgm', 'assets/bgm.mp3');
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
3. 在 `MainScene.ts` 中播放:
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
this.audioManager.playBGM('bgm');
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### 调试渠道
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
# 本地预览时模拟 Google Ads 渠道
|
|
190
|
+
npm run dev
|
|
191
|
+
|
|
192
|
+
# 模拟 Facebook 渠道
|
|
193
|
+
npm run dev:wp facebook
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## 获取帮助
|
|
197
|
+
|
|
198
|
+
- 查看 [README.md](./README.md) 了解详细功能
|
|
199
|
+
- 查看 [CLAUDE.md](./CLAUDE.md) 了解架构设计
|
|
200
|
+
- 查看 [Phaser 官方文档](https://phaser.io/learn)
|
|
201
|
+
- 查看主题元数据:`src/theme/theme.metadata.md`
|
|
202
|
+
|
|
203
|
+
## 下一步
|
|
204
|
+
|
|
205
|
+
- 学习 Phaser 基础:https://phaser.io/tutorials
|
|
206
|
+
- 了解可玩广告规范:各渠道的尺寸和功能限制
|
|
207
|
+
- 探索 UI 组件:`src/ui/` 目录中的示例组件
|
|
208
|
+
|
|
209
|
+
祝开发顺利!🎮
|