在2020年学习cocos游戏引擎
常用鏈接
Cocos2d-x 用戶手冊
參考書目
《Cocos2d-X游戲開發實戰精解》
《我所理解的Cocos2d-x》
《Effective C++》中文版第三版
環境搭建
macOS 10.15.6
Xcode 11.5
cocos2d-x 3.17.2
cmake 3.17.3
創建工程
采用cocos2d-x 3.17版本可直接通過cocos console創建,4.0版本需要額外通過cmake生成.xcodeproj文件。
cocos new 工程名 -p com.cocos2dx.工程名 -l cpp -d 目錄名(/Users/xxx)架構分析
目錄分析
Classes存放邏輯代碼,Resource存放資源文件
C++文件由.hpp(聲明)和.cpp(定義及初始化)組成
AppDelegate.h
#ifndef _APP_DELEGATE_H_ // 宏定義 保證頭文件不需要多次編譯 #define _APP_DELEGATE_H_#include "cocos2d.h"class AppDelegate : private cocos2d::Application { public:AppDelegate(); // 構造virtual ~AppDelegate(); // 虛析構virtual void initGLContextAttrs(); // 初始化openGL參數virtual bool applicationDidFinishLaunching(); // 應用進入virtual void applicationDidEnterBackground(); // 應用中途退入后臺virtual void applicationWillEnterForeground(); // 應用中途來電// 虛析構函數能夠保證當用一個基類的指針刪除一個派生類的對象時,派生類的析構函數會被調用// 虛函數被繼承后仍然是虛擬函數,可以省略掉關鍵字“virtual” };#endif // _APP_DELEGATE_H_AppDelegate.cpp
#include "AppDelegate.h" #include "MainScene.h"USING_NS_CC; // visiableSize static cocos2d::Size designResolutionSize = cocos2d::Size(1386, 640); static cocos2d::Size smallResolutionSize = cocos2d::Size(480, 320); static cocos2d::Size mediumResolutionSize = cocos2d::Size(1024, 768); static cocos2d::Size largeResolutionSize = cocos2d::Size(2048, 1536);AppDelegate::AppDelegate() { }AppDelegate::~AppDelegate() { }void AppDelegate::initGLContextAttrs() {// set OpenGL context attributes: red, green, blue, alpha, depth, stencil, multisamplesCountGLContextAttrs glContextAttrs = {8, 8, 8, 8, 24, 8, 0};GLView::setGLContextAttrs(glContextAttrs); }bool AppDelegate::applicationDidFinishLaunching() {auto director = Director::getInstance();auto glview = director->getOpenGLView();if(!glview) {director->setOpenGLView(glview);}// 顯示演示信息director->setDisplayStats(true);// 設置幀率director->setAnimationInterval(1.0f / 60);// designResolutionSize 設計分辨率大小glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::FIXED_WIDTH);// frameSize 手機分辨率大小auto frameSize = glview->getFrameSize();// 適配策略if (frameSize.height > mediumResolutionSize.height) {director->setContentScaleFactor(MIN(largeResolutionSize.height/designResolutionSize.height, largeResolutionSize.width/designResolutionSize.width));} else if (frameSize.height > smallResolutionSize.height) {director->setContentScaleFactor(MIN(mediumResolutionSize.height/designResolutionSize.height, mediumResolutionSize.width/designResolutionSize.width));} else {director->setContentScaleFactor(MIN(smallResolutionSize.height/designResolutionSize.height, smallResolutionSize.width/designResolutionSize.width));}// 創建場景auto mainScene = MainScene::createScene();// 導演類調度場景director->runWithScene(mainScene);return true; }void AppDelegate::applicationDidEnterBackground() {Director::getInstance()->stopAnimation(); } void AppDelegate::applicationWillEnterForeground() {Director::getInstance()->startAnimation(); }MainScene.hpp
#ifndef __MAIN_SCENE_H__ #define __MAIN_SCENE_H__#include "cocos2d.h" // 繼承Scene class MainScene : public cocos2d::Scene { public:static cocos2d::Scene* createScene(); // 靜態,用于獲取場景對象virtual bool init() override; // 初始化場景CREATE_FUNC(MainScene); // };#endif // __HELLOWORLD_SCENE_H__MainScene.cpp
#include "MainScene.h"USING_NS_CC; // 等同于 using namespace cocos2d Scene* HelloWorld::createScene() {auto scene = Scene::create(); // 創建一個Scene對象auto layer = MainScene::create(); // 創建一個MainScene對象scene->addChild(layer); // 將layer加入到場景中return scene; }bool mainScene::init() {if ( !Scene::init() ){return false;}// 在這里添加邏輯代碼return true; }層的生命周期函數
bool init() // 初始化層調用 void onEnter() // 進入層時調用 void onEnterTransitionDidFinish() // 進入層且過渡動畫結束時調用 void onEixt() // 退出層時調用 void onEixtTransitionDidStart() // 退出層且開始過渡動畫時調用 void cleanup() // 層對象被清除時調用場景文件
// .h文件 #ifndef __SET_SCENE__ #define __SET_SCENE__#include "cocos2d.h"class SetScene : public cocos2d::Scene { public:static cocos2d::Scene* createScene();virtual bool init();CREATE_FUNC(SetScene); private:int volume = 50; }; #endif -------------------------------------------------------------------------------------- // .cpp文件 #include"SetScene.h"USING_NS_CC;Scene* SetScene::createScene() { return SetScene::create(); } bool SetScene::init() {if (!Scene::init()){return false;}auto visibleSize = Director::getInstance()->getVisibleSize();Vec2 origin = Director::getInstance()->getVisibleOrigin(); }普通文件
// .h文件 #ifndef _PROP_H_ #define _PROP_H_ #include "cocos2d.h"USING_NS_CC;class Prop : public Entity { public:Prop();~Prop();CREATE_FUNC(Prop);virtual bool init(); }; #endif; -------------------------------------------------------------------------------------- // .cpp文件 #include "prop.h"Prop::Prop() {} Prop::~Prop() {} bool Prop::init() { return true; } void Prop::createProp(float _x, float _y) {this->x = x;this->y = y;} } -------------------------------------------------------------------------------------- // 實例化 Prop* props = Prop::create(); props->createProp(10, 20);二段構造
// 二段構造的宏函數,其中(std::nothrow)當new失敗后強制返回指針,而非try-catch異常 #define CREATE_FUNC(__TYPE__) \ static __TYPE__* create() \ { \__TYPE__ *pRet = new(std::nothrow) __TYPE__(); \if (pRet && pRet->init()) \{ \pRet->autorelease(); \return pRet; \} \else \{ \delete pRet; \pRet = nullptr; \return nullptr; \} \ }二段構造并非經典23種設計模式之一,按照cocos2d-x創始人王哲對于為什么要設計成二段構建的看法:
其實我們設計二段構造時首先考慮其優勢而非兼容cocos2d-iphone。初始化時會遇到圖片資源不存在等異常,而C++構造函數無返回值,只能用try-catch來處理異常,啟用try-catch會使編譯后二進制文件大不少,故需要init返回bool值。Symbian, Bada SDK,objc的alloc + init也都是二階段構造。
我們暫且接受非兼容cocos2d-iphone這個理由(反正我不信)。按我個人的理解,既然C++現在已經愿意支持try-catch了,說明C++本身已經不在乎這些二進制文件的體量問題了,更不用說對于java、C#等一些語言來說異常已是必備的特性。而且既然C++都決定支持異常,還為了這些老版本的技術提供(std::nothrow)強制返回指針,自然也表明了并不推薦返回指針了。
所以實際上對于cocos來說,已經不需要采用二段構建來實例化一個類了,只是沒有人在愿意調整框架底層,cocos的每個內置類諸如Sprite、Button等都是采用的二段構建。所以對于開發者來說,需要用的地方自然是要用的,自己寫的類可用可不用。不過cocos在實現二段構建的同時,已經實現了簡化版的垃圾回收機制,可以省去new/delete操作,所以還是能夠簡化一些操作的。
常用功能
UI布局
Layer的錨點默認為左下角,其他Node的錨點默認為中心
Layer要設置錨點,必須先:layerTest->setIgnoreAnchorPointForPosition(false);
錨點不等于原點
切換場景
// include "ShopScene.hpp" Director::getInstance()->replaceScene(ShopScene::createScene());通過圖集加載圖片
// 使用texture package將美術提供的tps文件轉化為plist和pvr.czz文件 ZipUtils::setPvrEncryptionKey() // plist->czz需要md5秘鑰解碼 SpriteFrameCache *sfc = SpriteFrameCache::getInstance(); // 定義SpriteFrameCache sfc->addSpriteFrameWithFile("xxx.plist"); // 調用實例方法addSpriteFrameWithFile()auto mainBg = Sprite::createWithSpritesFrameName("xxx.png"); // 使用圖集加載圖片添加Button
// include "ui/CocosGUI.h" auto btn = cocos2d::ui::Button::create(); btn->loadTextures("xxx_normal.png", "xxx_pressed.png", "", cocos2d::ui::Widget::TextureResType::PLIST); btn->setPosition(Vec2(20, 100)); this->addChild(btn);添加文本
auto label = Label::createWithTTF("Hello World", "fonts/Marker Felt.ttf", 24); auto label2 = Label::createWithSystemFont("Hello World", "Arial", 24); label->setPosition(Vec2(20, 100)); this->addChild(label);添加事件
// 方法一:設置監聽器,由_eventDispatcher派發事件。需要注意的是,在添加到多個對象時,需要使用clone()方法。 auto listener = EventListenerTouchOneByOne::create();listener->setSwallowTouches(true);listener->onTouchBegan = [=](Touch *touch, Event* event) {// 自己實現事件區域檢測,默認全屏可觸發auto target = static_cast<Sprite*>(event->getCurrentTarget());//獲取到你點擊的對象具體是哪個精靈Point locationInNode = target->convertTouchToNodeSpace(touch);//獲取到點擊位置在你這個對象的相對位置Size size = target->getContentSize();//對象內容大小,在后面用來判斷是否點中了某對象的區域Rect rect = Rect(0, 0, size.width, size.height);//包含這個對象的矩形區域if (rect.containsPoint(locationInNode))//矩形局域檢測,點是否在矩形內部{printf("點到了圖片");Director::getInstance()->replaceScene(HelloWorld::createScene());return true;}return false;};_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, btn);// 方法二:直接通過對象掛載事件監聽器 btn->addTouchEventListener([&](Ref* sender, cocos2d::ui::Widget::TouchEventType type){switch (type){default:break;case ui::Widget::TouchEventType::BEGAN:break;case ui::Widget::TouchEventType::ENDED:break;} }); // []:默認不捕獲任何變量; // [=]:默認以值捕獲所有變量; // [&]:默認以引用捕獲所有變量; // [x]:僅以值捕獲x,其它變量不捕獲;添加菜單
// 1. 創建標簽 auto volumeHigherLab = Label::createWithTTF("+", "fonts/Marker Felt.ttf", 150); auto volumeLowerLab = Label::createWithTTF("-", "fonts/Marker Felt.ttf", 150); // 2. 創建菜單項 auto volumeHigherMenu = MenuItemLabel::create(volumeHigherLab, CC_CALLBACK_1(SetScene::menuCloseCallbackVolumeHigher, this)); auto volumeLowerMenu = MenuItemLabel::create(volumeLowerLab, CC_CALLBACK_1(SetScene::menuCloseCallbackVolumeLower, this)); // 3. 創建菜單 MenuHigherVolume = Menu::create(volumeHigherMenu, NULL); MenuLowerVolume = Menu::create(volumeLowerMenu, NULL); // 4. 設置位置并添加到場景中 MenuHigherVolume->setPosition(850, 250); MenuLowerVolume->setPosition(960, 260); this->addChild(MenuHigherVolume, 1); this->addChild(MenuLowerVolume, 1);添加動畫
// 繞y軸旋轉180,5s auto* rotateBy = RotateBy::create(5.0f, Vec3(0, 180, 0)); // 定義回調函數 auto* callFun = CallFunc::create(CC_CALLBACK_0(MainScene::rotateFun, this)); // 定義動畫序列 auto* sequence = Sequence::create(rotateBy, callFun, NULL); sprite->runAction(sequence);添加定時器
// 在init()中進行調用 scheduleUpdate(); // 重寫Update(float dt)方法 schedule(schedule_selector(MainScene::myUpdate), 0.2f); // 自定義方法讀取XML文件
// #include <tinyxml2/tinyxml2.h> auto doc = new tinyxml2::XMLDocument(); doc->Parse(FileUtils::getInstance()->getStringFromFile("data.xml").c_str()); // 調用解析函數 auto root = doc->RootElement(); // 從根節點開始查找 for (auto e = root->FirstChildElement(); e != NULL; e = e->NextSiblingElement()) {for (auto attr = e->FirstAttribute(); attr != NULL; attr = attr->Next()) {printf("%s %s\n", attr->Name(), attr->Value());}讀取json文件
// #include <json/document.h> rapidjson::Document d; d.Parse<0>(FileUtils::getInstance()->getStringFromFile("data.json").c_str()); // 調用解析函數 <0>默認解析方式 printf("%s",d[0]["name"].GetString());讀取本地存儲
UserDefault::getInstance()->getIntegerForKey("int"); // 設置key UserDefault::getInstance()->setIntegerForKey("int", 999); // 讀取key printf("saved file path is %s\n", UserDefault::getInstance()->getXMLFilePath().c_str()); // 存儲路徑網絡編程
弱聯網:CURL庫
強聯網:socket
音頻控制
// 聲明 .h CocosDenshion::SimpleAudioEngine* audio; // 定義 .cpp audio = CocosDenshion::SimpleAudioEngine::getInstance(); if (!audio->isBackgroundMusicPlaying())audio->playBackgroundMusic("xxx.mp3", true);骨骼動畫
// #include "cocostudio/CocoStudio.h" // using namespace cocostudio; // 引入骨骼動畫文件,保證plist和json在同一個目錄下 ArmatureDataManager::getInstance()->addArmatureFileInfo("ani_mainshop.ExportJson"); auto armature = Armature::create("ani_mainshop"); armature->getAnimation()->playWithIndex(1); // 按照Animation的index添加動畫 armature->setPosition(Vec2(0, 0)); mainShopCarBg->addChild(armature, 1);游戲控制
CCScheduler* defaultScheduler = CCDirector::sharedDirector()->getScheduler(); defaultScheduler->setTimeScale(2.0f); // 全局加速 defaultScheduler->pauseTarget(this); // 暫停游戲 defaultScheduler->resumeTarget(this); // 恢復游戲開發經驗
最小化在編寫代碼前需要了解的信息
不是解決任何問題都要從頭做起
框架只是讓你規范地去開發
設計模式是學習OOP的最佳模板
總結
以上是生活随笔為你收集整理的在2020年学习cocos游戏引擎的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MC.9 与 LIS
- 下一篇: xstream,节点属性起别名时这样的问