Android cocos2dx游戏开发——示例程序HelloCpp源码分析

本文通过分析cocos2dx提供的示例程序HelloCpp来分析cocos2dx的启动过程。

我们从HelloCpp.java开始:

[java] view plaincopyprint?

  1. package org.cocos2dx.hellocpp;
  2. import org.cocos2dx.lib.Cocos2dxActivity;
  3. import android.os.Bundle;
  4. public class HelloCpp extends Cocos2dxActivity{
  5. protected void onCreate(Bundle savedInstanceState){
  6. super.onCreate(savedInstanceState);
  7. }
  8. static {
  9. System.loadLibrary("hellocpp");
  10. }
  11. }
package org.cocos2dx.hellocpp;

import org.cocos2dx.lib.Cocos2dxActivity;

import android.os.Bundle;

public class HelloCpp extends Cocos2dxActivity{

	protected void onCreate(Bundle savedInstanceState){
		super.onCreate(savedInstanceState);
	}

    static {
         System.loadLibrary("hellocpp");
    }
}

HelloCpp是一个Activity,首先会执行静态代码块,加载libhellocpp.so库,然后就是执行onCreate方法,这里调用了父类的onCreate方法。我们看看Cocos2dxActivity的onCreate方法,该类在cocos2dx的库工程libcocos2dx中:

[java] view plaincopyprint?

  1. @Override
  2. protected void onCreate(final Bundle savedInstanceState) {
  3. super.onCreate(savedInstanceState);
  4. sContext = this;
  5. this.mHandler = new Cocos2dxHandler(this);
  6. this.init();
  7. Cocos2dxHelper.init(this, this);
  8. }
@Override
	protected void onCreate(final Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		sContext = this;
    	this.mHandler = new Cocos2dxHandler(this);

    	this.init();

		Cocos2dxHelper.init(this, this);
	}

这里主要是执行初始化过程,Cocos2dxHandler主要处理显示Dialog的消息,Cocos2dxHelper是个辅助类,我们主要看init()方法:

[java] view plaincopyprint?

  1. public void init() {
  2. // FrameLayout
  3. ViewGroup.LayoutParams framelayout_params =
  4. new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
  5. ViewGroup.LayoutParams.FILL_PARENT);
  6. FrameLayout framelayout = new FrameLayout(this);
  7. framelayout.setLayoutParams(framelayout_params);
  8. // Cocos2dxEditText layout
  9. ViewGroup.LayoutParams edittext_layout_params =
  10. new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
  11. ViewGroup.LayoutParams.WRAP_CONTENT);
  12. Cocos2dxEditText edittext = new Cocos2dxEditText(this);
  13. edittext.setLayoutParams(edittext_layout_params);
  14. // ...add to FrameLayout
  15. framelayout.addView(edittext);
  16. // Cocos2dxGLSurfaceView
  17. this.mGLSurfaceView = this.onCreateView();
  18. // ...add to FrameLayout
  19. framelayout.addView(this.mGLSurfaceView);
  20. // Switch to supported OpenGL (ARGB888) mode on emulator
  21. if (isAndroidEmulator())
  22. this.mGLSurfaceView.setEGLConfigChooser(8 , 8, 8, 8, 16, 0);
  23. this.mGLSurfaceView.setCocos2dxRenderer(new Cocos2dxRenderer());
  24. this.mGLSurfaceView.setCocos2dxEditText(edittext);
  25. // Set framelayout as the content view
  26. setContentView(framelayout);
  27. }
