Cocos2d-x游戏开发实战完全指南:从入门到跨平台发布的完整教程

Cocos2d-x游戏开发实战完全指南:从入门到跨平台发布的完整教程

Cocos2d-x是一款开源的跨平台游戏引擎,支持iOS、Android、Windows、Mac等多个平台。它使用C++编写核心,同时支持Lua和JavaScript脚本开发。本文将从基础概念到高级特性,全面介绍Cocos2d-x游戏开发的核心技术。

一、Cocos2d-x核心概念

1.1 坐标系与屏幕原点

Cocos2d-x使用笛卡尔坐标系,但屏幕原点位于左下角(0,0),与常见的左上角坐标系不同。

1
2
3
4
5
6
        Y
|
|
(0,0)---+------- X
|
|

重要说明:

  • Cocos2d-x原点:左下角(0,0)
  • 白鹭(Egret)原点:左上角(0,0)
  • X轴向右递增,Y轴向上递增

1.2 屏幕尺寸相关概念

概念 说明 使用场景
FrameSize 设备屏幕实际分辨率 获取设备真实屏幕尺寸
WinSize 设计分辨率 游戏设计的逻辑尺寸
VisibleSize 可视区域大小 实际显示的游戏画面
VisibleOrigin 可视区域左下角坐标 确定显示区域位置

分辨率适配示例:

1
2
3
4
5
6
7
8
9
10
11
// 设置设计分辨率
Director::getInstance()->getOpenGLView()->setDesignResolutionSize(
1280, 720, ResolutionPolicy::SHOW_ALL);

// 获取设计分辨率
Size winSize = Director::getInstance()->getWinSize();
log("设计分辨率: %.2f x %.2f", winSize.width, winSize.height);

// 获取可视区域
Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();

1.3 场景(Scene)与层(Layer)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 创建场景
auto scene = Scene::create();

// 创建层
auto layer = Layer::create();
layer->setContentSize(Size(1280, 720));
scene->addChild(layer);

// 运行场景
Director::getInstance()->runWithScene(scene);

// 切换场景
Director::getInstance()->replaceScene(scene);

// 带过渡效果的场景切换
auto transition = TransitionFade::create(1.0f, scene);
Director::getInstance()->replaceScene(transition);

常用场景过渡效果:

效果类 说明
TransitionFade 淡入淡出
TransitionSlideInL/R 从左/右滑入
TransitionJumpZoom 跳跃缩放
TransitionFlipX/Y X/Y轴翻转
TransitionShrinkGrow 收缩放大

二、Action动画系统

2.1 基础动作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 移动到指定位置(绝对移动)
auto moveTo = MoveTo::create(2.0f, Vec2(300, 300));
sprite->runAction(moveTo);

// 相对移动
auto moveBy = MoveBy::create(2.0f, Vec2(100, 100));
sprite->runAction(moveBy);

// 旋转
auto rotateTo = RotateTo::create(2.0f, 180.0f);
auto rotateBy = RotateBy::create(2.0f, 90.0f);

// 缩放
auto scaleTo = ScaleTo::create(2.0f, 2.0f);
auto scaleBy = ScaleBy::create(2.0f, 1.5f);

// 透明度变化
auto fadeIn = FadeIn::create(1.0f);
auto fadeOut = FadeOut::create(1.0f);
auto fadeTo = FadeTo::create(1.0f, 128); // 半透明

// 倾斜
auto skewTo = SkewTo::create(2.0f, 30.0f, 30.0f);

// 颜色变化
auto tintTo = TintTo::create(2.0f, 255, 0, 0); // 变红

2.2 跳跃与贝塞尔曲线

1
2
3
4
5
6
7
8
9
10
11
12
// 跳跃动作
auto jumpTo = JumpTo::create(2.0f, Vec2(300, 300), 100, 3);
// 参数:持续时间,目标位置,跳跃高度,跳跃次数

// 贝塞尔曲线
ccBezierConfig bezier;
bezier.controlPoint_1 = Vec2(0, 0);
bezier.controlPoint_2 = Vec2(300, 300);
bezier.endPosition = Vec2(600, 0);

auto bezierTo = BezierTo::create(3.0f, bezier);
sprite->runAction(bezierTo);

2.3 动作组合与序列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 动作序列(按顺序执行)
auto move = MoveBy::create(1.0f, Vec2(100, 0));
auto rotate = RotateBy::create(1.0f, 90.0f);
auto sequence = Sequence::create(move, rotate, nullptr);
sprite->runAction(sequence);

// 动作并列(同时执行)
auto spawn = Spawn::create(move, rotate, nullptr);
sprite->runAction(spawn);

