作者:慧科集团华东校区-朱家聪老师,转载请注明出处及本链接。
开发准备
开发设备:MacBook Pro(Retina 显示屏,13 英寸,2014 年中)
Cocos2d-x版本:3.15
CPU:2.6 GHz Intel Core i5
内存:8 GB 1600 MHz DDR3
系统版本:macOS 10.12.4
IDE:Xcode Version 8.0 (8A218a)
环境搭建
参考Cocos的官方文档可以快速搭建一个Cocos2d-x的HelloWorld工程。
下载Cocos2d-x
前往cocos2d-x.org/download下载Cocos2d-x的工具包。现版本有3.15
和2.2.6
两个版本可以使用,选择3.15
版本(319MB)进行下载。下载完成解压后放到一个常用路径中去。这里我把解压包发到了 /Document
的根目录下。完成后使用终端进入到这个文件夹中/Users/ZhuJiaCong/Documents/cocos2d-x-3.15
。这个下载完成后的文件夹可以理解问Cocos2d-x游戏引擎的源文件,我们今后创建的每一个工程都需要通过这个源文件来创建。
创建HelloWorld工程项目
在Cocos2d-x引擎中,为我们提供了一个新建工程的Python脚本。这个脚本的作用就是新建一个Cocos2d-x的项目。启用终端,找到Cocos2d-x引擎所在的文件夹。然后按照路径进入到子文件夹/tools/cocos2d-console/bin/
。在这文件夹中就能找到这个Python脚本文件(cocos.py)。接下来要做的就是运行这个脚本文件来创建一个新的工程项目。在终端中输入如下指令:
python cocos.py new HelloWorldDemo -p com.coco2dx.org -l cpp -d ~/Desktop
HelloWorldDemo为项目名称
-p后面接包名
-l后面接开发语言类型,有cpp, lua, js三种类型
-d后面接项目存放的目录 ~/Desktop表示当前用户的桌面
在运行这个脚本的时候,要注意的是运行cocos.py脚本要求系统安装了Python2.7以上版本。在终端中执行Pyhton指令能够查看当前系统中的Python版本号。
ZhuJiaCongdeMacBook-Pro:bin ZhuJiaCong$ python
Python 2.7.10 (default, Feb 6 2017, 23:53:20)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.34)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
可以看出我的电脑已经安装了2.7.10
版本的Python。如果版本过低或者没有安装,需要先前往python.org下载更新版本的Python。
# ****第一个****Demo****文件
创建好第一个工程文件后,进入到这个工程文件夹。先来熟悉一下工程文件夹中的内容。
Classes //项目工程的通用类,我们所编写的代码基本都在此
cocos2d //Cocos2d-x引擎的源代码
Resources //工程的资源文件
CMakeLists.txt
proj.android //安卓平台下代码
proj.tizen //Tizen平台,也是一种移动端系统
proj.android-studio //这个也是安卓平台下的代码
proj.win10 //Windows 10以及WinPhone平台下的代码
proj.ios_mac //macOS或者iOS平台下的代码
proj.win32 //其他版本Windows平台下的代码
proj.linux //Linux平台下的代码
首先我们现在macOS/iOS平台中进行代码的开发,在开发完成后再移植到安卓或者其他系统中去。所以首先打开proj.ios_mac
文件夹。在文件夹中可以看到一个Xcode项目文件,双击可以打开这个文件。编译运行这个文件就能够看到HelloWorldDemo工程在iPhone模拟器中运行的效果了。
## ****代码文件分析
接下来我们简单的分析一下这个Demo工程中的代码文件。在Classes
文件中,有四个文件。
AppDelegate.h
AppDelegate.cpp
HelloWorldScene.h
HelloWorldScene.cpp
做过iOS开发的朋友应该对AppDelegate一点也不陌生,这就是应用程序的代理类。简单看一下里面的代码就能理解他的工作原理。
AppDelegate
AppDelegate.h
#include "cocos2d.h"
class AppDelegate : private cocos2d::Application
{
public:
AppDelegate();
virtual ~AppDelegate();
//设置OpenGL
virtual void initGLContextAttrs();
//应用程序加载完成后调用的方法
virtual bool applicationDidFinishLaunching();
//应用程序进入到后台时调用的方法
virtual void applicationDidEnterBackground();
//应用程序退出后台时调用的方法
virtual void applicationWillEnterForeground();
};
在AppDelegate.h文件中定义了AppDelegate这个类,用于处理和响应应用程序的的各种事件。当程序加载完成后会自动的调用virtual bool applicationDidFinishLaunching();
方法。
AppDelegate.cpp
//Cocos2d-x中的一个宏定义 作用是替换了 using namespace cocos2d
USING_NS_CC;
//定义了几种屏幕分辨率
static cocos2d::Size designResolutionSize = cocos2d::Size(480, 320);
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的析构函数
AppDelegate::~AppDelegate()
{
#if USE_AUDIO_ENGINE
AudioEngine::end();
#elif USE_SIMPLE_AUDIO_ENGINE
SimpleAudioEngine::end();
#endif
}
//初始化OpenGL的上下文(context)属性
void AppDelegate::initGLContextAttrs()
{
// 设置 OpenGL 上下文的属性
//red,green,blue,alpha,depth(深度缓存),stencil(模版缓存)
GLContextAttrs glContextAttrs = {8, 8, 8, 8, 24, 8};
GLView::setGLContextAttrs(glContextAttrs);
}
// if you want to use the package manager to install more packages,
// don't modify or remove this function
static int register_all_packages()
{
return 0; //flag for packages manager
}
//应用程序加载完成后所调用的方法
bool AppDelegate::applicationDidFinishLaunching() {
// 初始化导演
auto director = Director::getInstance();
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)
//创建OprnGL视图
glview = GLViewImpl::createWithRect("HelloWorldDemo", cocos2d::Rect(0, 0, designResolutionSize.width, designResolutionSize.height));
#else
glview = GLViewImpl::create("HelloWorldDemo");
#endif
//设置导演类的OpenGL视图
director->setOpenGLView(glview);
}
// 是否显示程序的状态信息(左下角的帧率)设置为false可以隐藏显示
director->setDisplayStats(true);
// 设定默认的计时器运行速率,1.0f/60 表示60分之1秒,即60FPS。
director->setAnimationInterval(1.0f / 60);
// 屏幕分辨率适配
glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::NO_BORDER);
auto 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();
// 使用HelloWorld类创建第一个游戏场景
auto scene = HelloWorld::createScene();
// 运行这个游戏场景
director->runWithScene(scene);
return true;
}
// 应用程序进入到后台
void AppDelegate::applicationDidEnterBackground() {
//停止动画效果
Director::getInstance()->stopAnimation();
//停止音乐播放
#if USE_AUDIO_ENGINE
AudioEngine::pauseAll();
#elif USE_SIMPLE_AUDIO_ENGINE
SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
SimpleAudioEngine::getInstance()->pauseAllEffects();
#endif
}
// 应用程序返回前台
void AppDelegate::applicationWillEnterForeground() {
//继续开始执行动画
Director::getInstance()->startAnimation();
//继续播放音乐
#if USE_AUDIO_ENGINE
AudioEngine::resumeAll();
#elif USE_SIMPLE_AUDIO_ENGINE
SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
SimpleAudioEngine::getInstance()->resumeAllEffects();
#endif
}
HelloWorldScene
在AppDelegate中,我们发现程序调用了HelloWorld这个类的方法创建了一个场景对象,然后运行了这一个新创建的场景。所以接下来再简单的来了解一下HelloWorld这个场景的运行原理。
HelloWorldScene.h
#include "cocos2d.h"
class HelloWorld : public cocos2d::Scene
{
public:
//创建场景函数,返回值为创建完成的场景对象
static cocos2d::Scene* createScene();
//初始化函数
virtual bool init();
// 菜单回调函数,用于触摸菜单事件的回调
void menuCloseCallback(cocos2d::Ref* pSender);
// 宏定义
CREATE_FUNC(HelloWorld);
};
从头文件可以看出,HelloWorld继承于cocos2d::Scene类。Scene(场景)是Cocos2d-x中非常重要的一个类,一个完整的游戏是由多个场景构成的。而之前在AppDelegate中出现的导演对象则负责这多个场景之间进行调度和切换。在这个类的定义中,使用到了一个宏定义CREATE_FUNC();
。这个宏定义的作用是自动生成当前类的create方法。具体实现如下:
static HelloWorld* create(){
HelloWorld *pRet = new(std::nothrow) HelloWorld();
if (pRet && pRet->init()) {
pRet->autorelease();
return pRet;
} else {
delete pRet;
pRet = nullptr;
return nullptr;
}
}
可以看出CREATE_FUNC();
这个宏定义的作用其实是创建了HelloWorld
类的create();
方法。在方法内部通过new
来新建了一个对象。并且将这个对象加入了自动释放池中。最后返回了这个对象。
HelloWorldScene.cpp
//创建场景函数
Scene* HelloWorld::createScene()
{
//调用了之前使用宏定义生成的创建方法创建了当前的场景对象
return HelloWorld::create();
}
//初始化方法,初始化当前对象
bool HelloWorld::init()
{
// 调用基类的初始化方法
if ( !Scene::init() )
{
return false;
}
// 获取当前屏幕可视区域的尺寸
auto visibleSize = Director::getInstance()->getVisibleSize();
// 屏幕的原点
Vec2 origin = Director::getInstance()->getVisibleOrigin();
// 创建一个菜单按钮,用来关闭当前程序
auto closeItem = MenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
CC_CALLBACK_1(HelloWorld::menuCloseCallback,
this));
// 设置关闭按钮的位置 Vec2是在Cocos框架中的一个二位坐标点类
closeItem->setPosition(Vec2(origin.x + visibleSize.width - closeItem->getContentSize().width/2 ,
origin.y + closeItem->getContentSize().height/2));
// 创建菜单对象,使用之前的关闭按钮来初始化
auto menu = Menu::create(closeItem, NULL);
menu->setPosition(Vec2::ZERO);
// 将菜单对象添加到当前的场景中
this->addChild(menu, 1);
// 创建一个Label对象,用于显示文字
// 三个参数分别是 文字信息,字体,字号
auto label = Label::createWithTTF("Hello World", "fonts/Marker Felt.ttf", 24);
// 设置Label的位置,定位在屏幕中心
label->setPosition(Vec2(origin.x + visibleSize.width/2,
origin.y + visibleSize.height - label->getContentSize().height));
// 添加Label到当前场景中
this->addChild(label, 1);
// 创建一个精灵对象 此处用到了一个Logo图片,然后添加到当前场景中去
auto sprite = Sprite::create("HelloWorld.png");
sprite->setPosition(Vec2(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));
this->addChild(sprite, 0);
return true;
}
//菜单回调函数
void HelloWorld::menuCloseCallback(Ref* pSender)
{
//关闭当前的场景,并且推出应用程序
Director::getInstance()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
}