从这里开始
Cocos2d-x 是基于 OpenGL 实现 的,游戏启动起点是 Cocos2d 中定义的程序类 Application,在每个 cocos2d 项目创建时,引擎会自动给我们创建一个 AppDelegate 类,这个类就是继承 Application 类的,游戏启动就是从这个类开始的,我们在这个类里初始化 OpenGL,一些基本设置和创建一个场景并运行。在这个类里主要实现以下四个方法:
- 初始化OpenGL
//初始化OpenGL
void AppDelegate::initGLContextAttrs()
{
//set OpenGL context attributions,now can only set six attributions:
//red,green,blue,alpha,depth,stencil
GLContextAttrs glContextAttrs = {8, 8, 8, 8, 24, 8};
GLView::setGLContextAttrs(glContextAttrs);
}
- 初始化游戏
//程序初始化
bool AppDelegate::applicationDidFinishLaunching() {
// 初始化导演
auto director = Director::getInstance();
//初始OpenGL视口
auto glview = director->getOpenGLView();
//设置视口大小
if(!glview) {
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) || (CC_TARGET_PLATFORM == CC_PLATFORM_MAC) || (CC_TARGET_PLATFORM == CC_PLATFORM_LINUX)
glview = GLViewImpl::createWithRect("Demo1", Rect(0, 0, designResolutionSize.width, designResolutionSize.height));
#else
glview = GLViewImpl::create("Demo1");
#endif
director->setOpenGLView(glview);
}
// 是否显示FPS
director->setDisplayStats(true);
// 设置 FPS.
director->setAnimationInterval(1.0 / 60);
//自动适配
glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::NO_BORDER);
Size frameSize = glview->getFrameSize();
// if the frame's height is larger than the height of medium size.
if (frameSize.height > mediumResolutionSize.height)
{
director->setContentScaleFactor(MIN(largeResolutionSize.height/designResolutionSize.height, largeResolutionSize.width/designResolutionSize.width));
}
// if the frame's height is larger than the height of small size.
else if (frameSize.height > smallResolutionSize.height)
{
director->setContentScaleFactor(MIN(mediumResolutionSize.height/designResolutionSize.height, mediumResolutionSize.width/designResolutionSize.width));
}
// if the frame's height is smaller than the height of medium size.
else
{
director->setContentScaleFactor(MIN(smallResolutionSize.height/designResolutionSize.height, smallResolutionSize.width/designResolutionSize.width));
}
//扩展其它包
register_all_packages();
//创建场景
auto scene = HelloNode::createScene();
//运行场景
director->runWithScene(scene);
return true;
}
// 扩展其它包
static int register_all_packages()
{
return 0; //flag for packages manager
}
- 游戏进入后台时调度
// 游戏进入后台运行时
void AppDelegate::applicationDidEnterBackground() {
//停止动画
Director::getInstance()->stopAnimation();
// 暂停背景音乐
// SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
}
- 游戏恢复运行时调度
// 游戏恢复运行时
void AppDelegate::applicationWillEnterForeground() {
//开始动画
Director::getInstance()->startAnimation();
// 恢复背景音乐
// SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
}
Cocos2d-x 架构
我们看一下Cocos2d引擎的架构,下面这张图来自官网:
我们可以看到,架构的最下层是操作系统,中间层是 cocos 引擎,声音引擎,物理引擎和脚本引擎等,最上面的一层才是我们自己写的代码。
下面我们再看一下cocos的组织结构,同样这张图来自官网教程:
- Director 是 cocos 的大总管,它主要的作用是在不同的游戏场景中切换,当然还有其它的工作,比如派发事件,播放和停止动画,取位图缓存、计数引用管理等等,还有我们在AppDelegate中的很多初始化工作也是Director完成的。总之Director是把控游戏全局的一个类,它是一个单例类,游戏中有且只有一个Director类。
- Scene顾名思义就是一个场景,cocos把游戏划分为一个场景,比如开始场景,战斗场景,结束场景等,事实上很多游戏引擎都会采用这种方式来管理游戏,比如Unity也是。这种方式不仅直观容易理解,也使得游戏更容易管理。Scene只是一个虚拟场景,我们不会把显示对象加到Scene里面去,而是加到一个Layer上,然后再把Layer加到Scene上,一个Scene可以有很多Layer。
- Layer是一个层,一般我们显示对象加到其上面,再把层加到场景上。一个场景可以添加多个层,后添加的层在先添加的层上面。一般我们在游戏中创建一个场景不会直接继承自Scene,而是继承自Layer,然后在Layer里面写一个静态方法CreateScene来创建一个场景,并创建一个自己(层)的实例加到场景上。
- Node是所有显示对象的根结点,Sprite,DrawNode,Label等等都会继承它(当然也可能继承其它类,C++是多重继承的)。
下面我们来看一下一个 HelloWorld 的场景,以了解cocos2d的组织结构,这个类实现一个矩形和一个点不断地旋转。
#include "HelloWorldScene.h"
//使用Cocos2d命名空间
//using namespace cocos2d;
USING_NS_CC;
//静态方法,创建一个场景
Scene* HelloWorld::createScene()
{
// 创建场景
auto scene = Scene::create();
// 实例化自己,创建一个层
auto layer = HelloWorld::create();
// 把层加到场景上
scene->addChild(layer);
// 返回场景
return scene;
}
// 初始化层
// 这个方法会在Layer的create里面被调用
bool HelloWorld::init()
{
//调用父类方法初始化层
if ( !Layer::init() )
{
return false;
}
/*下面代码实现我们自己的功能*/
//获得屏幕的大小
Size visibleSize = Director::getInstance()->getVisibleSize();
//获得屏幕的原点
Vec2 origin = Director::getInstance()->getVisibleOrigin();
//创建一个矩形
auto rect=DrawNode::create();
rect->drawRect(Vec2(0,0),Vec2(0,100),Vec2(100,100),Vec2(100,0),Color4F(0.1,0.2,0.3,1));
//设置位置,相对于它的父结点
rect->setPosition(origin.x+visibleSize.width/2,origin.y+visibleSize.height/2);
//设置锚点(百分比)
rect->setAnchorPoint(Vec2(0.5,0.5));
rect->setContentSize(Size(100,100));
//添加到父结点
this->addChild(rect);
//创建一个点
auto dot=DrawNode::create();
dot->drawDot(Vec2(0,0),10,Color4F(1,0,0,0.5));
//设置位置,相对坐标
dot->setPosition(Vec2::ZERO);
//锚点对点不起作用
dot->setAnchorPoint(Vec2(0.5,0.5));
//添加到父结点
rect->addChild(dot);
//调度器,其回调函数在游戏运行的每一帧里都会被调用一次
schedule([dot,rect](float f){
rect->setRotation(rect->getRotation()+1);
Vec2 p=dot->convertToWorldSpace(Vec2(0,0));
log("%f,%f",p.x,p.y);
},"test");
/****************************/
return true;
}
我们再看一下.h文件
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
class HelloWorld : public cocos2d::Layer
{
public:
<span style="white-space:pre"> </span>//创建场景的静态方法createScene
static cocos2d::Scene* createScene();
//实现初始化方法init
virtual bool init();
// 实现静态方法create
CREATE_FUNC(HelloWorld);
};
#endif
我们看到在这个类里我们实现了三个方法,一个创建场景的静态方法,一个创建层的静态方法,一个初始化层的实例方法。CREATE_FUNC(类名)是cocos定义的一个宏,一般我们直接用这个宏的创建层就可以了,如果有需要我们也可以自己手动实现这个方法,比如我们在创建层的时候需要传参数进来,就必须要自己写了。我们看一下这个宏的定义,我们自己实现这个方法也是要根据它的写法来的。
#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; \
} \
}