public void init() {

    	// FrameLayout
        ViewGroup.LayoutParams framelayout_params =
            new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
                                       ViewGroup.LayoutParams.FILL_PARENT);
        FrameLayout framelayout = new FrameLayout(this);
        framelayout.setLayoutParams(framelayout_params);

        // Cocos2dxEditText layout
        ViewGroup.LayoutParams edittext_layout_params =
            new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
                                       ViewGroup.LayoutParams.WRAP_CONTENT);
        Cocos2dxEditText edittext = new Cocos2dxEditText(this);
        edittext.setLayoutParams(edittext_layout_params);

        // ...add to FrameLayout
        framelayout.addView(edittext);

        // Cocos2dxGLSurfaceView
        this.mGLSurfaceView = this.onCreateView();

        // ...add to FrameLayout
        framelayout.addView(this.mGLSurfaceView);

        // Switch to supported OpenGL (ARGB888) mode on emulator
        if (isAndroidEmulator())
           this.mGLSurfaceView.setEGLConfigChooser(8 , 8, 8, 8, 16, 0);

        this.mGLSurfaceView.setCocos2dxRenderer(new Cocos2dxRenderer());
        this.mGLSurfaceView.setCocos2dxEditText(edittext);

        // Set framelayout as the content view
		setContentView(framelayout);
	}

这里就是为Activity绑定View Hierarchy,大家做Android开发的对着一定很熟悉。View Hierarchy的根View是个FrameLayout,FrameLayout又包含一个EditText和一个GLSurfaceView,这个GLSurfaceView就是cocos引擎用来绘制游戏画面的关键View,我们来详细分析一下它。首先看一下Cocos2dxActivity的onCreateView方法:

[java] view plaincopyprint?

  1. public Cocos2dxGLSurfaceView onCreateView() {
  2. return new Cocos2dxGLSurfaceView(this);
  3. }
public Cocos2dxGLSurfaceView onCreateView() {
    	return new Cocos2dxGLSurfaceView(this);
    }

该方法就是新建一个Cocos2dxGLSurfaceView,Cocos2dxGLSurfaceView又继承于GLSurfaceView。我们都知道GLSurfaceView的核心就是Renderer,初始化时会调用Renderer的onSurfaceCreated方法,每一帧的绘制是通过调用Renderer的onDrawFrame方法。Cocos2dxGLSurfaceView的Renderer是一个Cocos2dxRenderer对象,我们先来看Cocos2dxRenderer对象的onSurfaceCreated方法:

[java] view plaincopyprint?

  1. @Override
  2. public void onSurfaceCreated(final GL10 pGL10, final EGLConfig pEGLConfig) {
  3. Cocos2dxRenderer.nativeInit(this.mScreenWidth, this.mScreenHeight);
  4. this.mLastTickInNanoSeconds = System.nanoTime();
  5. }
@Override
	public void onSurfaceCreated(final GL10 pGL10, final EGLConfig pEGLConfig) {
		Cocos2dxRenderer.nativeInit(this.mScreenWidth, this.mScreenHeight);
		this.mLastTickInNanoSeconds = System.nanoTime();
	}

这里调用了一个本地方法nativeInit(final int pWidth, final int pHeight),本地方法的实现在jni/hellocpp/main.cpp中实现的:

[java] view plaincopyprint?

  1. void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv*  env, jobject thiz, jint w, jint h)
  2. {
  3. if (!CCDirector::sharedDirector()->getOpenGLView())
  4. {
  5. CCEGLView *view = CCEGLView::sharedOpenGLView();
  6. view->setFrameSize(w, h);
  7. AppDelegate *pAppDelegate = new AppDelegate();
  8. CCApplication::sharedApplication()->run();
  9. }
  10. else
  11. {
  12. ......
  13. }
  14. }
void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv*  env, jobject thiz, jint w, jint h)
{
    if (!CCDirector::sharedDirector()->getOpenGLView())
    {
        CCEGLView *view = CCEGLView::sharedOpenGLView();
        view->setFrameSize(w, h);

        AppDelegate *pAppDelegate = new AppDelegate();
        CCApplication::sharedApplication()->run();
    }
    else
    {
        ......
    }
}

CCDirector是游戏的导演类,一个游戏只有一个导演类用来控制和管理场景。CCDirector::sharedDirector()是个静态方法,用来获取导演类的单例对象:

[java] view plaincopyprint?

  1. CCDirector* CCDirector::sharedDirector(void)
  2. {
  3. if (!s_SharedDirector)
  4. {
  5. s_SharedDirector = new CCDisplayLinkDirector();
  6. s_SharedDirector->init();
  7. }
  8. return s_SharedDirector;
  9. }
