Cocos Creator Playable 广告项目文件夹结构与命名规范

Cocos Creator Playable 广告项目文件夹结构与命名规范

Playable 广告(可玩广告)在 Cocos Creator 中的开发需要遵循特定的文件夹结构和命名规则,以满足广告平台的技术要求和性能优化需求。以下是完整的规范指南:

一、文件夹命名规则

1. 基本原则

  • 全小写字母:所有文件夹名使用小写字母
  • 下划线分隔 :使用下划线 _ 代替空格
  • 简洁明确:名称应反映内容
  • 避免特殊字符:不使用中文、空格、特殊符号

2. 禁止使用的名称

  • adads(可能被广告拦截器屏蔽)
  • systemwindows(操作系统保留名称)
  • 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. 资源命名规范

  • 图片资源:

    复制代码
    [类型]_[名称]_[尺寸].webp
    • bg_main_1080x1920.webp
    • btn_play_200x80.webp
  • 音频资源:

    复制代码
    [类型]_[名称]_[时长]s.mp3
    • sfx_click_1s.mp3
    • bgm_main_30s.mp3
  • 动画资源:

    复制代码
    [对象]_[动作].clip
    • hero_jump.clip
    • ui_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. 提交检查清单

  1. 入口文件为 index.html
  2. 无外部资源依赖
  3. 所有资源在 res/ 目录下
  4. 总包大小 ≤ 平台限制
  5. 包含跳过按钮功能
  6. 结束页有下载引导
  7. 适配竖屏和横屏
  8. 无控制台错误日志

九、平台适配技巧

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 广告项目开发需要遵循严格的规范:

  1. 文件夹结构
    • 清晰的资源分类(images, audio, animations)
    • 模块化的脚本组织(core, managers, ui)
    • 分离构建输出和临时文件
  2. 命名规范
    • 全小写+下划线命名法
    • 类型前缀(btn_, bg_, sfx_)
    • 尺寸/时长后缀(_1080x1920, _2s)
  3. 性能优化
    • WebP图片格式
    • 音频压缩
    • 按需加载资源
    • 内存管理
  4. 广告要求
    • 5秒跳过按钮
    • 结束页下载引导
    • 无外部依赖
    • 严格大小限制
  5. 平台适配
    • iOS/Android差异处理
    • 社交媒体平台SDK集成
    • 横竖屏适配

遵循这些规范可以确保您的Playable广告:

  • 满足各大广告平台的技术要求
  • 在各种设备上流畅运行
  • 通过审核并高效投放
  • 提供良好的用户体验和转化率
相关推荐
怣疯knight1 天前
Cocos creator如何使用onCollisionEnter或者onTriggerEnter
cocos2d
怣疯knight3 天前
Cocos creator判断节点是否能用的方法
unity·cocos2d
Doc.S4 天前
多无人机任务自定义(基于ZJU-FAST-Lab / EGO-Planner-v2)
游戏引擎·无人机·cocos2d
天途小编4 天前
无人机操控模式解析:美国手、日本手、中国手
游戏引擎·无人机·cocos2d
Unity打怪升级8 天前
【Unity精品源码】Ultimate Character Controller:高级角色控制器完整解决方案
游戏·unity·ue5·游戏引擎·godot·游戏程序·cocos2d
7***n7523 天前
C++在游戏中的Cocos2d-x
游戏·游戏引擎·cocos2d
Marvin_Kai23 天前
Cocos Creator 3.x 实现“粒子特效” 的 点击触发
cocos2d
胡童嘉1 个月前
长沙烈焰鸟网络科技有限公司实习day13日记
功能测试·学习·职场和发展·游戏引擎·cocos2d
神秘的土鸡1 个月前
【CS创世SD NAND征文】为无人机打造可靠数据仓:工业级存储芯片CSNP32GCR01-AOW在飞控系统中的应用实践
嵌入式硬件·游戏引擎·无人机·cocos2d·雷龙