关闭

Cocos2d-x HelloWorld 之源码分析

标签: helloworld源码Cocos2d-x
151人阅读 评论(0) 收藏 举报
分类:
在《HelloWorld 之目录结构》中我们已经了解了怎么样新建一个HelloWorld工程,下面我们来看看源代码是什么样子的

main.cpp -- 程序的主入口
  1. #include "main.h"
  2. #include "AppDelegate.h"
  3. #include "cocos2d.h"
  4. USING_NS_CC;
  5. int APIENTRY _tWinMain(HINSTANCE hInstance,
  6. HINSTANCE hPrevInstance,
  7. LPTSTR lpCmdLine,
  8. int nCmdShow)
  9. {
  10. UNREFERENCED_PARAMETER(hPrevInstance);
  11. UNREFERENCED_PARAMETER(lpCmdLine);
  12. // create the application instance
  13. AppDelegate app; //创建这个应用程序实例
  14. return Application::getInstance()->run(); //运行它
  15. }
问题:AppDelegate app; 的时候创建应用程序对象,但是为什么可以使用Application::getInstance()->run(); 来运行呢。为什么不是app.run(); 呢?

AppDelegate.cpp -- 应用程序类,相当于Android 里面自定义Application
class  AppDelegate : private cocos2d::Application  
class CC_DLL Application : public ApplicationProtocol  
class CC_DLL ApplicationProtocol  
  • CCApplicationProtocol.h 没有对应的cpp 文件,代码量很少
  • CCApplication.h 这个类在每一个不同的平台都会有对应的实现类
  • 源代码位置为:F:\software\cocos2d\cocos2d-x-3.6\cocos\platform
Application 的单例实现方案
win32
  1. Application * Application::sm_pSharedApplication = 0; //0 就是null,C++比Java灵活多了
  2. Application::Application() //构造函数
  3. : _instance(nullptr)
  4. , _accelTable(nullptr)
  5. {
  6. _instance = GetModuleHandle(nullptr);
  7. _animationInterval.QuadPart = 0;
  8. CC_ASSERT(! sm_pSharedApplication);
  9. sm_pSharedApplication = this;
  10. }
  11. Application::~Application() //析构函数
  12. {
  13. CC_ASSERT(this == sm_pSharedApplication);
  14. sm_pSharedApplication = nullptr;
  15. }
  16. Application* Application::getInstance() //拿到实例函数
  17. {
  18. CC_ASSERT(sm_pSharedApplication);
  19. return sm_pSharedApplication;
  20. }
Android
  1. Application * Application::sm_pSharedApplication = 0;
  2. Application::Application()
  3. {
  4. CCAssert(! sm_pSharedApplication, "");
  5. sm_pSharedApplication = this;
  6. }
  7. Application::~Application()
  8. {
  9. CCAssert(this == sm_pSharedApplication, "");
  10. sm_pSharedApplication = NULL;
  11. }
  12. Application* Application::getInstance()
  13. {
  14. CCAssert(sm_pSharedApplication, "");
  15. return sm_pSharedApplication;
  16. }
可以看出win32 和Android版的基本相同,在整个Cocos2d-x中AppDelegate就是一个单例模式。

解上面的问题:单例模式和Java里面的有点不同,不是类本身实例化自己,还是要靠外部来实例化,例如在main.cpp 里面的AppDelegate app; 创建了实例,同时赋值给静态变量sm_pSharedApplication,以后可以通过getInstance() 方法拿到这个实例(C++里面是叫实例吗?好纠结这些问题哦),为了满足单例模式拿到实例的一贯使用getInstance() 方法(习惯了Java里面叫方法,好像C++里面叫函数,以后我会改的)拿到实例。所以不用app->run();明白了吗?

回到AppDelegale.cpp/h 

相关的函数
  1. AppDelegate();
  2. virtual ~AppDelegate();
  3. virtual void initGLContextAttrs(); //初始化OpenGL Context 的6个属性,red,green,blue,alpha,depth,stencil
  4. virtual bool applicationDidFinishLaunching(); //当应用程序启动的时候执行,这里是游戏的开始,例如启动了loading 界面,开始加载游戏
  5. virtual void applicationDidEnterBackground(); //当游戏进入后台时会执行,例如电话来了
  6. virtual void applicationWillEnterForeground(); //当游戏恢复到前台运行时候执行,例如拒接电话
实现的函数

英文不好也要看英文呀

