feat: 添加微信SDK和关卡页面,重构预制体结构

- 新增 WxSDK 微信SDK工具类
- 新增 PageLevel 关卡选择页面组件
- 将 prefabs 目录从 resources 移至根目录
- 更新 ViewManager 支持预制体属性引用
- 添加 BaseView 页面基类

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
richarjiang
2026-03-11 10:35:21 +08:00
parent 8986d8d8f2
commit 0bda6904fa
18 changed files with 1149 additions and 1646 deletions

View File

@@ -0,0 +1,560 @@
[
{
"__type__": "cc.Prefab",
"_name": "PageHome",
"_objFlags": 0,
"__editorExtras__": {},
"_native": "",
"data": {
"__id__": 1
},
"optimizationPolicy": 0,
"persistent": false
},
{
"__type__": "cc.Node",
"_name": "PageHome",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": null,
"_children": [
{
"__id__": 2
},
{
"__id__": 10
}
],
"_active": true,
"_components": [
{
"__id__": 20
},
{
"__id__": 22
},
{
"__id__": 24
}
],
"_prefab": {
"__id__": 26
},
"_lpos": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_lrot": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_lscale": {
"__type__": "cc.Vec3",
"x": 1,
"y": 1,
"z": 1
},
"_mobility": 0,
"_layer": 1073741824,
"_euler": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_id": ""
},
{
"__type__": "cc.Node",
"_name": "Bg",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": {
"__id__": 1
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 3
},
{
"__id__": 5
},
{
"__id__": 7
}
],
"_prefab": {
"__id__": 9
},
"_lpos": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_lrot": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_lscale": {
"__type__": "cc.Vec3",
"x": 1,
"y": 1,
"z": 1
},
"_mobility": 0,
"_layer": 1073741824,
"_euler": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_id": ""
},
{
"__type__": "cc.UITransform",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 2
},
"_enabled": true,
"__prefab": {
"__id__": 4
},
"_contentSize": {
"__type__": "cc.Size",
"width": 1080,
"height": 2160
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "516nXwOy1HyILEPLAixt3+"
},
{
"__type__": "cc.Sprite",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 2
},
"_enabled": true,
"__prefab": {
"__id__": 6
},
"_customMaterial": null,
"_srcBlendFactor": 2,
"_dstBlendFactor": 4,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_spriteFrame": {
"__uuid__": "d532045e-55f8-47c2-9493-b918e18364b0@f9941",
"__expectedType__": "cc.SpriteFrame"
},
"_type": 0,
"_fillType": 0,
"_sizeMode": 0,
"_fillCenter": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_useGrayscale": false,
"_atlas": null,
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "caSJymhl1EjYDJB5ONQknn"
},
{
"__type__": "d33b0ZrKQJEaKZYN2Peg+C/",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 2
},
"_enabled": true,
"__prefab": {
"__id__": 8
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "5fvoDQhtZHSaQ4OjsBm2R+"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "34DqITevxDppujuUM+M3Ep",
"instance": null,
"targetOverrides": null,
"nestedPrefabInstanceRoots": null
},
{
"__type__": "cc.Node",
"_name": "startGame",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": {
"__id__": 1
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 11
},
{
"__id__": 13
},
{
"__id__": 15
},
{
"__id__": 17
}
],
"_prefab": {
"__id__": 19
},
"_lpos": {
"__type__": "cc.Vec3",
"x": 0,
"y": -800.532,
"z": 0
},
"_lrot": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_lscale": {
"__type__": "cc.Vec3",
"x": 1.583,
"y": 1.583,
"z": 1.583
},
"_mobility": 0,
"_layer": 1073741824,
"_euler": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_id": ""
},
{
"__type__": "cc.UITransform",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 10
},
"_enabled": true,
"__prefab": {
"__id__": 12
},
"_contentSize": {
"__type__": "cc.Size",
"width": 216,
"height": 107
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "35asQ5bFtJOr9Onmy9xZov"
},
{
"__type__": "cc.Sprite",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 10
},
"_enabled": true,
"__prefab": {
"__id__": 14
},
"_customMaterial": null,
"_srcBlendFactor": 2,
"_dstBlendFactor": 4,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_spriteFrame": {
"__uuid__": "010e6809-3636-4c23-8403-1424c771f0f8@f9941",
"__expectedType__": "cc.SpriteFrame"
},
"_type": 0,
"_fillType": 0,
"_sizeMode": 1,
"_fillCenter": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_useGrayscale": false,
"_atlas": null,
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "bbY0DIwZZE564mJcuIqyL2"
},
{
"__type__": "cc.Widget",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 10
},
"_enabled": true,
"__prefab": {
"__id__": 16
},
"_alignFlags": 4,
"_target": null,
"_left": 0,
"_right": 0,
"_top": 0,
"_bottom": 194.77749999999992,
"_horizontalCenter": 0,
"_verticalCenter": 0,
"_isAbsLeft": true,
"_isAbsRight": true,
"_isAbsTop": true,
"_isAbsBottom": true,
"_isAbsHorizontalCenter": true,
"_isAbsVerticalCenter": true,
"_originalWidth": 0,
"_originalHeight": 0,
"_alignMode": 2,
"_lockFlags": 0,
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "daRisiwm1PEKRk63d1ICPO"
},
{
"__type__": "cc.Button",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 10
},
"_enabled": true,
"__prefab": {
"__id__": 18
},
"clickEvents": [],
"_interactable": true,
"_transition": 3,
"_normalColor": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_hoverColor": {
"__type__": "cc.Color",
"r": 211,
"g": 211,
"b": 211,
"a": 255
},
"_pressedColor": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_disabledColor": {
"__type__": "cc.Color",
"r": 124,
"g": 124,
"b": 124,
"a": 255
},
"_normalSprite": null,
"_hoverSprite": null,
"_pressedSprite": null,
"_disabledSprite": null,
"_duration": 0.1,
"_zoomScale": 1.2,
"_target": null,
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "29dh3pT0tGe4UqoNypQFFz"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "24z1aCS5BGUoUcLzSowxMh",
"instance": null,
"targetOverrides": null,
"nestedPrefabInstanceRoots": null
},
{
"__type__": "cc.UITransform",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 1
},
"_enabled": true,
"__prefab": {
"__id__": 21
},
"_contentSize": {
"__type__": "cc.Size",
"width": 1080,
"height": 2160
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "3fh/GQw5BFtaWjY2iRXZNj"
},
{
"__type__": "cc.Widget",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 1
},
"_enabled": true,
"__prefab": {
"__id__": 23
},
"_alignFlags": 45,
"_target": null,
"_left": 0,
"_right": 0,
"_top": 0,
"_bottom": 0,
"_horizontalCenter": 0,
"_verticalCenter": 0,
"_isAbsLeft": true,
"_isAbsRight": true,
"_isAbsTop": true,
"_isAbsBottom": true,
"_isAbsHorizontalCenter": true,
"_isAbsVerticalCenter": true,
"_originalWidth": 1080,
"_originalHeight": 2160,
"_alignMode": 2,
"_lockFlags": 0,
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "adez9PYBlO+o5jJaEuv12a"
},
{
"__type__": "ada67C1KJZGrIrj62ihFzBE",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 1
},
"_enabled": true,
"__prefab": {
"__id__": 25
},
"startGameBtn": {
"__id__": 10
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "59sKvUi4BJY43S8yX+l4bC"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "c46/YsCPVOJYA4mWEpNYRx",
"instance": null,
"targetOverrides": null
}
]