// 动作重复
auto repeat = Repeat::create(sequence, 3);
auto repeatForever = RepeatForever::create(rotate);

// 动作逆序
auto reverse = sequence->reverse();

// 动作延时
cocos2d::DelayTime::create(1.0f);

// 动作回调
auto callback = CallFunc::create([=](){
log("动作完成!");
});
auto seqWithCallback = Sequence::create(move, callback, nullptr);

2.4 缓动效果(Easing)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 线性(默认)
auto linear = MoveTo::create(2.0f, Vec2(300, 300));

// 渐入
auto easeIn = EaseIn::create(linear->clone(), 2.0f);

// 渐出
auto easeOut = EaseOut::create(linear->clone(), 2.0f);

// 渐入渐出
auto easeInOut = EaseInOut::create(linear->clone(), 2.0f);

// 弹性效果
auto easeElasticIn = EaseElasticIn::create(linear->clone());
auto easeElasticOut = EaseElasticOut::create(linear->clone());

// 弹跳效果
auto easeBounceIn = EaseBounceIn::create(linear->clone());
auto easeBounceOut = EaseBounceOut::create(linear->clone());

// 指数加速/减速
auto easeExponentialIn = EaseExponentialIn::create(linear->clone());
auto easeExponentialOut = EaseExponentialOut::create(linear->clone());

// 正弦波
auto easeSineIn = EaseSineIn::create(linear->clone());
auto easeSineOut = EaseSineOut::create(linear->clone());

缓动效果对比:

缓动类型 效果描述 适用场景
EaseIn 开始慢,结束快 加速运动
EaseOut 开始快,结束慢 减速运动
EaseInOut 开始和结束慢,中间快 自然的运动
EaseElastic 弹性效果 弹跳动画
EaseBounce 弹跳效果 物体落地
EaseExponential 指数变化 急速加速/减速

2.5 动作速度控制

1
2
3
4
5
6
7
8
9
// 加速
auto speedUp = Speed::create(action, 2.0f);

// 减速
auto speedDown = Speed::create(action, 0.5f);

// 变速
auto speedAction = Speed::create(action, 3.0f);
speedAction->setSpeed(1.5f);

三、触摸与事件处理

3.1 单点触摸

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 创建事件监听器
auto touchListener = EventListenerTouchOneByOne::create();

// 设置触摸回调
touchListener->onTouchBegan = [=](Touch* touch, Event* event) {
Vec2 location = touch->getLocation();
log("触摸开始: (%.2f, %.2f)", location.x, location.y);
return true; // 返回true继续接收触摸事件
};

touchListener->onTouchMoved = [=](Touch* touch, Event* event) {
Vec2 location = touch->getLocation();
Vec2 delta = touch->getDelta(); // 移动距离
log("触摸移动: (%.2f, %.2f), 移动: (%.2f, %.2f)",
location.x, location.y, delta.x, delta.y);
};

touchListener->onTouchEnded = [=](Touch* touch, Event* event) {
log("触摸结束");
};

touchListener->onTouchCancelled = [=](Touch* touch, Event* event) {
log("触摸取消");
};

// 注册监听器
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);

3.2 多点触摸

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
auto touchListener = EventListenerTouchAllAtOnce::create();

touchListener->onTouchesBegan = [=](const std::vector<Touch*>& touches, Event* event) {
log("触摸点数: %zu", touches.size());
for (auto touch : touches) {
log("Touch ID: %d, Location: (%.2f, %.2f)",
touch->getID(), touch->getLocation().x, touch->getLocation().y);
}
};

touchListener->onTouchesMoved = [=](const std::vector<Touch*>& touches, Event* event) {
if (touches.size() >= 2) {
// 计算两点距离(缩放)
float distance = touches[0]->getLocation().distance(touches[1]->getLocation());
log("两点距离: %.2f", distance);
}
};

_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);

3.3 键盘事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
auto keyboardListener = EventListenerKeyboard::create();

keyboardListener->onKeyPressed = [=](EventKeyboard::KeyCode keyCode, Event* event) {
switch (keyCode) {
case EventKeyboard::KeyCode::KEY_LEFT_ARROW:
log("左键按下");
break;
case EventKeyboard::KeyCode::KEY_RIGHT_ARROW:
log("右键按下");
break;
case EventKeyboard::KeyCode::KEY_SPACE:
log("空格键按下");
break;
default:
break;
}
};

keyboardListener->onKeyReleased = [=](EventKeyboard::KeyCode keyCode, Event* event) {
log("按键释放: %d", keyCode);
};

_eventDispatcher->addEventListenerWithSceneGraphPriority(keyboardListener, this);

3.4 鼠标事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
auto mouseListener = EventListenerMouse::create();