CCDirector* CCDirector::sharedDirector(void)
{
    if (!s_SharedDirector)
    {
        s_SharedDirector = new CCDisplayLinkDirector();
        s_SharedDirector->init();
    }

    return s_SharedDirector;
}

CCCCDisplayLinkDirector是CCDirector的子类。我们再回到nativeinit方法中,获取到导演类的单例对象后又调用了它的getOpenGLView()方法:

[java] view plaincopyprint?

  1. inline CCEGLView* getOpenGLView(void) { return m_pobOpenGLView; }
inline CCEGLView* getOpenGLView(void) { return m_pobOpenGLView; }

该方法返回用于游戏绘制的CCEGLView,在Android平台下,这个CCEGLView其实没有什么作用,因为游戏都是绘制在Cocos2dxGLSurfaceView上的。由于我们是初始化过程,所以此时m_pobOpenGLView为null,所以if (!CCDirector::sharedDirector()->getOpenGLView())条件成立,执行以下的代码:

[java] view plaincopyprint?

  1. CCEGLView *view = CCEGLView::sharedOpenGLView();
  2. view->setFrameSize(w, h);
  3. AppDelegate *pAppDelegate = new AppDelegate();
  4. CCApplication::sharedApplication()->run();
   CCEGLView *view = CCEGLView::sharedOpenGLView();
   view->setFrameSize(w, h);

   AppDelegate *pAppDelegate = new AppDelegate();
   CCApplication::sharedApplication()->run();

同样,我们先获取一个CCEGLView的单例对象,接下来又新建了一个AppDelegate对象,大家可能在工程中找不到AppDelegate类。我们打开工程目录的上一级目录:

我们的Android工程是在proj.android文件夹中,而AppDelegate类就在Classes文件夹中。因为cocos2dx是跨平台的,而AppDelegate在各个平台之间是通用的不需要修改的,所以就放在一个公用的目录下。

[java] view plaincopyprint?

  1. #ifndef  _APP_DELEGATE_H_
  2. #define  _APP_DELEGATE_H_
  3. #include "cocos2d.h"
  4. /**
  5. @brief    The cocos2d Application.
  6. The reason for implement as private inheritance is to hide some interface call by CCDirector.
  7. */
  8. class  AppDelegate : private cocos2d::CCApplication
  9. {
  10. public:
  11. AppDelegate();
  12. virtual ~AppDelegate();
  13. /**
  14. @brief    Implement CCDirector and CCScene init code here.
  15. @return true    Initialize success, app continue.
  16. @return false   Initialize failed, app terminate.
  17. */
  18. virtual bool applicationDidFinishLaunching();
  19. /**
  20. @brief  The function be called when the application enter background
  21. @param  the pointer of the application
  22. */
  23. virtual void applicationDidEnterBackground();
  24. /**
  25. @brief  The function be called when the application enter foreground
  26. @param  the pointer of the application
  27. */
  28. virtual void applicationWillEnterForeground();
  29. };
  30. #endif // _APP_DELEGATE_H_
#ifndef  _APP_DELEGATE_H_
#define  _APP_DELEGATE_H_

#include "cocos2d.h"

/**
@brief    The cocos2d Application.

The reason for implement as private inheritance is to hide some interface call by CCDirector.
*/
class  AppDelegate : private cocos2d::CCApplication
{
public:
    AppDelegate();
    virtual ~AppDelegate();

    /**
    @brief    Implement CCDirector and CCScene init code here.
    @return true    Initialize success, app continue.
    @return false   Initialize failed, app terminate.
    */
    virtual bool applicationDidFinishLaunching();

    /**
    @brief  The function be called when the application enter background
    @param  the pointer of the application
    */
    virtual void applicationDidEnterBackground();

    /**
    @brief  The function be called when the application enter foreground
    @param  the pointer of the application
    */
    virtual void applicationWillEnterForeground();
};

#endif // _APP_DELEGATE_H_

AppDelegate是继承CCApplication类的,我们看一下CCApplication的构造方法:

[java] view plaincopyprint?

  1. // sharedApplication pointer
  2. CCApplication * CCApplication::sm_pSharedApplication = 0;
  3. CCApplication::CCApplication()
  4. {
  5. CCAssert(! sm_pSharedApplication, "");
  6. sm_pSharedApplication = this;
  7. }
// sharedApplication pointer
CCApplication * CCApplication::sm_pSharedApplication = 0;

CCApplication::CCApplication()
{
    CCAssert(! sm_pSharedApplication, "");
    sm_pSharedApplication = this;
}

我们看到在新建CCApplication对象时,会把该对象赋给一个全局变量sm_pSharedApplication。所以我们在new AppDelegate()的时候,就把它象赋给全局变量sm_pSharedApplication。我们再看下CCApplication的CCApplication::sharedApplication方法:

[java] view plaincopyprint?

  1. CCApplication* CCApplication::sharedApplication()
  2. {
  3. CCAssert(sm_pSharedApplication, "");
  4. return sm_pSharedApplication;
  5. }
CCApplication* CCApplication::sharedApplication()
{
    CCAssert(sm_pSharedApplication, "");
    return sm_pSharedApplication;
}

此时,sm_pSharedApplication指向的是一个AppDelegate对象。所以我们执行CCApplication::sharedApplication()->run()时其实执行的是AppDelegate对象的run方法。现在我们应该明白这个类为什么叫AppDelegate了,因为CCApplication的工作实际都委托给了AppDelegate类了。看一下AppDelegate的方法:

[java] view plaincopyprint?

  1. int CCApplication::run()
  2. {
  3. // Initialize instance and cocos2d.
  4. if (! applicationDidFinishLaunching())
  5. {
  6. return 0;
  7. }
  8. return -1;
  9. }
int CCApplication::run()
{
    // Initialize instance and cocos2d.
    if (! applicationDidFinishLaunching())
    {
        return 0;
    }

    return -1;
}

[java] view plaincopyprint?

  1. bool AppDelegate::applicationDidFinishLaunching() {
  2. // initialize director
  3. CCDirector* pDirector = CCDirector::sharedDirector();
  4. CCEGLView* pEGLView = CCEGLView::sharedOpenGLView();
  5. pDirector->setOpenGLView(pEGLView);
  6. CCSize frameSize = pEGLView->getFrameSize();
  7. // Set the design resolution
  8. #if (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
  9. pEGLView->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, kResolutionShowAll);
  10. #else
  11. pEGLView->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, kResolutionNoBorder);
  12. #endif
  13. vector<string> searchPath;
  14. // In this demo, we select resource according to the frame‘s height.
  15. // If the resource size is different from design resolution size, you need to set contentScaleFactor.
  16. // We use the ratio of resource‘s height to the height of design resolution,
  17. // this can make sure that the resource‘s height could fit for the height of design resolution.
  18. // if the frame‘s height is larger than the height of medium resource size, select large resource.
  19. if (frameSize.height > mediumResource.size.height)
  20. {
  21. searchPath.push_back(largeResource.directory);
  22. pDirector->setContentScaleFactor(MIN(largeResource.size.height/designResolutionSize.height, largeResource.size.width/designResolutionSize.width));
  23. }
  24. // if the frame‘s height is larger than the height of small resource size, select medium resource.
  25. else if (frameSize.height > smallResource.size.height)
  26. {
  27. searchPath.push_back(mediumResource.directory);
  28. pDirector->setContentScaleFactor(MIN(mediumResource.size.height/designResolutionSize.height, mediumResource.size.width/designResolutionSize.width));
  29. }
  30. // if the frame‘s height is smaller than the height of medium resource size, select small resource.
  31. else
  32. {
  33. searchPath.push_back(smallResource.directory);
  34. pDirector->setContentScaleFactor(MIN(smallResource.size.height/designResolutionSize.height, smallResource.size.width/designResolutionSize.width));
  35. }
  36. // set searching path
  37. CCFileUtils::sharedFileUtils()->setSearchPaths(searchPath);
  38. // turn on display FPS
  39. pDirector->setDisplayStats(true);
  40. // set FPS. the default value is 1.0/60 if you don‘t call this
  41. pDirector->setAnimationInterval(1.0 / 60);
  42. // create a scene. it‘s an autorelease object
  43. CCScene *pScene = HelloWorld::scene();
  44. // run
  45. pDirector->runWithScene(pScene);
  46. return true;
  47. }
