问题遇到的现象和发生背景
在cocos 3.8.7中可以使用,但是构建发布到微信小程序就报错,具体要怎么修改呢

代码
import {
_decorator, // 装饰器
Component, // 组件基类
Prefab, // 预制体
instantiate, // 实例化
Node, // 节点
Sprite, // Sprite 组件
SpriteFrame, // SpriteFrame
Label, // Label
Layout, // Layout 布局
resources // resources 资源加载
} from 'cc';
import { LoadTable } from '../LoadTable'; // 配置表加载
import { EventManager } from '../EventManager'; // 事件管理
import { snail } from '../table/schema'; // 表结构
const { ccclass, property } = _decorator;
/**
* 根据配置生成皮肤预制体列表
*/
@ccclass('SkinList')
export class SkinList extends Component {
// 👉 这里拖拽的就是原来的 List1.prefab(带背景图的那个)
@property(Prefab)
skinPrefab: Prefab = null;
// 皮肤配置数据
private skinDataList: snail.Skin[] = [];
// SpriteFrame 缓存
private skinSpriteFrames: Map<string, SpriteFrame> = new Map();
/**
* 组件启动
*/
start() {
// 监听配置加载完成
EventManager.getInstance().on(
'configLoaded',
this.onConfigLoaded,
this
);
// 已加载直接执行
if (LoadTable.tab && LoadTable.tab.TvSkin) {
this.onConfigLoaded();
}
}
/**
* 组件销毁
*/
onDestroy() {
EventManager.getInstance().off(
'configLoaded',
this.onConfigLoaded,
this
);
}
/**
* 配置表加载完成
*/
private onConfigLoaded() {
if (!LoadTable.tab || !LoadTable.tab.TvSkin) {
console.error("配置表数据未加载完成");
return;
}
// 获取皮肤数据
this.skinDataList = LoadTable.tab.TvSkin.getDataList();
if (!this.skinDataList || this.skinDataList.length === 0) {
console.error("皮肤配置数据为空");
return;
}
// 👉 Layout 只加在 List 节点上
this.setupLayout(this.node);
// 加载皮肤图片
this.loadSkinSprites();
}
/**
* 加载皮肤 SpriteFrame
*/
private loadSkinSprites() {
resources.loadDir(
'game/skin',
SpriteFrame,
(err, assets: SpriteFrame[]) => {
if (err) {
console.error('加载皮肤图片失败', err);
return;
}
// 缓存 SpriteFrame
assets.forEach(sf => {
this.skinSpriteFrames.set(sf.name, sf);
});
// 创建皮肤 Item
this.createSkinItems();
}
);
}
/**
* 设置 Layout
* 作用对象:List 节点
*/
private setupLayout(listNode: Node) {
let layout = listNode.getComponent(Layout);
if (!layout) {
layout = listNode.addComponent(Layout);
}
// 网格布局
layout.type = Layout.Type.GRID;
// 固定列数
layout.constraint = Layout.Constraint.FIXED_COL;
// 每行 4 个
layout.constraintNum = 4;
// 间距
layout.spacingX = 70;
layout.spacingY = 70;
// 内边距
layout.paddingTop = -200;
layout.paddingBottom = 100;
layout.paddingLeft = -180;
layout.paddingRight = 0;
// 不改变自身尺寸
layout.resizeMode = Layout.ResizeMode.CHILDREN;
}
/**
* 创建皮肤 Item(每一个都是 List1 预制体)
*/
private createSkinItems() {
if (!this.skinPrefab) {
console.error('skinPrefab 未设置(请拖拽 List1.prefab)');
return;
}
this.skinDataList.forEach(skinData => {
// 实例化 List1 预制体
const skinItem = instantiate(this.skinPrefab);
// 命名
skinItem.name = `skin_${skinData.id}`;
// 直接添加到 List 节点
this.node.addChild(skinItem);
// 设置名称
const nameLabel = skinItem
.getChildByName('NameLabel')
?.getComponent(Label);
if (nameLabel) {
nameLabel.string = skinData.name;
}
// 设置价格
const priceLabel = skinItem
.getChildByName('PriceLabel')
?.getComponent(Label);
if (priceLabel) {
priceLabel.string = `价格: ${skinData.gold} 金币`;
}
// 设置 Icon 图片
const spriteName = `${skinData.icon}_0`;
const spriteFrame = this.skinSpriteFrames.get(spriteName);
const iconSprite = skinItem
.getChildByName('Icon')
?.getComponent(Sprite);
if (iconSprite && spriteFrame) {
iconSprite.spriteFrame = spriteFrame;
}
});
}
}
import { JsonAsset, resources } from "cc";
import { Tables } from "./table/schema";
export class LoadTable {
// 存储加载的配置表数据
static tab: Tables;
/**
* 初始化 LoadTable。
* 加载配置表数据,并创建 Tables 实例。
*/
static init(){
/**
* 表名数组
*
* 声明了一个名为 tableNames 的变量,
* 并将其赋值为一个
* 包含单个字符串元素 "tvskin" 的数组。
*/
let tableNames = ["tvskin"];
// 为每个表名添加 "config/" 前缀
for (let i in tableNames) {
tableNames[i] = "config/" + tableNames[i]
}
// 使用 resources.load 方法加载表数据
resources.load(tableNames,JsonAsset,
(err: Error,data:JsonAsset[]) => {
// 加载完成后创建 Tables 实例,并将数据存储在 tab 属性中
LoadTable.tab = new Tables(LoadTable.loadJson);
}
)
}
/**
* 加载指定名称的 JSON 数据。
* @param jsonName JSON 文件的名称。
* @return 返回加载的 JSON 数据。
*/
static loadJson(jsonName: string) {
// 使用 resources.get 方法获取指定名称的 JSON 资源
let asset = resources.get("config/" + jsonName, JsonAsset);
// 如果获取成功并且该资源具有 json 属性,则返回该属性的值
if (asset && asset.json) {
return asset.json;
}
// 否则,返回一个空数组
return [];
}
}
import { _decorator, Component, director, assetManager, ProgressBar, log, SpriteFrame, JsonAsset, ImageAsset } from 'cc';
import { LoadTable } from '../main/scripts/LoadTable';
import { ProgressBar001 } from './ProgressBar001';
const { ccclass, property } = _decorator;
// 使用装饰器定义组件类
@ccclass('StartCom')
export class StartCom extends Component {
// 进度条属性,在编辑器中可配置
@property(ProgressBar001)
bar: ProgressBar001 = null;
// 总资源数量
private totalResources = 0;
// 已加载资源数量
private loadedResources = 0;
// 已成功加载的资源路径数组
private loadedPaths: string[] = [];
// 需要加载的所有资源路径数组
private resourcePaths: string[] = [];
// 组件开始时的生命周期方法
start() {
// 输出日志标识开始加载资源
log('=== 开始加载资源 ===');
// 初始化进度条为0
this.bar.progress = 0;
// 确保进度条组件设置正确
this.setupProgressBar();
// 直接测试加载配置表文件(先确保配置表能加载)
this.testLoadConfigDirectly();
}
/**
* 设置进度条属性
*/
private setupProgressBar() {
// 设置移动方向为从左到右
this.bar.moveLeftToRight = true;
// 设置可见宽度(根据你的图片尺寸调整)
// 414是图片显示的宽度,可以根据需要调整
this.bar.visibleWidth = 350; // 使用你测试的350或500
// 输出设置信息用于调试
log(`进度条设置: 方向=${this.bar.moveLeftToRight ? '左→右' : '右→左'}, 宽度=${this.bar.visibleWidth}`);
}
/**
* 直接测试加载配置表文件
* 这个方法绕过LoadTable,直接测试配置表文件是否能正常加载
*/
private testLoadConfigDirectly() {
// 输出日志
log('直接测试加载配置表...');
// 加载resources资源包
assetManager.loadBundle('resources', (err, bundle) => {
// 如果加载失败
if (err) {
log(` 加载resources失败: ${err.message}`);
// 直接完成加载流程
this.finishLoading();
return;
}
// 配置表文件路径
const configPath = 'config/snail_tvskin';
log(`尝试加载配置表: ${configPath}`);
// 直接加载配置表文件(使用JsonAsset类型)
bundle.load(configPath, JsonAsset, (err2, jsonAsset) => {
// 如果加载失败
if (err2) {
log(` 直接加载配置表失败: ${err2.message}`);
} else {
// 加载成功
log(` 直接加载配置表成功`);
// 检查配置表数据
if (jsonAsset.json && Array.isArray(jsonAsset.json)) {
// 输出配置表数据数量
log(`配置表有 ${jsonAsset.json.length} 条数据`);
// 显示前3条数据作为示例
jsonAsset.json.slice(0, 3).forEach((item: any, index: number) => {
log(`数据 ${index + 1}: id=${item.id}, name=${item.name}, icon=${item.icon}`);
});
} else {
// 数据格式错误
log(` 配置表数据格式错误:`, jsonAsset.json);
}
}
// 继续使用LoadTable进行正式的配置表加载
this.loadConfigTables();
});
});
}
/**
* 加载配置表
* 使用LoadTable加载所有配置表数据
*/
private loadConfigTables() {
log('开始通过LoadTable加载配置表...');
// 检查LoadTable是否存在
if (!LoadTable) {
log(' LoadTable 未定义');
this.finishLoading();
return;
}
try {
// 重新初始化配置表(调用LoadTable的初始化方法)
LoadTable.init();
log(' LoadTable.init() 调用完成');
// 等待更长时间确保配置表加载完成(异步加载需要时间)
setTimeout(() => {
this.debugLoadTable();
}, 800);
} catch (error) {
// 初始化失败
log(` LoadTable初始化失败: ${error}`);
this.finishLoading();
}
}
/**
* 调试LoadTable状态
* 检查LoadTable是否正确加载了配置表数据
*/
private debugLoadTable() {
log('=== 调试LoadTable状态 ===');
// 检查LoadTable的所有属性
log(`LoadTable 对象:`, LoadTable);
log(`LoadTable.tab:`, LoadTable.tab);
// 如果LoadTable.tab存在
if (LoadTable.tab) {
// 检查所有表(特别是TvSkin表)
log(`LoadTable.tab.TvSkin:`, LoadTable.tab.TvSkin);
// 如果TvSkin表存在
if (LoadTable.tab.TvSkin) {
// 检查TvSkin的方法是否存在
log(`TvSkin.getDataMap:`, LoadTable.tab.TvSkin.getDataMap);
log(`TvSkin.getDataList:`, LoadTable.tab.TvSkin.getDataList);
// 尝试调用方法获取数据
try {
// 获取数据映射
const dataMap = LoadTable.tab.TvSkin.getDataMap();
// 获取数据列表
const dataList = LoadTable.tab.TvSkin.getDataList();
// 输出数据大小信息
log(`getDataMap() 返回: Map(${dataMap?.size})`);
log(`getDataList() 返回: Array(${dataList?.length})`);
// 检查数据列表
if (dataList && Array.isArray(dataList)) {
log(` 从getDataList()获取到 ${dataList.length} 个皮肤数据`);
// 显示前5条数据作为示例
dataList.slice(0, 5).forEach((skin: any, index: number) => {
log(`皮肤 ${index + 1}: id=${skin.id}, name=${skin.name}, icon=${skin.icon}`);
});
// 显示剩余数据数量
log(`... 还有 ${dataList.length - 5} 个皮肤`);
} else {
// 数据格式错误
log(` getDataList() 返回的不是数组:`, dataList);
}
} catch (error) {
// 调用方法失败
log(` 调用getDataList()失败: ${error}`);
}
}
}
// 继续加载资源包
this.loadResourcesBundle();
}
/**
* 加载整个resources资源包
* 这是正式的加载流程
*/
private loadResourcesBundle() {
log('正在加载 resources 资源包...');
// 重新加载bundle,确保是最新的(避免缓存问题)
assetManager.loadBundle('resources', (err, bundle) => {
// 如果加载失败
if (err) {
log(` 加载resources资源包失败: ${err.message}`);
this.finishLoading();
return;
}
// 加载成功
log(' resources资源包加载成功');
// 获取需要加载的资源列表
this.getResourceList(bundle);
});
}
/**
* 获取需要加载的资源列表
* 根据配置表数据构建需要加载的所有资源路径
*/
private getResourceList(bundle: any) {
log('构建资源加载列表...');
// 基础资源列表(必须加载的资源)
const resourceList = [
'game/listBg' // 游戏列表背景图
];
// 如果配置表有数据,添加所有皮肤资源
try {
// 检查LoadTable和TvSkin是否存在
if (LoadTable.tab && LoadTable.tab.TvSkin) {
// 获取皮肤数据列表
const dataList = LoadTable.tab.TvSkin.getDataList();
// 检查数据列表是否有效
if (dataList && Array.isArray(dataList) && dataList.length > 0) {
log(`从配置表获取 ${dataList.length} 个皮肤,开始添加所有皮肤...`);
// 添加所有皮肤资源路径
dataList.forEach((skin: any, index: number) => {
// 构建皮肤资源路径(格式:game/skin/characterX_0)
const skinPath = `game/skin/${skin.icon}_0`;
// 添加到资源列表
resourceList.push(skinPath);
// 每10个皮肤输出一次日志,避免日志太多
if (index < 5 || index % 10 === 0) {
log(`添加皮肤 ${index + 1}: ${skin.name} -> ${skinPath}`);
}
});
log(` 已添加所有 ${dataList.length} 个皮肤资源`);
} else {
// 数据为空或不是数组
log(` 配置表数据为空或不是数组`);
}
} else {
// LoadTable或TvSkin不存在
log(` LoadTable.tab 或 LoadTable.tab.TvSkin 不存在`);
}
} catch (error) {
// 获取配置表数据失败
log(` 获取配置表数据失败: ${error}`);
}
// 去重(确保没有重复的资源路径)
this.resourcePaths = [...new Set(resourceList)];
// 更新总资源数量
this.totalResources = this.resourcePaths.length;
// 输出加载统计信息
log(`需要加载 ${this.totalResources} 个资源 (包括 ${this.resourcePaths.length - 1} 个皮肤资源):`);
// 只显示前几个和最后几个资源路径,避免日志太长
const maxShow = 10;
for (let i = 0; i < Math.min(this.resourcePaths.length, maxShow); i++) {
log(`${i + 1}. ${this.resourcePaths[i]}`);
}
// 如果资源数量超过显示上限
if (this.resourcePaths.length > maxShow) {
log(`... 还有 ${this.resourcePaths.length - maxShow} 个资源未显示`);
log(`最后几个资源:`);
// 显示最后几个资源
for (let i = Math.max(maxShow, this.resourcePaths.length - 3); i < this.resourcePaths.length; i++) {
log(`${i + 1}. ${this.resourcePaths[i]}`);
}
}
// 测试加载第一个资源(验证资源是否能正常加载)
this.testLoadFirstResource(bundle);
}
/**
* 测试加载第一个资源
* 验证资源包中的资源是否能正常加载
*/
private testLoadFirstResource(bundle: any) {
// 如果没有资源需要加载
if (this.resourcePaths.length === 0) {
this.finishLoading();
return;
}
// 获取第一个资源路径
const testPath = this.resourcePaths[0];
log(`测试加载第一个资源: ${testPath}`);
// 尝试加载第一个资源
bundle.load(testPath, (err: any, asset: any) => {
// 如果加载失败
if (err) {
log(` 测试资源加载失败 [${testPath}]: ${err.message}`);
log(`尝试其他可能的路径...`);
// 尝试其他路径格式
this.tryAlternativePaths(bundle, testPath);
} else {
// 加载成功
log(` 测试资源加载成功 [${testPath}] (类型: ${asset?.constructor?.name})`);
// 开始加载所有资源
this.startLoadingAllResources(bundle);
}
});
}
/**
* 尝试其他可能的路径
* 当默认路径加载失败时,尝试其他可能的路径格式
*/
private tryAlternativePaths(bundle: any, originalPath: string) {
// 生成可能的替代路径数组
const alternatives = [
originalPath.replace('game/skin/', 'skin/'), // 去掉game/前缀
originalPath.replace('_0', ''), // 去掉_0后缀
originalPath.replace('game/skin/', 'game/'), // 去掉skin/子目录
originalPath.replace('game/', '') // 去掉game/前缀
];
// 已尝试的路径数量
let tried = 0;
// 总尝试路径数量
const total = alternatives.length;
// 遍历所有替代路径
alternatives.forEach((altPath) => {
// 跳过原始路径(已经尝试过了)
if (altPath === originalPath) return;
// 尝试加载替代路径
bundle.load(altPath, (err: any, asset: any) => {
// 增加尝试计数
tried++;
// 如果加载失败
if (err) {
log(` 替代路径失败 [${altPath}]: ${err.message}`);
} else {
// 加载成功
log(` 替代路径成功 [${altPath}] (类型: ${asset?.constructor?.name})`);
// 更新资源路径列表中的路径
const index = this.resourcePaths.indexOf(originalPath);
if (index !== -1) {
this.resourcePaths[index] = altPath;
}
}
// 如果所有路径都尝试过了
if (tried >= total) {
// 开始加载所有资源
this.startLoadingAllResources(bundle);
}
});
});
}
/**
* 开始加载所有资源
* 并行加载所有资源路径对应的资源
*/
private startLoadingAllResources(bundle: any) {
log(`开始加载所有 ${this.totalResources} 个资源...`);
// 记录开始时间(用于计算加载耗时)
const startTime = Date.now();
// 已完成加载的资源数量
let completedCount = 0;
// 遍历所有资源路径
this.resourcePaths.forEach((path, index) => {
// 使用不指定类型的方式加载(让引擎自动判断资源类型)
bundle.load(path, (err: any, asset: any) => {
// 增加完成计数
completedCount++;
// 如果加载失败
if (err) {
log(` 资源加载失败 [${path}]: ${err.message}`);
} else {
// 加载成功,添加到已加载路径列表
this.loadedPaths.push(path);
// 每加载10个资源输出一次进度,或者加载完成时输出
if (completedCount % 10 === 0 || completedCount === this.totalResources) {
const currentTime = Date.now();
const elapsedTime = (currentTime - startTime) / 1000;
log(` 已加载 ${completedCount}/${this.totalResources} 个资源 (用时: ${elapsedTime.toFixed(2)}s)`);
}
}
// 更新进度
this.updateProgress();
});
});
}
/**
* 更新进度
* 更新进度条显示和检查是否所有资源都加载完成
*/
private updateProgress() {
// 增加已加载资源计数
this.loadedResources++;
// 计算当前进度(0-1)
const progress = this.loadedResources / this.totalResources;
// 更新进度条显示
this.bar.progress = progress;
// 强制调用进度条的更新方法(确保草的位置更新)
if (this.bar['_updateBarStatus']) {
this.bar['_updateBarStatus']();
}
// 每10%输出一次日志,或者加载完成时输出
if (this.loadedResources % Math.ceil(this.totalResources / 10) === 0 || this.loadedResources === this.totalResources) {
log(`进度: ${(progress * 100).toFixed(1)}% (${this.loadedResources}/${this.totalResources})`);
}
// 检查是否所有资源都加载完成
if (this.loadedResources >= this.totalResources) {
log(`所有资源加载完成 (成功: ${this.loadedPaths.length}, 失败: ${this.totalResources - this.loadedPaths.length})`);
// 完成加载流程
this.finishLoading();
}
}
/**
* 所有资源加载完成
* 跳转到游戏场景
*/
private finishLoading() {
log('=====================');
log('所有资源加载流程完成');
log(`成功加载的资源 (${this.loadedPaths.length} 个):`);
// 只显示前几个和最后几个成功加载的资源,避免日志太长
const maxShow = 10;
for (let i = 0; i < Math.min(this.loadedPaths.length, maxShow); i++) {
log(`${i + 1}. ${this.loadedPaths[i]}`);
}
// 如果成功加载的资源超过显示上限
if (this.loadedPaths.length > maxShow) {
log(`... 还有 ${this.loadedPaths.length - maxShow} 个资源未显示`);
}
// 确保至少等待1秒,让用户能看到加载完成的进度条
setTimeout(() => {
log('准备跳转到 Game 场景...');
// 加载游戏场景
director.loadScene('Game', (err: any) => {
// 如果跳转失败
if (err) {
log(`跳转场景失败: ${err.message}`);
} else {
// 跳转成功
log('成功跳转到 Game 场景');
}
});
}, 1000);
}
}