mouseListener->onMouseMove = [=](Event* event) {
EventMouse* e = (EventMouse*)event;
log("鼠标移动: (%.2f, %.2f)", e->getCursorX(), e->getCursorY());
};

mouseListener->onMouseDown = [=](Event* event) {
EventMouse* e = (EventMouse*)event;
log("鼠标按下: %d", e->getMouseButton());
};

mouseListener->onMouseUp = [=](Event* event) {
EventMouse* e = (EventMouse*)event;
log("鼠标释放");
};

mouseListener->onMouseScroll = [=](Event* event) {
EventMouse* e = (EventMouse*)event;
log("滚轮滚动: %.2f", e->getScrollY());
};

_eventDispatcher->addEventListenerWithSceneGraphPriority(mouseListener, this);

四、物理引擎集成

4.1 Chipmunk物理引擎基础

1
2
3
4
5
6
7
8
9
10
#include "cocos2d.h"
#include "chipmunk/chipmunk.h"

// 创建物理世界
PhysicsWorld* world = scene->getPhysicsWorld();
world->setGravity(Vec2(0, -980)); // 重力加速度
world->setSpeed(3.0f); // 模拟速度

// 开启调试绘制
world->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);

4.2 创建物理体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 创建刚体
auto body = PhysicsBody::createCircle(50.0f);
body->setDynamic(true); // 动态刚体
body->setMass(1.0f);
body->setMoment(PHYSICS_INFINITY); // 无限转动惯量(不旋转)
body->setVelocity(Vec2(100, 0));
body->setAngularVelocity(90);

// 创建精灵并绑定刚体
auto sprite = Sprite::create("ball.png");
sprite->setPhysicsBody(body);
sprite->setPosition(visibleSize.width/2, visibleSize.height/2);
this->addChild(sprite);

// 静态刚体(如地面)
auto groundBody = PhysicsBody::createEdgeBox(visibleSize, PhysicsMaterial(1.0f, 0.0f, 1.0f));
groundBody->setDynamic(false); // 静态刚体

auto edgeNode = Node::create();
edgeNode->setPosition(visibleSize.width/2, visibleSize.height/2);
edgeNode->setPhysicsBody(groundBody);
this->addChild(edgeNode);

4.3 碰撞检测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 设置碰撞回调
auto contactListener = EventListenerPhysicsContact::create();

contactListener->onContactBegin = [=](PhysicsContact& contact) {
auto shapeA = contact.getShapeA();
auto shapeB = contact.getShapeB();

auto bodyA = shapeA->getBody();
auto bodyB = shapeB->getBody();

auto nodeA = bodyA->getNode();
auto nodeB = bodyB->getNode();

log("碰撞检测: %s vs %s",
nodeA ? nodeA->getName().c_str() : "null",
nodeB ? nodeB->getName().c_str() : "null");

return true; // 返回true继续处理碰撞
};

contactListener->onContactPreSolve = [=](PhysicsContact& contact, PhysicsContactPreSolve& solve) {
// 预碰撞处理
return true;
};

contactListener->onContactPostSolve = [=](PhysicsContact& contact, const PhysicsContactPostSolve& solve) {
// 碰撞后处理
};

contactListener->onContactSeparate = [=](PhysicsContact& contact) {
// 碰撞分离
};

_eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);

4.4 关节连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 创建两个刚体
auto body1 = PhysicsBody::createBox(Size(50, 50));
auto body2 = PhysicsBody::createBox(Size(50, 50));

// 距离关节
auto distanceJoint = PhysicsJointDistance::construct(body1, body2,
Vec2::ZERO, Vec2::ZERO, 100.0f);
world->addJoint(distanceJoint);

// 旋转关节
auto pivotJoint = PhysicsJointPin::construct(body1, body2,
Vec2(visibleSize.width/2, visibleSize.height/2));
world->addJoint(pivotJoint);

// 弹簧关节
auto springJoint = PhysicsJointSpring::construct(body1, body2,
Vec2::ZERO, Vec2::ZERO, 500.0f, 0.3f);
world->addJoint(springJoint);

五、Android平台打包发布

5.1 开发环境配置

Android Studio配置:

  1. 安装Android Studio和SDK
  2. 配置NDK(推荐r21e版本)
  3. 设置环境变量:
1
2
3
export ANDROID_SDK_ROOT=/path/to/android-sdk
export ANDROID_NDK_ROOT=/path/to/android-ndk
export PATH=$PATH:$ANDROID_SDK_ROOT/tools:$ANDROID_SDK_ROOT/platform-tools

Cocos2d-x项目配置:

1
2
3
4
5
6
7
8
# 进入项目目录
cd MyGame

# 生成Android项目
cocos compile -p android