bool AppDelegate::applicationDidFinishLaunching() {
    // initialize director
    CCDirector* pDirector = CCDirector::sharedDirector();
    CCEGLView* pEGLView = CCEGLView::sharedOpenGLView();

    pDirector->setOpenGLView(pEGLView);
	CCSize frameSize = pEGLView->getFrameSize();

    // Set the design resolution
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
    pEGLView->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, kResolutionShowAll);
#else
    pEGLView->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, kResolutionNoBorder);
#endif

    vector<string> searchPath;

    // In this demo, we select resource according to the frame's height.
    // If the resource size is different from design resolution size, you need to set contentScaleFactor.
    // We use the ratio of resource's height to the height of design resolution,
    // this can make sure that the resource's height could fit for the height of design resolution.

    // if the frame's height is larger than the height of medium resource size, select large resource.
	if (frameSize.height > mediumResource.size.height)
	{
        searchPath.push_back(largeResource.directory);

        pDirector->setContentScaleFactor(MIN(largeResource.size.height/designResolutionSize.height, largeResource.size.width/designResolutionSize.width));
	}
    // if the frame's height is larger than the height of small resource size, select medium resource.
    else if (frameSize.height > smallResource.size.height)
    {
        searchPath.push_back(mediumResource.directory);

        pDirector->setContentScaleFactor(MIN(mediumResource.size.height/designResolutionSize.height, mediumResource.size.width/designResolutionSize.width));
    }
    // if the frame's height is smaller than the height of medium resource size, select small resource.
	else
    {
        searchPath.push_back(smallResource.directory);

        pDirector->setContentScaleFactor(MIN(smallResource.size.height/designResolutionSize.height, smallResource.size.width/designResolutionSize.width));
    }

    // set searching path
    CCFileUtils::sharedFileUtils()->setSearchPaths(searchPath);

    // turn on display FPS
    pDirector->setDisplayStats(true);

    // set FPS. the default value is 1.0/60 if you don't call this
    pDirector->setAnimationInterval(1.0 / 60);

    // create a scene. it's an autorelease object
    CCScene *pScene = HelloWorld::scene();

    // run
    pDirector->runWithScene(pScene);

    return true;
}



时间: 2025-01-03 20:55:45

Android cocos2dx游戏开发——示例程序HelloCpp源码分析的相关文章

Android异步消息处理机制详解及源码分析

PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN.因为CSDN也支持MarkDown语法了,牛逼啊! [工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处,尊重分享成果] 最近相对来说比较闲,加上养病,所以没事干就撸些自己之前的知识点为博客,方便自己也方便别人. 1 背景 之所以选择这个知识点来分析有以下几个原因: 逛GitHub时发现关注的isuss中有人不停的在讨论Android中的Looper , Handler , Me

ym——Android仿网易新闻导航栏PagerSlidingTabStrip源码分析

