Cocos Creator Playable 广告项目文件夹结构与命名规范
Playable 广告(可玩广告)在 Cocos Creator 中的开发需要遵循特定的文件夹结构和命名规则,以满足广告平台的技术要求和性能优化需求。以下是完整的规范指南:
一、文件夹命名规则
1. 基本原则
- 全小写字母:所有文件夹名使用小写字母
- 下划线分隔 :使用下划线
_代替空格 - 简洁明确:名称应反映内容
- 避免特殊字符:不使用中文、空格、特殊符号
2. 禁止使用的名称
ad、ads(可能被广告拦截器屏蔽)system、windows(操作系统保留名称)libs(平台可能限制)
二、标准文件夹结构
推荐的项目结构
playable_ad/
├── assets/
│ ├── images/
│ │ ├── backgrounds/
│ │ ├── characters/
│ │ ├── ui/
│ │ └── effects/
│ ├── audio/
│ │ ├── bgm/
│ │ └── sfx/
│ ├── animations/
│ ├── fonts/
│ └── data/
| ├── scripts/
| │ ├── core/
| │ ├── managers/
| │ ├── ui/
| │ └── utils/
| ├── scenes/
| ├── prefabs/
│ │ ├── common/
| ├── config/
├── build/
└── temp/
三、详细结构说明
1. assets/ - 资源目录
markdown
assets/
├── images/ # 图片资源
│ ├── backgrounds/ # 背景图 (bg_main.webp, bg_game.webp)
│ ├── characters/ # 角色图 (hero.webp, enemy.webp)
│ ├── ui/ # UI元素 (btn_play.webp,icon_restart.webp)
│ └── effects/ # 特效 (particle_fire.webp, effect_win.webp)
│
├── audio/ # 音频资源
│ ├── bgm/ # 背景音乐 (bgm_main.mp3)
│ └── sfx/ # 音效 (sfx_click.mp3, sfx_win.mp3)
│
├── animations/ # 动画资源
│ ├── character/ # 角色动画 (hero_anim.clip)
│ └── ui/ # UI动画 (btn_anim.clip)
│
├── fonts/ # 字体文件
│ └── ad_font.ttf # 广告专用字体
│
└── data/ # 数据文件
└── level_config.json # 关卡配置
2. scripts/ - 脚本目录
markdown
scripts/
├── core/ # 核心游戏逻辑
│ ├── game_controller.ts
│ └── character.ts
│
├── managers/ # 管理器
│ ├── resource_manager.ts
│ ├── audio_manager.ts
│ └── ad_manager.ts
│
├── ui/ # UI相关
│ ├── ui_manager.ts
│ ├── start_ui.ts
│ └── end_ui.ts
│
└── utils/ # 工具类
├── math_utils.ts
└── device_utils.ts
3. 其他关键目录
markdown
scenes/ # 游戏场景
├── start_scene.fire # 开始场景
├── game_scene.fire # 游戏主场景
└── end_scene.fire # 结束场景
prefabs/ # 预制体
├── player.prefab # 玩家预制体
└── enemy.prefab # 敌人预制体
config/ # 配置文件
├── ad_config.json # 广告配置
└── game_config.json # 游戏配置
build/ # 构建输出目录(不上传版本控制)
temp/ # 临时文件(不上传版本控制)
四、Playable 广告特殊要求
1. 资源命名规范
-
图片资源:
[类型]_[名称]_[尺寸].webpbg_main_1080x1920.webpbtn_play_200x80.webp
-
音频资源:
[类型]_[名称]_[时长]s.mp3sfx_click_1s.mp3bgm_main_30s.mp3
-
动画资源:
[对象]_[动作].cliphero_jump.clipui_button_pulse.clip
2. 文件大小优化
-
图片格式:优先使用 WebP(比 PNG 小 70%)
-
音频格式:使用 MP3(44.1kHz,96kbps)
-
资源压缩:
typescript// 在构建前自动压缩资源 Editor.Builder.on('before-change-files', () => { compressImages(); optimizeAudio(); });
3. 入口文件要求
-
必须文件 :
index.html(位于构建根目录) -
内容要求:
html<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <title>Playable Ad</title> <style> body { margin:0; padding:0; overflow:hidden; } #game-container { width:100%; height:100%; } </style> </head> <body> <div id="game-container"></div> <script src="cocos2d-js-min.js"></script> <script src="main.js"></script> </body> </html>
五、构建配置规范
1. 构建设置(project.json)
json
{
"engine": "engine",
"packages": "packages",
"name": "playable_ad",
"platform": "web-mobile",
"buildPath": "build",
"debug": false,
"md5Cache": false,
"sourceMaps": false,
"replaceSplashScreen": true,
"orientation": "portrait",
"webOrientation": "portrait",
"includeModules": ["cocos2d", "physics"],
"renderMode": 0, // 0:自动,1:Canvas,2:WebGL
"inlineSpriteFrames": true,
"mergeStartScene": false,
"optimizeHotUpdate": false,
"compressionType": "zip",
"zipCompressionLevel": 6,
"template": "link"
}
2. 资源压缩脚本
javascript
// scripts/compress_resources.js
const fs = require('fs');
const path = require('path');
const imagemin = require('imagemin');
const imageminWebp = require('imagemin-webp');
const { execSync } = require('child_process');
const ASSETS_PATH = path.join(__dirname, '../assets');
const BUILD_PATH = path.join(__dirname, '../build');
// 压缩图片为WebP格式
async function compressImages() {
await imagemin([`${ASSETS_PATH}/images/*.{jpg,png}`], {
destination: `${BUILD_PATH}/res/images`,
plugins: [imageminWebp({ quality: 80 })]
});
}
// 优化音频文件
function optimizeAudio() {
const audioFiles = fs.readdirSync(`${ASSETS_PATH}/audio`);
audioFiles.forEach(file => {
if (file.endsWith('.wav')) {
const input = `${ASSETS_PATH}/audio/${file}`;
const output = `${BUILD_PATH}/res/audio/${file.replace('.wav', '.mp3')}`;
execSync(`ffmpeg -i ${input} -codec:a libmp3lame -qscale:a 4 ${output}`);
}
});
}
// 主执行函数
async function main() {
console.log('Starting resource optimization...');
await compressImages();
optimizeAudio();
console.log('Resource optimization completed!');
}
main();
六、Playable 广告特殊组件
1. 广告管理器
typescript
// scripts/managers/ad_manager.ts
export class AdManager {
private static instance: AdManager;
private constructor() {}
public static getInstance(): AdManager {
if (!AdManager.instance) {
AdManager.instance = new AdManager();
}
return AdManager.instance;
}
// 显示跳过按钮(5秒后显示)
public showSkipButton(delay: number = 5): void {
setTimeout(() => {
const skipBtn = this.createSkipButton();
cc.director.getScene().addChild(skipBtn);
}, delay * 1000);
}
private createSkipButton(): cc.Node {
const node = new cc.Node('skip_btn');
node.setPosition(cc.v2(cc.winSize.width - 50, cc.winSize.height - 50));
const sprite = node.addComponent(cc.Sprite);
sprite.spriteFrame = this.loadTexture('ui/skip_btn');
node.on(cc.Node.EventType.TOUCH_END, () => {
this.onSkipAd();
});
return node;
}
private onSkipAd(): void {
// 调用广告平台SDK的跳过方法
if (typeof window['adSDK'] !== 'undefined') {
window['adSDK'].skipAd();
} else {
cc.log('Skip ad triggered');
}
}
// 游戏结束处理
public onGameEnd(success: boolean): void {
if (success) {
this.showEndScreen('win');
} else {
this.showEndScreen('lose');
}
}
private showEndScreen(type: 'win' | 'lose'): void {
// 显示结束画面并添加下载按钮
}
}
2. 资源加载管理器
typescript
// scripts/managers/resource_manager.ts
export class ResourceManager {
private loadedResources: Set<string> = new Set();
public preloadCriticalResources(): Promise<void> {
return new Promise((resolve) => {
const criticalResources = [
'images/backgrounds/bg_main',
'images/characters/hero',
'audio/bgm/main',
'fonts/ad_font'
];
let loadedCount = 0;
const total = criticalResources.length;
criticalResources.forEach(path => {
cc.resources.load(path, (err) => {
if (!err) {
this.loadedResources.add(path);
}
loadedCount++;
if (loadedCount === total) resolve();
});
});
});
}
public async loadGameResources(): Promise<void> {
await this.loadImageGroup('game_assets');
await this.loadAudioGroup('game_sounds');
}
private loadImageGroup(group: string): Promise<void> {
return new Promise((resolve) => {
const imageList = this.getGroupResources(group, 'image');
cc.resources.loadDir('images/' + group, cc.SpriteFrame, (err) => {
if (!err) {
imageList.forEach(img => this.loadedResources.add(img));
}
resolve();
});
});
}
private getGroupResources(group: string, type: string): string[] {
// 从配置文件中获取资源列表
return [];
}
}
七、性能优化技巧
1. 资源加载策略
typescript
// 在开始场景中预加载
start() {
this.loadProgressBar();
ResourceManager.getInstance().preloadCriticalResources()
.then(() => {
this.showStartButton();
})
.catch(err => {
cc.error('Preload failed:', err);
});
}
private loadProgressBar() {
// 显示进度条
this.progressBar = this.node.getChildByName('progress_bar');
this.progressLabel = this.progressBar.getChildByName('label').getComponent(cc.Label);
cc.resources.onProgress = (completed, total) => {
const percent = Math.floor(completed / total * 100);
this.progressBar.width = percent * 2;
this.progressLabel.string = `${percent}%`;
};
}
2. 内存管理
typescript
// 场景切换时释放资源
onDestroy() {
// 释放本场景专用资源
const sceneResources = [
'images/game_bg',
'audio/game_bgm'
];
sceneResources.forEach(res => {
if (ResourceManager.getInstance().isLoaded(res)) {
cc.resources.release(res);
}
});
// 清理节点
this.cleanupNodes();
}
private cleanupNodes() {
// 递归清理节点
const cleanup = (node: cc.Node) => {
node.children.forEach(child => cleanup(child));
// 移除组件引用
const components = node.getComponents(cc.Component);
components.forEach(comp => {
if (comp.unregisterEvents) {
comp.unregisterEvents();
}
});
// 销毁节点
node.destroy();
};
cleanup(this.node);
}
八、提交规范
1. 最终构建结构
playable_ad_build/
├── index.html # 入口文件
├── cocos2d-js-min.js # Cocos引擎精简版
├── main.js # 游戏主逻辑
├── style.css # 样式文件(可选)
├── res/ # 资源目录
│ ├── images/ # 图片资源(WebP格式)
│ ├── audio/ # 音频资源(MP3格式)
│ └── data/ # 配置文件
└── libs/ # 第三方库(如需要)
└── ad_sdk.js # 广告平台SDK
2. 文件大小限制
-
总包大小:通常 ≤ 3MB(不同平台要求不同)
-
单个文件:≤ 500KB(避免加载阻塞)
-
解决方案:
bash# 使用命令行工具检查大小 du -h --max-depth=1 playable_ad_build find playable_ad_build -type f -size +500k -exec ls -lh {} \;
3. 提交检查清单
- 入口文件为 index.html
- 无外部资源依赖
- 所有资源在 res/ 目录下
- 总包大小 ≤ 平台限制
- 包含跳过按钮功能
- 结束页有下载引导
- 适配竖屏和横屏
- 无控制台错误日志
九、平台适配技巧
1. 多平台检测
typescript
// scripts/utils/device_utils.ts
export class DeviceUtils {
public static isIOS(): boolean {
return cc.sys.os === cc.sys.OS_IOS;
}
public static isAndroid(): boolean {
return cc.sys.os === cc.sys.OS_ANDROID;
}
public static isWechat(): boolean {
return cc.sys.platform === cc.sys.WECHAT_GAME;
}
public static isFacebook(): boolean {
return navigator.userAgent.includes('FBAN');
}
}
2. 平台特定代码
typescript
// 在游戏初始化时
initPlatformSpecificFeatures() {
if (DeviceUtils.isIOS()) {
// iOS特殊处理
this.setupIOSGestures();
} else if (DeviceUtils.isAndroid()) {
// Android特殊处理
this.setupAndroidBackButton();
}
if (DeviceUtils.isWechat()) {
// 微信小游戏适配
this.initWechatSDK();
} else if (DeviceUtils.isFacebook()) {
// Facebook Instant Games适配
this.initFacebookSDK();
}
}
十、总结
Cocos Playable 广告项目开发需要遵循严格的规范:
- 文件夹结构 :
- 清晰的资源分类(images, audio, animations)
- 模块化的脚本组织(core, managers, ui)
- 分离构建输出和临时文件
- 命名规范 :
- 全小写+下划线命名法
- 类型前缀(btn_, bg_, sfx_)
- 尺寸/时长后缀(_1080x1920, _2s)
- 性能优化 :
- WebP图片格式
- 音频压缩
- 按需加载资源
- 内存管理
- 广告要求 :
- 5秒跳过按钮
- 结束页下载引导
- 无外部依赖
- 严格大小限制
- 平台适配 :
- iOS/Android差异处理
- 社交媒体平台SDK集成
- 横竖屏适配
遵循这些规范可以确保您的Playable广告:
- 满足各大广告平台的技术要求
- 在各种设备上流畅运行
- 通过审核并高效投放
- 提供良好的用户体验和转化率