这里又有一个问题,Context 是不是和Android 的Context 同一个概念呢?但是我连Android 的Context 的不理解,就算相同我也不知道是怎么样的一个东西。
  1. //if you want a different context,just modify the value of glContextAttrs
  2. //it will takes effect on all platforms
  3. void AppDelegate::initGLContextAttrs()
  4. {
  5. //set OpenGL context attributions,now can only set six attributions:
  6. //red,green,blue,alpha,depth,stencil
  7. GLContextAttrs glContextAttrs = {8, 8, 8, 8, 24, 8};
  8. GLView::setGLContextAttrs(glContextAttrs);//是为GLView 设置的,感觉这个GLView 非同一般
  9. }
说明几点
  • auto c++ 11 的特征,相当于PHP 的var。类型自动识别
  • Director::getInstance(); 导演的单例模式
  • if(!glview){} 两部理解,我们的需求是,当个头OpenGLView() 返回空的时候我们需要创建这个glview
    • 1,if(glview) 当glview == null 的时候,但发现null == 0,这样直接为假,跳出去了
    • 2,if(!glview) 我加一个!不就完事了吗。
    • 3,背下来就ok了。
  • director有getOpenGLView() & setOpenGLView(glview); 说明director 有一个属性GLView,猜想这个就是用来显示场景的,在拍戏的时候导演都是坐在一个电视机前面叫开始的,这个电视机就是GLView 了。
  1. bool AppDelegate::applicationDidFinishLaunching() {
  2. // initialize director
  3. auto director = Director::getInstance(); //导演隆重登场,这里也是用了单例模式,整个游戏只能有一个导演,不知道有没有副导演呢?
  4. auto glview = director->getOpenGLView(); //GLView 再次出现,还是导演亲自请来的
  5. if(!glview) { //0(null) 是假,非0 是真,那当什么时候!glview 为真呢?就是当glview == null 的时候
  6.  //当glview 为null的时候
  7.         glview = GLViewImpl::create("My Game");
  8. director->setOpenGLView(glview);
  9. }
  10. // turn on display FPS
  11. director->setDisplayStats(true); //显示FPS
  12. // set FPS. the default value is 1.0/60 if you don't call this
  13. director->setAnimationInterval(1.0 / 60); //刷新屏幕的间隔时间,就是等待多久换一次帧数据
  14. register_all_packages();
  15. // create a scene. it's an autorelease object
  16. auto scene = HelloWorld::createScene();
  17. // run
  18. director->runWithScene(scene);
  19. return true;
  20. }
HelloWorld 的超简单实现了另外两个函数
  1. // This function will be called when the app is inactive. When comes a phone call,it's be invoked too
  2. void AppDelegate::applicationDidEnterBackground() {
  3. Director::getInstance()->stopAnimation();
  4. // if you use SimpleAudioEngine, it must be pause
  5. // SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
  6. }
  7. // this function will be called when the app is active again
  8. void AppDelegate::applicationWillEnterForeground() {
  9. Director::getInstance()->startAnimation();
  10. // if you use SimpleAudioEngine, it must resume here
  11. // SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
  12. }
从分析上面的代码看出,显示的第一个场景为HelloWorld::createScene();

HelloWorldScene.cpp -- 运行的场景,相当于Android的Activity

相关函数
  • Ref 类:Ref is used for reference count manangement. If a class inherits from Ref, then it is easy to be shared in different places.
    • cocos2dx中所有对象都继承于Ref,或者继承于 Ref和Clonable,Ref中就是维护了一个计数器,用于判断该继承于Ref的对象是否应该delete,意思就是我们可以放心的使用这些实例,不需要担心实例什么时候需要delete
  • CREATE_FUNC(HelloWorld)
    • 定义create() 方法,里面做了
      • 创建对象
      • 调用对象的init() 方法
      • 把对象加入到引用计数器的对象池中
      • 返回这个对象
    • 想必普通的对象都使用了这个宏了
    • 以后都使用这个函数来实例化对象
  1. //there's no 'id' in cpp, so we recommend returning the class instance pointer
  2. static cocos2d::Scene* createScene(); //创建场景实例,返回的是一个指针
  3. //Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
  4. virtual bool init(); //看到这个注释我也是醉了,一开始看到在cpp 里不能返回id,我就是看不明白,现在明白了,是不是iPhone 里面是可以返回id 的?猜应该是,Cocos2d-x 是由Cocos2d-iphone 版本发展过来的
  5. void menuCloseCallback(cocos2d::Ref* pSender); //一个回调函数
  6. CREATE_FUNC(HelloWorld);
函数实现

  1. Scene* HelloWorld::createScene()
  2. {
  3. auto scene = Scene::create(); //创建一个场景
  4. auto layer = HelloWorld::create(); //HelloWorld是一个层,MD,才发现HelloWorld 是一个层,看文件名字,我还以为是场景呢
  5. scene->addChild(layer); //直接显示HelloWorld 层
  6. return scene;
  7. }