转载请注明本文出自Cym的博客(http://blog.csdn.net/cym492224103),谢谢支持! 前言 最近工作比较忙,所以现在才更新博文,对不住大家了~!言归正传,我们来说说这个PagerSlidingTabStrip,它是配合ViewPager使用的导航栏,网易新闻就是用的这个导航,我们仔细观察这个导航栏不仅他是跟着ViewPager滑动而滑动,而且指示器还会随着标题的长度而动态的变化长度,还可以改变多种样式哦~! · 下载地址: Github:https://github.

Android 4.2 Wifi Display 之 Settings 源码分析(一)

一.简单背景 简单背景:随着无线互联的深入,不管是蓝牙.WIFI或者各种基于此的规范不管是UPNP还是DLNA都随着用户的需求得到了很大的发展,google 自从android 4.0引入wifi direct后,又在11月份公布的android 4.2中引入了Miracast无线显示共享,其协议在此可以下载.具体的协议部分内容比较多,本人由于水平有限,就不在这里罗列协议的内容了,只附上一份架构图供大家对其有个大致的印象. 英文缩写对应如下: HIDC: Human Interface Devi

Android异步消息处理 Handler Looper Message关系源码分析

# 标签: 读博客 对于Handler Looper Message 之前一直只是知道理论,知其然不知所以然,看了hongyang大神的源码分析,写个总结帖. 一.概念.. Handler . Looper .Message 这三者都与Android异步消息处理线程相关的概念. 异步消息处理线程启动后会进入一个无限的循环体之中,每循环一次,从其内部的消息队列中取出一个消息,然后回调相应的消息处理函数,执行完成一个消息后则继续循环.若消息队列为空,线程则会阻塞等待. 说了这一堆,那么和Handle

FiddlerCoreAPI开发(一)源码分析

1.前言 前一段时间想利用fiddlercore截取本地HTTPS的流量做一些分析,按照样例代码的注释学习了一下,没搞清楚怎么实现,后来又在网上查了些资料,对HTTPS的处理提及很少,都没有解决我的问题,主要是HTTPS证书的问题,索性自己研究了一下,终于解决了问题.我会在下篇文章中分享下我的思路,本篇文章先简单分析下fiddlercore自带样例的代码,帮助刚接触fiddlercore的人快速入门,如果有说的不对的地方,欢迎批评指正. 2.源码分析 首先从官网下载FiddlerCoreAPI

游戏开发入门500vip全套源码下载游戏开发概述

1.游戏机发展500vip全套源码下载dsluntan.com 20世纪70年×××始 首款主机magnavox odysse80年代 红白机80-90年代 各类非FC主机(PS,NDS等) PC单机游戏90年代-2000年 局域网对战游戏2000年后 大型多人游戏 页游 手游现在 VR,AR ..2.游戏是如何开发出来的,开发流程是什么? 原始的游戏比较粗糙,内容也很少,一般就一个人开发,美术与策划都由自己完成(建议看看<doom启示录>). 随着游戏逐渐变得复杂,需要多人去合作完成,分工也

《逐梦旅程 WINDOWS游戏编程之从零开始》源码分析2——GDI

GDI: 图形设备接口 1. 取得设备环境的句柄(如屏幕) 使用BeginPaint和EndPaint这两个函数,或者使用GetDC和ReleaseDC这两个函数.关于函数的具体说明可以参考mdsn文档. 一个GDI程序通用框架: 1 #include <windows.h> 2 3 #define WINDOW_WIDTH 800 //为窗口宽度定义的宏,以方便在此处修改窗口宽度 4 #define WINDOW_HEIGHT 600 //为窗口高度定义的宏,以方便在此处修改窗口高度 5 #

Android实现多个倒计时优化与源码分析

因为之前有个项目需求是需要时时刻去更新UI倒计时,之前想到的,这简单嘛,用计时或者Handler就可以搞定,而且性能也不错,但是需求要ListView,什么,?大量的View都需要,那Handle处理不好会挂的啊,那轮训呢,?太消耗内存和Cpu,突然之前只有想到用Handle去处理,但是Item太多如何管理呢.?带着这样的问题,思考着纠结着,今天无意中看到一个源码还不错, 这个类是Google原生提供的数字时钟,可以实现时时刻刻的更新,我想里面肯定封装了一些实现的逻辑就跟着开始研究学习,下面是该

Android 轻量级ORM数据库开源框架ActiveAndroid 源码分析

ActiveAndroid 项目地址在https://github.com/pardom/ActiveAndroid 关于他的详细介绍和使用步骤 可以看下面两篇文章: https://github.com/pardom/ActiveAndroid/wiki http://www.future-processing.pl/blog/persist-your-data-activeandroid-and-parse/ 请确保你在阅读本文下面的内容之前 熟读上面的2篇文章.我不会再讲一遍如何使用这个框