View File

@@ -0,0 +1,13 @@
{
"ver": "1.1.50",
"importer": "prefab",
"imported": true,
"uuid": "ae6e1ab4-19be-4cb3-90e4-9a1f3204a0fd",
"files": [
".json"
],
"subMetas": {},
"userData": {
"syncNodeName": "PageHome"
}
}

View File

@@ -0,0 +1,77 @@
import { _decorator, Node, Button } from 'cc';
import { BaseView } from 'db://assets/scripts/core/BaseView';
import { ViewManager } from 'db://assets/scripts/core/ViewManager';
import { WxSDK } from 'db://assets/scripts/utils/WxSDK';
const { ccclass, property } = _decorator;
/**
* 首页组件
* 继承 BaseView实现页面生命周期
*/
@ccclass('PageHome')
export class PageHome extends BaseView {
@property({ type: Node, tooltip: '开始游戏按钮' })
startGameBtn: Node | null = null;
/**
* 页面首次加载时调用
*/
onViewLoad(): void {
console.log('[PageHome] onViewLoad');
this._initButtons();
this._initWxShare();
}
/**
* 初始化微信分享功能
*/
private _initWxShare(): void {
WxSDK.initShare({
title: '写英语',
imageUrl: '',
query: ''
});
}
/**
* 初始化按钮事件
*/
private _initButtons(): void {
if (this.startGameBtn) {
this.startGameBtn.on(Button.EventType.CLICK, this._onStartGameClick, this);
}
}
/**
* 开始游戏按钮点击回调
*/
private _onStartGameClick(): void {
console.log('[PageHome] 开始游戏按钮点击');
ViewManager.instance.open('PageLevel');
}
/**
* 页面每次显示时调用
*/
onViewShow(): void {
console.log('[PageHome] onViewShow');
}
/**
* 页面隐藏时调用
*/
onViewHide(): void {
console.log('[PageHome] onViewHide');
}
/**
* 页面销毁时调用
*/
onViewDestroy(): void {
console.log('[PageHome] onViewDestroy');
// 移除按钮事件监听
if (this.startGameBtn) {
this.startGameBtn.off(Button.EventType.CLICK, this._onStartGameClick, this);
}
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "ada670b5-2896-46ac-8ae3-eb68a1173044",
"files": [],
"subMetas": {},
"userData": {}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,13 @@
{
"ver": "1.1.50",
"importer": "prefab",
"imported": true,
"uuid": "8611dbdc-4749-49f1-97ca-aedae3d16320",
"files": [
".json"
],
"subMetas": {},
"userData": {
"syncNodeName": "PageLevel"
}
}

221
assets/prefabs/PageLevel.ts Normal file
View File

@@ -0,0 +1,221 @@
import { _decorator, Node, EditBox, instantiate, Vec3 } from 'cc';
import { BaseView } from 'db://assets/scripts/core/BaseView';
const { ccclass, property } = _decorator;
/**
* 关卡配置接口
*/
export interface LevelConfig {
/** 需要的输入框数量 */
inputCount: number;
/** 题目文本 */
questionText?: string;
}
/**
* 关卡页面组件
* 继承 BaseView实现页面生命周期
*/
@ccclass('PageLevel')
export class PageLevel extends BaseView {
// ========== 节点引用 ==========
@property(Node)
inputLayout: Node | null = null;
@property(Node)
submitButton: Node | null = null;
@property(Node)
inputTemplate: Node | null = null;
@property(Node)
actionNode: Node | null = null;
// ========== 配置属性 ==========
@property({
tooltip: '默认输入框数量',
min: 1,
max: 10
})
defaultInputCount: number = 2;
// ========== 内部状态 ==========
/** 当前输入框数量 */
private _inputCount: number = 0;
/** 当前创建的输入框节点数组 */
private _inputNodes: Node[] = [];
/** 当前关卡配置 */
private _levelConfig: LevelConfig | null = null;
/**
* 页面首次加载时调用
*/
onViewLoad(): void {
console.log('[PageLevel] onViewLoad');
this.initLevel();
}
/**
* 页面每次显示时调用
*/
onViewShow(): void {
console.log('[PageLevel] onViewShow');
}
/**
* 页面隐藏时调用
*/
onViewHide(): void {
console.log('[PageLevel] onViewHide');
}
/**
* 页面销毁时调用
*/
onViewDestroy(): void {
console.log('[PageLevel] onViewDestroy');
this.clearInputNodes();
}
/**
* 设置关卡配置
*/
setLevelConfig(config: LevelConfig): void {
this._levelConfig = config;
this.initLevel();
}
/**
* 初始化关卡
*/
private initLevel(): void {
// 使用配置或默认值
const inputCount = this._levelConfig?.inputCount ?? this.defaultInputCount;
// 隐藏提交按钮
if (this.submitButton) {
this.submitButton.active = false;
}
// 创建输入框
this.createInputs(inputCount);
}
/**
* 动态创建输入框
*/
private createInputs(count: number): void {
if (!this.inputLayout || !this.inputTemplate) {
console.error('[PageLevel] inputLayout 或 inputTemplate 未设置');
return;
}
// 清理现有输入框
this.clearInputNodes();
this._inputCount = count;
// 隐藏模板节点
this.inputTemplate.active = false;
// 创建指定数量的输入框
for (let i = 0; i < count; i++) {
const inputNode = instantiate(this.inputTemplate);
inputNode.active = true;
inputNode.name = `input${i}`;
// 设置位置Layout 会自动排列)
inputNode.setPosition(new Vec3(0, 0, 0));
// 获取 EditBox 组件并监听事件
const editBox = inputNode.getComponent(EditBox);
if (editBox) {
// 清空输入内容
editBox.string = '';
// 监听文本变化事件
editBox.node.on(EditBox.EventType.TEXT_CHANGED, this.onInputTextChanged, this);
// 监听编辑结束事件
editBox.node.on(EditBox.EventType.EDITING_DID_ENDED, this.onInputEditingEnded, this);
}
this.inputLayout.addChild(inputNode);
this._inputNodes.push(inputNode);
}
console.log(`[PageLevel] 创建了 ${count} 个输入框`);
}
/**
* 清理所有输入框节点
*/
private clearInputNodes(): void {
for (const node of this._inputNodes) {
if (node.isValid) {
node.destroy();
}
}
this._inputNodes = [];
this._inputCount = 0;
}
/**
* 检查所有输入框是否都已填写
*/
private checkAllInputsFilled(): void {
let allFilled = true;
for (const node of this._inputNodes) {
const editBox = node.getComponent(EditBox);
if (!editBox || editBox.string.trim() === '') {
allFilled = false;
break;
}
}
// 根据填写状态显示/隐藏提交按钮
if (this.submitButton) {
this.submitButton.active = allFilled;
}
console.log(`[PageLevel] 检查输入状态: ${allFilled ? '全部已填写' : '未全部填写'}`);
}
/**
* 获取所有输入框的值
*/
getInputValues(): string[] {
const values: string[] = [];
for (const node of this._inputNodes) {
const editBox = node.getComponent(EditBox);
values.push(editBox?.string ?? '');
}
return values;
}
/**
* 获取拼接后的答案字符串
*/
getAnswer(): string {
return this.getInputValues().join('');
}
// ========== EditBox 事件回调 ==========
/**
* 输入框文本变化回调
*/
private onInputTextChanged(editBox: EditBox): void {
this.checkAllInputsFilled();
}
/**
* 输入框编辑结束回调
*/
private onInputEditingEnded(editBox: EditBox): void {
this.checkAllInputsFilled();
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "14b235e0-e649-477a-beb1-7890db8d0c9a",
"files": [],
"subMetas": {},
"userData": {}
}