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 ; }; 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 ; }; 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配置:
安装Android Studio和SDK
配置NDK(推荐r21e版本)
设置环境变量:
1 2 3 export ANDROID_SDK_ROOT=/path/to/android-sdkexport ANDROID_NDK_ROOT=/path/to/android-ndkexport PATH=$PATH :$ANDROID_SDK_ROOT /tools:$ANDROID_SDK_ROOT /platform-tools
Cocos2d-x项目配置:
1 2 3 4 5 6 7 8 cd MyGamecocos compile -p android
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" > <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 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 cocos compile -p android -j4 cocos compile -p android --release --sign-bundle ./gradlew assembleRelease
5.5 JNI调用Java代码 1 2 3 4 5 6 7 8 9 JniMethodInfo t; if (JniHelper::getStaticMethodInfo (t, "org/cocos2dx/cpp/AppActivity" , "showAd" , "()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 ); 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 (); auto sprite = Sprite::create ("image.png" );sprite->autorelease ();
6.3 常见优化策略
优化项
优化前
优化后
效果
Draw Call
500
< 100
渲染性能提升
纹理内存
200MB
< 100MB
减少内存占用
物理体数量
无限制
< 100
提升物理性能
同时播放音效
32
< 16
减少音频资源占用
七、总结 Cocos2d-x作为一款成熟的跨平台游戏引擎,具有以下优势:
性能优异 :基于C++开发,运行效率高
跨平台 :一次开发,多平台发布
开源免费 :MIT协议,无授权费用
文档丰富 :社区活跃,资料充足
工具链完善 :Cocos Studio、Cocos Creator等可视化工具
在游戏开发过程中,建议:
合理规划资源 :控制纹理大小和数量
优化渲染性能 :减少Draw Call,使用合图
内存管理 :及时释放不用的资源
多分辨率适配 :使用相对坐标和百分比布局
物理引擎优化 :控制刚体数量,使用触发器代替碰撞检测
通过本文的学习,相信读者已经掌握了Cocos2d-x游戏开发的核心技术,可以开始自己的游戏开发之旅。