本次使用的Cocos版本为3.8.7
前期准备:图片处理与格式转换
在游戏开发或图形应用中,高效的资源管理对性能提升至关重要,而纹理处理是其中关键一环。
思路
1.使用TexturePacker 工具导出包含 test.png 和 test.plist 的图集文件。
2.得到 test.png 后,为进一步降低纹理内存占用、提升加载与渲染效率,将其转换为 ASTC 格式,本次选用 6x6 转的参数配置。
附加转astc格式方法 参考:【分享】图片工具将png转pkm或astc 且可还原
3.使用脚本 将 plist 内容融入 astc文件中
在完成图片格式转换后,一个巧妙的操作是将 plist 文件内容写入到 test.astc 中,这里自己将plist内容写入到astc文件中。将plist写入文件的目的是为了减少文件下载量
我写入的 plist 内容如下:
子纹理文件名 | x 坐标 | y 坐标 | 宽度 | 高度 | 偏移 x | 偏移 y | 原始宽度 | 原始高度 | 是否旋转 | 图集宽|图集高
path=test.png
test_01.png|802|2|154|136|26|46|300|300|0|958|140
test_02.png|486|2|158|136|28|46|300|300|0|958|140
test_03.png|164|2|160|136|30|46|300|300|0|958|140
test_04.png|2|2|160|136|30|46|300|300|0|958|140
test_05.png|326|2|158|136|27|46|300|300|0|958|140
test_06.png|646|2|154|136|25|46|300|300|0|958|140
在这个新的内容结构里,第一行 “path=stand1_4.png” 明确了纹理图集对应的原始图片文件名,就像给一个档案库贴上了总标签,表明里面的文件来自何处。后续每一行以 “子纹理文件名 | x 坐标 | y 坐标 | 宽度 | 高度 | 偏移 x | 偏移 y | 原始宽度 | 原始高度 | 是否旋转 | 其他信息” 的格式,详细记录了每个子纹理在图集中的位置、自身尺寸、偏移量以及旋转状态等关键信息
后缀转换与文件准备
完成 plist 内容写入 test.astc 后,将 test.astc 的后缀改成 test.bin ,这是为了个体assetManager.loadRemote下载二进制数据
核心加载:Cocos Creator 3.8.7 大显身手
加载流程解析
在 Cocos Creator 3.8.7 的项目开发中,loadBin函数承担着远程加载 test.bin 文件并解析其中 plist 内容的关键职责,是资源加载流程的核心环节 。由于将plist内容写到test.bin中了,因此我们只需要下载test.bin一个文件
interface PlistInfo {
name: string
x: number
y: number
w: number
h: number
offsetX: number
offsetY: number
srcSizeX: number
srcSizeY: number
rotated: number
textureWidth: number
textureHeight: number
}
loadBin(URL) {
assetManager.loadRemote(URL, (Err, pAsset:BufferAsset) => {
if (Err == null && pAsset) {
let pBuffView = new DataView(pAsset.buffer())
let nLen = pBuffView.byteLength
let pTail = ""
let PlistData = { Name: "", Info: \[] }
for (let i = nPlistLen; i >= 1; i--) {
let V = pBuffView.getUint8(nLen - i - 12)
let B = String.fromCharCode(V)
if (B == '\n') {
pTail = pTail.replace('\r', '')
let StrList = pTail.split("|")
if (StrList.length == 1) {
PlistData.Name = StrList[0]
} else {
PlistData.Info.push({
name: StrList[0],
x: Number(StrList[1]),
y: Number(StrList[2]),
w: Number(StrList[3]),
h: Number(StrList[4]),
offsetX: Number(StrList[5]),
offsetY: Number(StrList[6]),
srcSizeX: Number(StrList[7]),
srcSizeY: Number(StrList[8]),
rotated: Number(StrList[9]),
})
}
pTail = ""
} else {
pTail = pTail + B
}
}
console.log("得到的Plist数据=>>>", PlistData)
this.CreateNativeImageBitmap(pAsset, PlistData).then((ImageAtils) => {
if (ImageAtils) {
this.msprite.spriteFrame = ImageAtils\[0]
} else {
console.log("图集加载失败")
}
}).catch(() => {
console.log("图集加载失败")
})
} else {
console.log("下载失败:", Err)
}
})
}
上述方法是通过远程下载test.bin得到pAsset:BufferAsset类型的数据,再通过解析pAsset得到plist的内容。
图片构建与显示
在成功解析出 plist 内容后,CreateNativeImageBitmap函数登场,它负责将加载的文件数据转化为可供显示的纹理和精灵帧,是实现图片最终显示在界面上的关键步骤 。
CreateNativeImageBitmap(Data: BufferAsset, PlistData: { Name: string; Info: Array<PlistInfo> }) {
return new Promise((resolve, reject) => {
try {
const dataView = new DataView(Data.buffer(), 0, 16);
const read3LE = (view: DataView, off: number) =>
view.getUint8(off) | (view.getUint8(off + 1) << 8) | (view.getUint8(off + 2) << 16);
const widthASTC = read3LE(dataView, 7);
const heightASTC = read3LE(dataView, 10);
const width = PlistData.Info[0].textureWidth ?? widthASTC;
const height = PlistData.Info[0].textureHeight ?? heightASTC;
console.log(`ASTC 文件头尺寸: ${widthASTC}x${heightASTC}, 原图尺寸: ${width}x${height}`);
const texture = new Texture2D();
texture.reset({
width: width,
height: height,
format: Texture2D.PixelFormat.RGBA_ASTC_6x6,
})
// 上传有效数据部分(跳过16字节文件头)
const validData = new DataView(Data.buffer(), 16);
texture.uploadData(validData);
let ImageAtils = new Array<SpriteFrame>()
let len = PlistData.Info.length
for (let i = 0; i < len; i++) {
const Info: PlistInfo = PlistData.Info[i]
const pSpriteFrame = new SpriteFrame()
pSpriteFrame.name = Info.name
pSpriteFrame.texture = texture
pSpriteFrame.offset = new Vec2(Info.offsetX, Info.offsetY)
pSpriteFrame.rect = new Rect(Info.x, Info.y, Info.w, Info.h)
pSpriteFrame.originalSize = new Size(Info.srcSizeX, Info.srcSizeY)
ImageAtils.push(pSpriteFrame)
}
resolve(ImageAtils)
} catch (error) {
console.error('从ArrayBuffer加载图像失败:', error)
reject(null)
}
})
}
最后,根据解析出的PlistData.Info数组中的信息,循环创建SpriteFrame对象 。为每个SpriteFrame对象设置名称、关联之前创建的texture、偏移量、矩形区域以及原始尺寸等属性 ,这些属性就像为每个子图像在画布上贴上了精准的位置和尺寸标签 ,将创建好的SpriteFrame对象添加到ImageAtils数组中 。当所有SpriteFrame创建完成后,通过resolve返回ImageAtils数组,若在整个过程中出现错误,通过reject返回错误信息 。
兼容性检测:确保 astc 畅行无阻
多平台支持判断
在跨平台应用开发中,ASTC 格式虽有显著优势,但不同平台对其支持程度存在差异,所以检测设备对 ASTC 格式的支持情况是至关重要的前置步骤,这就像在出发前检查车辆是否能适应不同路况一样 。
export enum ASTCSIZE {
'4x4'='4x4',
'5x5'='5x5',
'6x6'='6x6',
'8x8'='8x8',
'10x10'='10x10'
}
isASTCSupported(blockSize: ASTCSIZE): boolean {
if (sys.isBrowser) {
return this.checkWebASTC(blockSize);
} else {
return this.checkNativeASTC(blockSize);
}
}
上述isASTCSupported函数是整个兼容性检测的总入口 ,它就像一个智能的导航仪,根据当前运行环境判断是 Web 平台还是原生平台 。若运行在浏览器环境(sys.isBrowser为true),则调用checkWebASTC函数进行 Web 平台的支持性检测;若在原生平台(sys.isBrowser为false),则调用checkNativeASTC函数开展原生平台的检测 ,这种分平台检测的方式,能精准地针对不同平台特性进行支持性判断,提高检测的准确性与可靠性 。
Web 平台检测是否支持astc
checkWebASTC(blockSize: string): boolean {
// 获取 WebGL 2.0 上下文(ASTC 仅支持 WebGL 2.0+)
const canvas = document.getElementById('GameCanvas') as HTMLCanvasElement;
if (!canvas) return false;
const gl = canvas.getContext('webgl2') as WebGL2RenderingContext;
if (!gl) {
console.log('WebGL 2.0 不支持,无法使用 ASTC');
return false;
}
// 检测所有可能的 ASTC 扩展(浏览器兼容性差异)
const astcExtensions = [
'WEBGL_compressed_texture_astc', // 通用扩展(Chrome 等主流浏览器)
'GL_KHR_texture_compression_astc_ldr', // KHR 标准扩展
'GL_OES_texture_compression_astc' // OpenGL ES 扩展(移动浏览器)
];
let astcExt: any = null;
for (const extName of astcExtensions) {
astcExt = gl.getExtension(extName);
if (astcExt) break;
}
if (!astcExt) {
console.log('浏览器不支持任何 ASTC 扩展');
return false;
}
// 检查扩展是否支持目标块大小的格式
const blockSizeToFormat: Record<string, string> = {
'4x4': 'COMPRESSED_RGBA_ASTC_4x4_KHR',
'5x5': 'COMPRESSED_RGBA_ASTC_5x5_KHR',
'6x6': 'COMPRESSED_RGBA_ASTC_6x6_KHR',
'8x8': 'COMPRESSED_RGBA_ASTC_8x8_KHR',
'10x10': 'COMPRESSED_RGBA_ASTC_10x10_KHR',
};
const formatKey = blockSizeToFormat[blockSize];
if (!formatKey || !astcExt[formatKey]) {
console.log(`ASTC 块大小 ${blockSize} 不被支持`);
return false;
}
return true;
}
原生平台检测是否支持Astc
checkNativeASTC(blockSize: string): boolean {
// 确保 gfx 设备已初始化
if (!gfx.deviceManager || !gfx.deviceManager.gfxDevice) {
console.log('gfx 设备未初始化,无法检测 ASTC');
return false;
}
// 映射块大小到 gfx.Format 枚举
const blockSizeToFormat: Record<string, gfx.Format> = {
'4x4': gfx.Format.ASTC_RGBA_4X4,
'5x5': gfx.Format.ASTC_RGBA_5X5,
'6x6': gfx.Format.ASTC_RGBA_6X6,
'8x8': gfx.Format.ASTC_RGBA_8X8,
'10x10': gfx.Format.ASTC_RGBA_10X10,
};
const targetFormat = blockSizeToFormat[blockSize];
if (targetFormat === undefined) {
console.log(`不支持的 ASTC 块大小:${blockSize}`);
return false;
}
// 查询 GPU 是否支持该格式作为纹理
const formatFeatures = gfx.deviceManager.gfxDevice.getFormatFeatures(targetFormat);
const support = (formatFeatures & 1) !== 0;
if (!support) {
console.log(`GPU 不支持 ASTC ${blockSize} 格式`);
}
return support;
}
这两个检测函数再API文档里面查不到,我还是论坛上找到的!!!
使用的时候大家可以根据项目情况参考修改。
我用windows的goole浏览器不支持Astc,预览我都是使用手机浏览器测试的!!