# 或者使用Android Studio打开
# proj.android-studio 目录

5.2 Android.mk配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

$(call import-add-path,$(LOCAL_PATH)/../../../cocos2d)
$(call import-add-path,$(LOCAL_PATH)/../../../cocos2d/external)
$(call import-add-path,$(LOCAL_PATH)/../../../cocos2d/cocos)

LOCAL_MODULE := MyGame_shared

LOCAL_MODULE_FILENAME := libMyGame

# 源文件
LOCAL_SRC_FILES := hellocpp/main.cpp \
../../Classes/AppDelegate.cpp \
../../Classes/HelloWorldScene.cpp

# 头文件路径
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes

# 静态库
LOCAL_STATIC_LIBRARIES := cocos2dx_static

include $(BUILD_SHARED_LIBRARY)

$(call import-module,.)

5.3 AndroidManifest.xml配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.mygame">

<!-- OpenGL ES 2.0 -->
<uses-feature android:glEsVersion="0x00020000" />

<!-- 权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

<application
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen">

<!-- 主Activity -->
<activity
android:name="org.cocos2dx.cpp.AppActivity"
android:screenOrientation="landscape"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

5.4 构建与发布

Gradle构建配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
android {
compileSdkVersion 30
buildToolsVersion "30.0.3"

defaultConfig {
applicationId "com.example.mygame"
minSdkVersion 16
targetSdkVersion 30
versionCode 1
versionName "1.0"
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}

externalNativeBuild {
ndkBuild {
path 'Android.mk'
}
}
}

构建命令:

1
2
3
4
5
6
7
8
# 编译debug版本
cocos compile -p android -j4

# 编译release版本(需要签名)
cocos compile -p android --release --sign-bundle

# Android Studio构建
./gradlew assembleRelease

5.5 JNI调用Java代码

1
2
3
4
5
6
7
8
9
// 调用Java方法
JniMethodInfo t;
if (JniHelper::getStaticMethodInfo(t,
"org/cocos2dx/cpp/AppActivity", // Java类路径
"showAd", // Java方法名
"()V")) { // 方法签名
t.env->CallStaticVoidMethod(t.classID, t.methodID);
t.env->DeleteLocalRef(t.classID);
}

对应的Java代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
package org.cocos2dx.cpp;

public class AppActivity extends Cocos2dxActivity {

public static void showAd() {
// 显示广告
Log.d("Cocos2d-x", "Show Ad");
}

public static void submitScore(int score) {
// 提交分数到排行榜
}
}

六、性能优化技巧

6.1 渲染优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 启用自动裁剪
Director::getInstance()->setProjection(Director::Projection::DEFAULT);
Director::getInstance()->setAnimationInterval(1.0f / 60); // 60fps

// 批量渲染(使用SpriteBatchNode)
auto batch = SpriteBatchNode::create("batch.png");
for (int i = 0; i < 100; i++) {
auto sprite = Sprite::createWithTexture(batch->getTexture());
batch->addChild(sprite);
}
this->addChild(batch);

// 对象池复用
Vector<Sprite*> pool;
// 使用时从池中取出,使用完毕后放回池中

6.2 内存优化

1
2
3
4
5
6
7
8
9
10
11
12
13
// 使用纹理缓存
auto cache = Director::getInstance()->getTextureCache();
auto texture = cache->addImage("image.png");

// 释放不用的纹理
cache->removeUnusedTextures();

// 场景切换时清理
Director::getInstance()->getTextureCache()->removeAllTextures();

// 使用autorelease
auto sprite = Sprite::create("image.png");
sprite->autorelease();

6.3 常见优化策略

优化项 优化前 优化后 效果
Draw Call 500 < 100 渲染性能提升
纹理内存 200MB < 100MB 减少内存占用
物理体数量 无限制 < 100 提升物理性能
同时播放音效 32 < 16 减少音频资源占用

七、总结

Cocos2d-x作为一款成熟的跨平台游戏引擎,具有以下优势:

  1. 性能优异:基于C++开发,运行效率高
  2. 跨平台:一次开发,多平台发布
  3. 开源免费:MIT协议,无授权费用
  4. 文档丰富:社区活跃,资料充足
  5. 工具链完善:Cocos Studio、Cocos Creator等可视化工具

在游戏开发过程中,建议:

  • 合理规划资源:控制纹理大小和数量
  • 优化渲染性能:减少Draw Call,使用合图
  • 内存管理:及时释放不用的资源
  • 多分辨率适配:使用相对坐标和百分比布局
  • 物理引擎优化:控制刚体数量,使用触发器代替碰撞检测

通过本文的学习,相信读者已经掌握了Cocos2d-x游戏开发的核心技术,可以开始自己的游戏开发之旅。