在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)

架构分析

目录分析

cocos目录结构
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的最佳模板

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/569598.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[源码学习]--UGUI

学习参考 从bitbucket上获取uGUI 2019.1源码 UGUI内核大探究 事件系统 UnityEngine.UI/EventSystem/EventSystem.cs private List<BaseInputModule> m_SystemInputModules new List<BaseInputModule>(); // 系统输入模块列表 private BaseInputModule m_Curr…

PureMVC在Unity游戏开发中的应用

作为开发人员&#xff0c;我们都想写出优雅的代码&#xff0c;可又苦于自身能力不知该如何下手&#xff0c;而框架的作用正在与能够让你规范的去开发。 之前写Web的时候&#xff0c;总被要求采用MVC架构&#xff0c;的确非常好用&#xff0c;也从来没有质疑过这种架构的好与不好…

Unity资源管理--AssetBundle学习

Unity资源目录 当用Unity创建一个工程的时候&#xff0c;目录如下&#xff1a; Assets&#xff1a;存放Unity工程实际的资源目录。 Library&#xff1a;存放Unity处理完毕的资源&#xff0c;由unity自动转化生成。 Log&#xff1a;存放日志文件。 Packages&#xff1a;统一管…

[读书笔记] 设计模式与游戏完美开发

最近在看《设计模式与游戏完美开发》&#xff0c;文章将记录一些要点和一些设计模式实现 GoF定义的23种设计模式及应用场景 系统设计可以采用的设计模式&#xff1a;单例、状态&#xff08;场景切换&#xff09;、外观&#xff08;保证高内聚&#xff09;、中介者&#xff08…

iOS开发——GPUImage源码解析

一、基本概念 GPUImage&#xff1a;一个开源的、基于openGL的图片或视频的处理框架&#xff0c;其本身内置了多达120多种常见的滤镜效果&#xff0c;并且支持照相机和摄像机的实时滤镜&#xff0c;并且能够自定义图像滤镜。同时也很方便在原有基础上加入自己的滤镜Filter&#…

[读书笔记] 敏捷软件开发:原则、模式与实践

关于面向对象编程的一些理解&#xff0c;这本书主要看六大原则的部分&#xff0c;书中关于设计模式的内容由于之前的那本《设计模式与游戏完美开发》已经很好的讲解了游戏开发领域的应用&#xff0c;所以不多关注。 面向对象的六大原则 单一职责原则SRP&#xff1a;一个类应该…

Caffe-SSD相关源码说明和调试记录

1 对Blob的理解及其操作&#xff1a; Blob是一个四维的数组。维度从高到低分别是: (num_&#xff0c;channels_&#xff0c;height_&#xff0c;width_) 对于图像数据来说就是&#xff1a;图片个数&#xff0c;彩色通道个数&#xff0c;宽&#xff0c;高 Blob中数据是row-…

[游戏策划] 读书笔记

交互式媒体最有趣的地方在于&#xff0c;它让玩家直面问题&#xff0c;思考、尝试各种解决方案&#xff0c;并体验各种解决方案的结果。然后玩家可以回到思考阶段&#xff0c;规划下一步行动。这种反复试错的过程中&#xff0c;玩家的脑海里就会构建出一个互动的世界。 [读书笔…

ECS框架学习

DOTS Unity DOTS是Unity官方基于ECS架构开发的一套包含Burst编辑器和JobSystem的技术栈&#xff0c;它旨在充分利用多核处理器的特点&#xff0c;充分发挥ECS的优势。 安装 Entities、Burst、Jobs、Hybrid Renderer&#xff08;必选&#xff0c;用于DOTS的渲染相关&#xf…

辅助排序和Mapreduce整体流程

一、辅助排序 需求&#xff1a;先有一个订单数据文件&#xff0c;包含了订单id、商品id、商品价格&#xff0c;要求将订单id正序&#xff0c;商品价格倒序&#xff0c;且生成结果文件个数为订单id的数量&#xff0c;每个结果文件中只要一条该订单最贵商品的数据。 思路&#xf…

[读书笔记] 史玉柱自述:我的营销心得

与下属的关系 从玩家角度设定目标 目标感的设计 论随机性 在前15分钟留住玩家 实际观察玩家对于游戏的翻译反应 好游戏是改出来的 注重细节 决策民主、责任人制度 论简单与复杂的关系 游戏经济中的投放与回收 避免进入降低压力的怪圈 创业初期的股份分配 单个行业…

记一次面试腾讯的奇葩经历

阅读本文大概需要 2.8 分钟。 作者&#xff1a;黄小斜 文章来源&#xff1a;微信公众号【程序员江湖】 ​ 上回说到&#xff0c;我腾讯面试出师不利&#xff0c;简历随即进入备胎池&#xff0c;不过没过多久&#xff0c;转机还是来了。 大概是一周之后&#xff0c;我的电话响起…

foot

码云链接&#xff1a;https://gitee.com/zyyyyyyyyyyy/codes/rcfdzmin4a82v975pl1ko47 效果图&#xff1a; 原网站截图&#xff1a; 源代码&#xff1a; <!DOCTYPE html><html><head><meta charset"UTF-8"><title></title><s…

Taro项目遇到的问题

1. https://taro-ui.aotu.io/#/docs/questions 请在Taro项目根目录找到 config/index.js 文件中的h5项&#xff0c;添加如下&#xff1a; h5: {...esnextModules: [taro-ui] } 2. 原则&#xff1a;少什么就装什么 少了 babel-plugin-transform-decorators-legacy &#xff0c;那…

严重: StandardServer.await: create[localhost:8005]

①看看任务管理器&#xff0c;是否打开了多个Tomcat程序 如果是&#xff0c;关闭其中一个 ②可能是端口冲突 1、将tomcat安装目录下的conf/server.xml中的8005端口号改为其它的端口号。&#xff08;不建议&#xff0c;因为会衍生出其他错误&#xff09; 2、将正在使用的8005端…

java里short,int,long,float,double范围及可写位数

一、取值范围 1、int二进制位数&#xff1a;32 包装类&#xff1a;java.lang.Integer最小值&#xff1a;Integer.MIN_VALUE -2147483648 &#xff08;-2的31次方&#xff09;最大值&#xff1a;Integer.MAX_VALUE 2147483647 &#xff08;2的31次方-1&#xff09;2、short 二…

第六周编程总结

6-1 求两数平方根之和 &#xff08;10 分) 函数fun的功能是&#xff1a;求两数平方根之和&#xff0c;作为函数值返回。例如&#xff1a;输入12和20&#xff0c;输出结果是&#xff1a;y 7.936238。 函数接口定义&#xff1a; double fun (double a, double b); 其中 a和 b是用…

【CH5105】Cookies

也是一道线型动态规划的好题…… 读入每个人的贪婪度之后&#xff0c;对其按照从大到小的顺序排序&#xff0c;定义状态f[i][j]为前i个人&#xff08;排序后&#xff09;分j个饼干的答案&#xff0c;那么答案为f[n][m],考虑状态转移方程。 1、若给第i个人的饼干数大于1 &#x…

sharing-jdbc实现读写分离及分库分表

需求&#xff1a; 分库&#xff1a;按业务线business_id将不同业务线的订单存储在不同的数据库上&#xff1b; 分表&#xff1a;按user_id字段将不同用户的订单存储在不同的表上&#xff0c;为方便直接用非分片字段order_id查询&#xff0c;可使用基因法&#xff1b; 读写分离&…