总要知识点
  • Layer 需要调用super 的init() 函数
      1. if ( !Layer::init() ) //c++ 使用类名来指定调用哪个父类的方法
  1. // on "init" you need to initialize your instance
  2. bool HelloWorld::init()
  3. {
  4. //////////////////////////////
  5. // 1. super init first
  6. if ( !Layer::init() )
  7. {
  8. return false;
  9. }
  10. Size visibleSize = Director::getInstance()->getVisibleSize();//显示大小
  11. Vec2 origin = Director::getInstance()->getVisibleOrigin(); //起点位置
  12. /////////////////////////////
  13. // 2. add a menu item with "X" image, which is clicked to quit the program
  14. // you may modify it.
  15. // add a "close" icon to exit the progress. it's an autorelease object
  16. auto closeItem = MenuItemImage::create(
  17. "CloseNormal.png",
  18. "CloseSelected.png",
  19. CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));
  20. closeItem->setPosition(Vec2(origin.x + visibleSize.width - closeItem->getContentSize().width/2 ,
  21. origin.y + closeItem->getContentSize().height/2));
  22. // create menu, it's an autorelease object
  23. auto menu = Menu::create(closeItem, NULL);
  24. menu->setPosition(Vec2::ZERO);
  25. this->addChild(menu, 1); //添加菜单
  26. /////////////////////////////
  27. // 3. add your codes below...
  28. // add a label shows "Hello World"
  29. // create and initialize a label
  30. auto label = Label::createWithTTF("Hello World", "fonts/Marker Felt.ttf", 24);
  31. // position the label on the center of the screen
  32. label->setPosition(Vec2(origin.x + visibleSize.width/2,
  33. origin.y + visibleSize.height - label->getContentSize().height));
  34. // add the label as a child to this layer
  35. this->addChild(label, 1); //添加label
  36. // add "HelloWorld" splash screen"
  37. auto sprite = Sprite::create("HelloWorld.png");
  38. // position the sprite on the center of the screen
  39. sprite->setPosition(Vec2(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));
  40. // add the sprite as a child to this layer
  41. this->addChild(sprite, 0);//最后加入一个精灵当做背景
  42. return true;
  43. }
回调函数,直接退出程序
  1. void HelloWorld::menuCloseCallback(Ref* pSender)
  2. {
  3. Director::getInstance()->end();
  4. #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
  5. exit(0);
  6. #endif
  7. }

定制HelloWorld -- win32 版
  • glview->setFrameSize(500,500); //指定显示的大小
  • GLFW_ICON    ICON     "res\\custom_game.ico" //在win32 的game.rc 文件中修改
  • 修改init 方法
  1. bool HelloWorld::init()
  2. {
  3. //////////////////////////////
  4. // 1. super init first
  5. if ( !Layer::init() )
  6. {
  7. return false;
  8. }
  9. Size visibleSize = Director::getInstance()->getVisibleSize();
  10. Vec2 origin = Director::getInstance()->getVisibleOrigin();
  11. //定制HelloWorld
  12. //弄了背景图
  13. auto background = Sprite::create("custom_hello_world.jpg");
  14. background->setPosition(Vec2(visibleSize.width/2+origin.x,visibleSize.height/2+origin.y));
  15. this->addChild(background,0);
  16. //显示个Label 标题,显示在背景图的上面
  17. auto labelTitle = Label::createWithTTF("Custom Hello World", "fonts/Marker Felt.ttf", 60);
  18. labelTitle->setPosition(Vec2(origin.x + visibleSize.width/2,
  19. origin.y + visibleSize.height/2 + labelTitle->getContentSize().height/2 + background->getContentSize().height/2));
  20. this->addChild(labelTitle, 1);
  21. //使用Label 做点击菜单项
  22. auto labelMenu = Label::createWithTTF("Click Me,Click Me", "fonts/Marker Felt.ttf", 60);
  23. auto closeMenu = MenuItemLabel::create(labelMenu);
  24. closeMenu->setPosition(Vec2(origin.x + visibleSize.width/2 - background->getContentSize().width/2 + labelMenu->getContentSize().width/2,
  25. origin.y + visibleSize.height/2 - background->getContentSize().width/2 + labelMenu->getContentSize().height/2));
  26. closeMenu->setCallback(CC_CALLBACK_1(HelloWorld::menuCloseCallback, this)); //设置回调函数
  27. auto menu = Menu::create(closeMenu,NULL);
  28. menu->setPosition(Vec2::ZERO);
  29. this->addChild(menu, 1);
  30. return true;
  31. }
运行结果,nice


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:409次
    • 积分:23
    • 等级:
    • 排名:千里之外
    • 原创:2篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章分类
    文章存档