本文摘要介绍了Cocos Creator 2.x游戏开发中的多项关键技术:
1.异步编程:通过Promise和async/await处理异步操作;
2.高级UI组件:包括进度条、滚动视图和切换按钮的实现;
3.物理系统:碰撞检测、射线检测和物理关节的应用;
4.音频系统:AudioSource组件的使用方法;
5.设计模式:状态管理器和对象池模式的实现;
6.数据持久化:利用localStorage存储游戏数据;
7.网络请求:封装HTTP请求的实现;
8.性能优化:渲染和资源优化技巧;
9.调试工具:性能监控和调试绘制的实现。这些技术点为Cocos Creator游戏开发提供了全面的解决方案。
1 Promise与异步编程
1.1 Promise基础
// 创建Promise
const promise = new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => {
const success = true;
if (success) {
resolve('操作成功');
} else {
reject('操作失败');
}
}, 1000);
});
// 使用Promise
promise.then(result => {
console.log(result); // 操作成功
}).catch(error => {
console.error(error); // 操作失败
});
1.2 Promise链式调用
// 加载资源的链式调用
cc.loader.loadRes('texture1', cc.SpriteFrame)
.then(spriteFrame1 => {
console.log('第一张图加载完成');
return cc.loader.loadRes('texture2', cc.SpriteFrame);
})
.then(spriteFrame2 => {
console.log('第二张图加载完成');
return cc.loader.loadRes('texture3', cc.SpriteFrame);
})
.then(spriteFrame3 => {
console.log('所有资源加载完成');
})
.catch(error => {
console.error('加载失败:', error);
});
1.3 async/await语法
// 异步函数
async function loadResources() {
try {
const spriteFrame1 = await cc.loader.loadRes('texture1', cc.SpriteFrame);
const spriteFrame2 = await cc.loader.loadRes('texture2', cc.SpriteFrame);
const spriteFrame3 = await cc.loader.loadRes('texture3', cc.SpriteFrame);
console.log('所有资源加载完成');
} catch (error) {
console.error('加载失败:', error);
}
}
// 调用异步函数
loadResources();
2 高级UI组件
2.1 ProgressBar进度条
cc.Class({
extends: cc.Component,
properties: {
progressBar: cc.ProgressBar,
targetProgress: 100
},
start() {
// 设置进度条属性
this.progressBar.totalLength = 200;
this.progressBar.progress = 0;
// 开始加载动画
this.startLoading();
},
startLoading() {
let currentProgress = 0;
const interval = setInterval(() => {
currentProgress += 5;
this.progressBar.progress = currentProgress / this.targetProgress;
if (currentProgress >= this.targetProgress) {
clearInterval(interval);
console.log('加载完成');
}
}, 100);
}
});
2.2 ScrollView滚动视图
cc.Class({
extends: cc.Component,
properties: {
scrollView: cc.ScrollView,
content: cc.Node,
itemPrefab: cc.Prefab
},
start() {
// 初始化滚动视图
this.scrollView.horizontal = false;
this.scrollView.vertical = true;
this.scrollView.bounceEnabled = true;
this.scrollView.inertia = true;
// 创建列表项
this.createListItems();
},
createListItems() {
const itemHeight = 50;
const itemCount = 20;
for (let i = 0; i < itemCount; i++) {
const item = cc.instantiate(this.itemPrefab);
item.parent = this.content;
item.y = -i * itemHeight;
// 设置列表项内容
const label = item.getComponent(cc.Label);
if (label) {
label.string = `列表项 ${i + 1}`;
}
}
// 更新content大小
this.content.height = itemCount * itemHeight;
}
});
2.3 Toggle切换按钮
cc.Class({
extends: cc.Component,
properties: {
toggle: cc.Toggle,
toggleGroup: cc.ToggleGroup
},
start() {
// 设置ToggleGroup
this.toggle.group = this.toggleGroup;
// 添加事件监听
this.toggle.node.on('toggle', this.onToggle, this);
},
onToggle(event) {
const toggle = event.target.getComponent(cc.Toggle);
if (toggle.isChecked) {
console.log('Toggle已选中');
} else {
console.log('Toggle已取消选中');
}
}
});
3 物理系统详解
3.1 碰撞检测
cc.Class({
extends: cc.Component,
onLoad() {
const collider = this.node.getComponent(cc.Collider2D);
if (collider) {
// 监听碰撞事件
collider.on('begin-contact', this.onBeginContact, this);
collider.on('end-contact', this.onEndContact, this);
collider.on('pre-solve', this.onPreSolve, this);
collider.on('post-solve', this.onPostSolve, this);
}
},
onBeginContact(contact, selfCollider, otherCollider) {
console.log('开始碰撞:', otherCollider.node.name);
// 获取碰撞点
const worldManifold = contact.getWorldManifold();
const points = worldManifold.points;
console.log('碰撞点:', points);
},
onEndContact(contact, selfCollider, otherCollider) {
console.log('结束碰撞:', otherCollider.node.name);
},
onPreSolve(contact, selfCollider, otherCollider) {
// 可以在这里修改碰撞结果
// contact.setEnabled(false); // 禁用碰撞
},
onPostSolve(contact, selfCollider, otherCollider) {
// 碰撞处理后的回调
}
});
3.2 射线检测
cc.Class({
extends: cc.Component,
start() {
// 创建射线
const start = cc.v2(0, 0);
const end = cc.v2(200, 200);
// 执行射线检测
const results = cc.director.getPhysicsManager().rayCast(start, end);
if (results.length > 0) {
console.log('检测到碰撞:', results.length);
results.forEach(result => {
console.log('碰撞对象:', result.collider.node.name);
console.log('碰撞点:', result.point);
});
}
}
});
3.3 物理关节
cc.Class({
extends: cc.Component,
properties: {
connectedBody: cc.RigidBody2D
},
start() {
const rigidBody = this.node.getComponent(cc.RigidBody2D);
// 创建距离关节
const joint = this.node.addComponent(cc.DistanceJoint2D);
joint.connectedBody = this.connectedBody;
joint.distance = 100;
joint.dampingRatio = 0.5;
joint.frequency = 2;
}
});
4 音频系统
4.1 AudioSource组件
cc.Class({
extends: cc.Component,
properties: {
bgmClip: cc.AudioClip,
sfxClip: cc.AudioClip
},
onLoad() {
// 添加AudioSource组件
this.audioSource = this.node.addComponent(cc.AudioSource);
},
start() {
// 播放背景音乐
this.playBGM();
},
playBGM() {
this.audioSource.clip = this.bgmClip;
this.audioSource.loop = true;
this.audioSource.volume = 0.5;
this.audioSource.play();
},
playSFX() {
// 播放音效(使用临时音频源)
cc.audioEngine.play(this.sfxClip, false, 0.8);
},
stopAudio() {
this.audioSource.stop();
},
pauseAudio() {
this.audioSource.pause();
},
resumeAudio() {
this.audioSource.resume();
}
});
5 状态管理器模式
5.1 游戏状态管理
// 状态枚举
const GameState = {
MENU: 'menu',
PLAYING: 'playing',
PAUSED: 'paused',
GAMEOVER: 'gameover'
};
cc.Class({
extends: cc.Component,
properties: {
currentState: {
default: GameState.MENU,
visible: false
}
},
onLoad() {
// 注册状态监听
this.stateListeners = {};
},
// 添加状态监听
addStateListener(state, callback) {
if (!this.stateListeners[state]) {
this.stateListeners[state] = [];
}
this.stateListeners[state].push(callback);
},
// 移除状态监听
removeStateListener(state, callback) {
if (this.stateListeners[state]) {
const index = this.stateListeners[state].indexOf(callback);
if (index > -1) {
this.stateListeners[state].splice(index, 1);
}
}
},
// 切换状态
changeState(newState) {
if (this.currentState === newState) return;
const previousState = this.currentState;
this.currentState = newState;
console.log(`状态切换: ${previousState} -> ${newState}`);
// 通知所有监听者
if (this.stateListeners[newState]) {
this.stateListeners[newState].forEach(callback => {
callback(newState);
});
}
// 执行状态切换逻辑
this.onStateChanged(previousState, newState);
},
// 状态切换处理
onStateChanged(previousState, newState) {
switch (newState) {
case GameState.MENU:
this.enterMenu();
break;
case GameState.PLAYING:
this.enterPlaying();
break;
case GameState.PAUSED:
this.enterPaused();
break;
case GameState.GAMEOVER:
this.enterGameOver();
break;
}
},
enterMenu() {
cc.log('进入菜单状态');
},
enterPlaying() {
cc.log('进入游戏状态');
},
enterPaused() {
cc.log('进入暂停状态');
},
enterGameOver() {
cc.log('进入游戏结束状态');
}
});
6 对象池模式
6.1 实现对象池
// 对象池管理类
const ObjectPool = (function() {
const pools = {};
return {
// 获取对象池
getPool(poolName) {
if (!pools[poolName]) {
pools[poolName] = {
objects: [],
prefab: null
};
}
return pools[poolName];
},
// 初始化对象池
initPool(poolName, prefab, count) {
const pool = this.getPool(poolName);
pool.prefab = prefab;
// 预创建对象
for (let i = 0; i < count; i++) {
const obj = cc.instantiate(prefab);
obj.active = false;
pool.objects.push(obj);
}
},
// 获取对象
getObject(poolName) {
const pool = this.getPool(poolName);
// 如果有空闲对象,直接返回
if (pool.objects.length > 0) {
const obj = pool.objects.pop();
obj.active = true;
return obj;
}
// 如果没有,创建新对象
const obj = cc.instantiate(pool.prefab);
obj.active = true;
return obj;
},
// 回收对象
recycleObject(poolName, obj) {
const pool = this.getPool(poolName);
obj.active = false;
obj.setPosition(0, 0);
pool.objects.push(obj);
},
// 清理对象池
clearPool(poolName) {
const pool = this.getPool(poolName);
pool.objects.forEach(obj => {
obj.destroy();
});
pool.objects = [];
}
};
})();
// 使用对象池
cc.Class({
extends: cc.Component,
properties: {
bulletPrefab: cc.Prefab,
container: cc.Node
},
start() {
// 初始化对象池
ObjectPool.initPool('bullets', this.bulletPrefab, 10);
},
fireBullet() {
// 获取对象
const bullet = ObjectPool.getObject('bullets');
bullet.parent = this.container;
bullet.setPosition(0, 0);
// 2秒后回收
setTimeout(() => {
ObjectPool.recycleObject('bullets', bullet);
}, 2000);
}
});
7 数据持久化
7.1 localStorage存储
cc.Class({
extends: cc.Component,
// 保存数据
saveData(key, data) {
try {
const jsonStr = JSON.stringify(data);
localStorage.setItem(key, jsonStr);
cc.log('数据保存成功');
} catch (error) {
cc.error('数据保存失败:', error);
}
},
// 读取数据
loadData(key) {
try {
const jsonStr = localStorage.getItem(key);
if (jsonStr) {
return JSON.parse(jsonStr);
}
return null;
} catch (error) {
cc.error('数据读取失败:', error);
return null;
}
},
// 删除数据
deleteData(key) {
localStorage.removeItem(key);
},
// 示例:保存游戏进度
saveGameProgress(progress) {
this.saveData('gameProgress', progress);
},
// 示例:加载游戏进度
loadGameProgress() {
return this.loadData('gameProgress');
}
});
8 网络请求
8.1 HTTP请求封装
cc.Class({
extends: cc.Component,
// GET请求
get(url, params = {}) {
return new Promise((resolve, reject) => {
// 拼接参数
const queryString = Object.keys(params)
.map(key => `${key}=${encodeURIComponent(params[key])}`)
.join('&');
const fullUrl = queryString ? `${url}?${queryString}` : url;
const xhr = new XMLHttpRequest();
xhr.open('GET', fullUrl, true);
xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 300) {
try {
const response = JSON.parse(xhr.responseText);
resolve(response);
} catch (error) {
reject(error);
}
} else {
reject(new Error(xhr.statusText));
}
};
xhr.onerror = () => {
reject(new Error('网络请求失败'));
};
xhr.send();
});
},
// POST请求
post(url, data = {}) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 300) {
try {
const response = JSON.parse(xhr.responseText);
resolve(response);
} catch (error) {
reject(error);
}
} else {
reject(new Error(xhr.statusText));
}
};
xhr.onerror = () => {
reject(new Error('网络请求失败'));
};
xhr.send(JSON.stringify(data));
});
},
// 示例:获取排行榜
async getLeaderboard() {
try {
const response = await this.get('https://api.example.com/leaderboard', {
limit: 10
});
console.log('排行榜数据:', response);
return response;
} catch (error) {
console.error('获取排行榜失败:', error);
throw error;
}
},
// 示例:提交分数
async submitScore(score) {
try {
const response = await this.post('https://api.example.com/submit', {
score: score,
playerId: 'player123'
});
console.log('提交结果:', response);
return response;
} catch (error) {
console.error('提交分数失败:', error);
throw error;
}
}
});
9 性能优化技巧
9.1 渲染优化
cc.Class({
extends: cc.Component,
start() {
// 合并静态对象
this.mergeStaticObjects();
// 设置LOD
this.setupLOD();
},
// 合并静态对象
mergeStaticObjects() {
const renderers = this.node.getComponentsInChildren(cc.Sprite);
const materialGroups = {};
// 按材质分组
renderers.forEach(renderer => {
const material = renderer.getMaterial(0);
const key = material.name;
if (!materialGroups[key]) {
materialGroups[key] = [];
}
materialGroups[key].push(renderer);
});
console.log(`材质组数: ${Object.keys(materialGroups).length}`);
console.log(`总渲染器数: ${renderers.length}`);
},
// 设置LOD
setupLOD() {
const lodGroup = this.node.addComponent(cc.LODGroup);
lodGroup.levels = [
{
screenRelativeTransitionHeight: 0.5,
renderers: [this.getComponent(cc.Sprite)]
},
{
screenRelativeTransitionHeight: 0.2,
renderers: [] // 使用简化版本
}
];
}
});
9.2 资源优化
cc.Class({
extends: cc.Component,
properties: {
cachedResources: {
default: {},
visible: false
}
},
// 缓存资源
async loadAndCache(path, type) {
const key = `${path}_${type.name}`;
// 如果已缓存,直接返回
if (this.cachedResources[key]) {
return this.cachedResources[key];
}
// 加载资源
return new Promise((resolve, reject) => {
cc.loader.loadRes(path, type, (err, asset) => {
if (err) {
reject(err);
return;
}
// 缓存资源
this.cachedResources[key] = asset;
resolve(asset);
});
});
},
// 释放缓存
releaseCache(path, type) {
const key = `${path}_${type.name}`;
if (this.cachedResources[key]) {
cc.loader.releaseRes(path, type);
delete this.cachedResources[key];
}
},
// 清空所有缓存
clearAllCache() {
Object.keys(this.cachedResources).forEach(key => {
cc.loader.releaseAsset(this.cachedResources[key]);
});
this.cachedResources = {};
}
});
10 调试工具
10.1 性能监控
cc.Class({
extends: cc.Component,
properties: {
fpsLabel: cc.Label,
drawCallsLabel: cc.Label
},
start() {
// 开启性能监控
this.schedule(this.updatePerformance, 1);
},
updatePerformance() {
// 获取帧率
const fps = cc.game.getFrameRate();
this.fpsLabel.string = `FPS: ${fps}`;
// 获取Draw Call数量
const drawCalls = cc.renderer.drawCalls;
this.drawCallsLabel.string = `Draw Calls: ${drawCalls}`;
},
onDestroy() {
this.unschedule(this.updatePerformance);
}
});
10.2 调试绘制
cc.Class({
extends: cc.Component,
start() {
// 注册渲染回调
cc.director.on('render', this.onRender, this);
},
onRender() {
// 绘制调试信息
const ctx = cc.renderer.getContext();
// 绘制线段
ctx.strokeStyle = '#ff0000';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(100, 100);
ctx.lineTo(200, 200);
ctx.stroke();
// 绘制矩形
ctx.strokeStyle = '#00ff00';
ctx.strokeRect(300, 100, 100, 100);
// 绘制文字
ctx.fillStyle = '#0000ff';
ctx.font = '20px Arial';
ctx.fillText('调试信息', 100, 300);
},
onDestroy() {
cc.director.off('render', this.onRender, this);
}
});
总结
通过本章的补充扩展,你应该掌握了:
-
异步编程:Promise、async/await的使用
-
高级UI组件:ProgressBar、ScrollView、Toggle的使用
-
物理系统:碰撞检测、射线检测、物理关节
-
音频系统:AudioSource组件的使用
-
设计模式:状态管理器、对象池模式
-
数据持久化:localStorage的使用
-
网络请求:HTTP请求封装
-
性能优化:渲染优化、资源优化
-
调试工具:性能监控、调试绘制
这些内容可以帮助你更好地理解和使用Cocos Creator 2.x进行游戏开发!