Cocos2dx 追踪cpp-tests运行流程(2)

本文深入解析Cocos2d-x游戏引擎的初始化流程,重点介绍了applicationDidFinishLaunching函数的工作原理及其内部调用过程,包括配置加载、资源路径设置、GLView创建等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

接上文,在进入主循环之前会进行相关初始化。applicationDidFinishLaunching()函数会被执行。本部分详细追踪cpp-tests中该函数。

首先进入applicationDidFinishLaunching()函数.

bool AppDelegate::applicationDidFinishLaunching()
{
    // As an example, load config file
    // FIXME:: This should be loaded before the Director is initialized,
    // FIXME:: but at this point, the director is already initialized
    Configuration::getInstance()->loadConfigFile("configs/config-example.plist");//加载程序的配置

    // initialize director
    auto director = Director::getInstance();//导演
    auto glview = director->getOpenGLView();//glview
    if(!glview) {//若glview未初始化
        glview = GLViewImpl::create("Cpp Tests");//初始化glview
        director->setOpenGLView(glview);//设置所使用的glview
    }

    director->setDisplayStats(true);//是否显示帧率
    director->setAnimationInterval(1.0 / 60);//设置帧率 60帧

    auto screenSize = glview->getFrameSize();//得到的大小
    auto designSize = Size(480, 320);//设计大小

    auto fileUtils = FileUtils::getInstance();
    std::vector<std::string> searchPaths;
    
    if (screenSize.height > 320)//根据界面大小选择资源路径
    {
        auto resourceSize = Size(960, 640);
        searchPaths.push_back("hd");
        searchPaths.push_back("ccs-res/hd");
        searchPaths.push_back("ccs-res/hd/scenetest");
        searchPaths.push_back("ccs-res/hd/scenetest/ArmatureComponentTest");
        searchPaths.push_back("ccs-res/hd/scenetest/AttributeComponentTest");
        searchPaths.push_back("ccs-res/hd/scenetest/BackgroundComponentTest");
        searchPaths.push_back("ccs-res/hd/scenetest/EffectComponentTest");
        searchPaths.push_back("ccs-res/hd/scenetest/LoadSceneEdtiorFileTest");
        searchPaths.push_back("ccs-res/hd/scenetest/ParticleComponentTest");
        searchPaths.push_back("ccs-res/hd/scenetest/SpriteComponentTest");
        searchPaths.push_back("ccs-res/hd/scenetest/TmxMapComponentTest");
        searchPaths.push_back("ccs-res/hd/scenetest/UIComponentTest");
        searchPaths.push_back("ccs-res/hd/scenetest/TriggerTest");
        searchPaths.push_back("ccs-res");
        searchPaths.push_back("Manifests");
        director->setContentScaleFactor(resourceSize.height/designSize.height);
        
        searchPaths.push_back("ccs-res/hd/cocosui/UIEditorTest/UIButton");
        searchPaths.push_back("ccs-res/hd/cocosui/UIEditorTest/UICheckBox");
        searchPaths.push_back("ccs-res/hd/cocosui/UIEditorTest/UIImageView");
        searchPaths.push_back("ccs-res/hd/cocosui/UIEditorTest/UILabel");
        searchPaths.push_back("ccs-res/hd/cocosui/UIEditorTest/UILabelBMFont");
        searchPaths.push_back("ccs-res/hd/cocosui/UIEditorTest/UILayout/BackgroundImage");
        searchPaths.push_back("ccs-res/hd/cocosui/UIEditorTest/UILayout/Color");
        searchPaths.push_back("ccs-res/hd/cocosui/UIEditorTest/UILayout/Layout");
        searchPaths.push_back("ccs-res/hd/cocosui/UIEditorTest/UILayout/Gradient_Color");
        searchPaths.push_back("ccs-res/hd/cocosui/UIEditorTest/UILayout/Scale9_BackgroundImage");
        searchPaths.push_back("ccs-res/hd/cocosui/UIEditorTest/UILayout/LayoutComponent");
        searchPaths.push_back("ccs-res/hd/cocosui/UIEditorTest/UILoadingBar");
        searchPaths.push_back("ccs-res/hd/cocosui/UIEditorTest/UIPageView");
        searchPaths.push_back("ccs-res/hd/cocosui/UIEditorTest/UIScrollView/Both");
        searchPaths.push_back("ccs-res/hd/cocosui/UIEditorTest/UIScrollView/Horizontal");
        searchPaths.push_back("ccs-res/hd/cocosui/UIEditorTest/UIScrollView/Vertical");
        searchPaths.push_back("ccs-res/hd/cocosui/UIEditorTest/UISlider");
        searchPaths.push_back("ccs-res/hd/cocosui/UIEditorTest/UITextField");
        searchPaths.push_back("ccs-res/hd/cocosui/UIEditorTest/UIWidgetAddNode");
        searchPaths.push_back("ccs-res/hd/cocosui/UIEditorTest/UIListView/New");
        
        searchPaths.push_back("ccs-res/hd/cocosui/CustomTest/CustomWidgetCallbackBindTest");
        searchPaths.push_back("hd/ActionTimeline");
        searchPaths.push_back("ccs-res/hd/armature");
    }
    else
    {
        searchPaths.push_back("ccs-res");
        searchPaths.push_back("ccs-res/scenetest/ArmatureComponentTest");
        searchPaths.push_back("ccs-res/scenetest/AttributeComponentTest");
        searchPaths.push_back("ccs-res/scenetest/BackgroundComponentTest");
        searchPaths.push_back("ccs-res/scenetest/EffectComponentTest");
        searchPaths.push_back("ccs-res/scenetest/LoadSceneEdtiorFileTest");
        searchPaths.push_back("ccs-res/scenetest/ParticleComponentTest");
        searchPaths.push_back("ccs-res/scenetest/SpriteComponentTest");
        searchPaths.push_back("ccs-res/scenetest/TmxMapComponentTest");
        searchPaths.push_back("ccs-res/scenetest/UIComponentTest");
        searchPaths.push_back("ccs-res/scenetest/TriggerTest");
        
        searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UIButton");
        searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UICheckBox");
        searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UIImageView");
        searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UILabel");
        searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UILabelBMFont");
        searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UILayout/BackgroundImage");
        searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UILayout/Color");
        searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UILayout/Layout");
        searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UILayout/Gradient_Color");
        searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UILayout/Scale9_BackgroundImage");
        searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UILayout/LayoutComponent");
        searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UILoadingBar");
        searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UIPageView");
        searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UIScrollView/Both");
        searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UIScrollView/Horizontal");
        searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UIScrollView/Vertical");
        searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UISlider");
        searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UITextField");
        searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UIWidgetAddNode");
        searchPaths.push_back("ccs-res/cocosui/UIEditorTest/UIListView/New");
        
        searchPaths.push_back("ccs-res/cocosui/CustomTest/CustomWidgetCallbackBindTest");
        searchPaths.push_back("ActionTimeline");
        searchPaths.push_back("ccs-res/armature");
    }
    
    fileUtils->setSearchPaths(searchPaths);//设置资源查找路径

    glview->setDesignResolutionSize(designSize.width, designSize.height, ResolutionPolicy::SHOW_ALL);//设计尺寸 涉及到屏幕适配 
    
    // Enable Remote Console
    auto console = director->getConsole();//远程调试
    console->listenOnTCP(5678);//监听端口5678

    _testController = TestController::getInstance();//控制类 控制例子运行
    
    return true;
}

详细注释我都写在了代码上。其中有几个函数可以追踪看看到底是如何做的。

追踪一下    Configuration::getInstance()->loadConfigFile("configs/config-example.plist");//加载程序的配置

这可以帮助我们理解Cocos到底是如何进行相关程序配置的。(注:plist文件是xml格式的)

void Configuration::loadConfigFile(const std::string& filename)
{
	ValueMap dict = FileUtils::getInstance()->getValueMapFromFile(filename);
	CCASSERT(!dict.empty(), "cannot create dictionary");

	// search for metadata
	bool validMetadata = false;
	auto metadataIter = dict.find("metadata");
	if (metadataIter != dict.cend() && metadataIter->second.getType() == Value::Type::MAP)
    {
        
		const auto& metadata = metadataIter->second.asValueMap();
        auto formatIter = metadata.find("format");
        
		if (formatIter != metadata.cend())
        {
			int format = formatIter->second.asInt();

			// Support format: 1
			if (format == 1)
            {
				validMetadata = true;
			}
		}
	}

	if (! validMetadata)
    {
		CCLOG("Invalid config format for file: %s", filename.c_str());
		return;
	}

	auto dataIter = dict.find("data");
	if (dataIter == dict.cend() || dataIter->second.getType() != Value::Type::MAP)
    {
		CCLOG("Expected 'data' dict, but not found. Config file: %s", filename.c_str());
		return;
	}

	// Add all keys in the existing dictionary
    
	const auto& dataMap = dataIter->second.asValueMap();
    for (auto dataMapIter = dataMap.cbegin(); dataMapIter != dataMap.cend(); ++dataMapIter)
    {
        if (_valueDict.find(dataMapIter->first) == _valueDict.cend())
            _valueDict[dataMapIter->first] = dataMapIter->second;
        else
            CCLOG("Key already present. Ignoring '%s'",dataMapIter->first.c_str());
    }
    
    //light info
    std::string name = "cocos2d.x.3d.max_dir_light_in_shader";
	if (_valueDict.find(name) != _valueDict.end())
        _maxDirLightInShader = _valueDict[name].asInt();
    else
        _valueDict[name] = Value(_maxDirLightInShader);
    
    name = "cocos2d.x.3d.max_point_light_in_shader";
	if (_valueDict.find(name) != _valueDict.end())
        _maxPointLightInShader = _valueDict[name].asInt();
    else
        _valueDict[name] = Value(_maxPointLightInShader);
    
    name = "cocos2d.x.3d.max_spot_light_in_shader";
	if (_valueDict.find(name) != _valueDict.end())
        _maxSpotLightInShader = _valueDict[name].asInt();
    else
        _valueDict[name] = Value(_maxSpotLightInShader);
    
    name = "cocos2d.x.3d.animate_quality";
    if (_valueDict.find(name) != _valueDict.end())
        _animate3DQuality = (Animate3DQuality)_valueDict[name].asInt();
    else
        _valueDict[name] = Value((int)_animate3DQuality);
}

 FileUtils::getInstance()->getValueMapFromFile(filename);该句将xml格式的plist文件处理成ValueMap。

 ValueMap的格式是std::unordered_map<std::string, Value>,Value保存的类型可以是以下格式

   enum class Type
    {
        /// no value is wrapped, an empty Value
        NONE = 0,
        /// wrap byte
        BYTE,
        /// wrap integer
        INTEGER,
        /// wrap float
        FLOAT,
        /// wrap double
        DOUBLE,
        /// wrap bool
        BOOLEAN,
        /// wrap string
        STRING,
        /// wrap vector
        VECTOR,
        /// wrap ValueMap
        MAP,
        /// wrap ValueMapIntKey
        INT_KEY_MAP
    };

把plist文件打开。其中保存的都是配置信息。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>data</key>
	<dict>
		<key>cocos2d.x.fps</key>
		<integer>60</integer>
		<key>cocos2d.x.display_fps</key>
		<true/>
		<key>cocos2d.x.gl.projection</key>
		<string>3d</string>
		<key>cocos2d.x.texture.pixel_format_for_png</key>
		<string>rgba8888</string>
		<key>cocos2d.x.texture.pvrv2_has_alpha_premultiplied</key>
		<false/>
		<key>cocos2d.x.testcpp.autorun</key>
		<false/>
		<key>cocos2d.x.3d.max_dir_light_in_shader</key>
		<integer>1</integer>
		<key>cocos2d.x.3d.max_point_light_in_shader</key>
		<integer>1</integer>
		<key>cocos2d.x.3d.max_spot_light_in_shader</key>
		<integer>1</integer>
		<key>cocos2d.x.3d.animate_quality</key>
		<integer>2</integer>
	</dict>
	<key>metadata</key>
	<dict>
		<key>format</key>
		<integer>1</integer>
	</dict>
</dict>
</plist>

loadConfigFile()最终将配置信息都存在了_valueDict中,_valueDict是ValueMap的实例。

这里保存的配置只是保存到了Configuration(单例)的实例中,并没有成功写入程序配置,写入程序配置是在Director的初始化时完成的。

void Director::setDefaultValues(void)
{
    Configuration *conf = Configuration::getInstance();

    // default FPS
    double fps = conf->getValue("cocos2d.x.fps", Value(kDefaultFPS)).asDouble();
    _oldAnimationInterval = _animationInterval = 1.0 / fps;

    // Display FPS
    _displayStats = conf->getValue("cocos2d.x.display_fps", Value(false)).asBool();

    // GL projection
    std::string projection = conf->getValue("cocos2d.x.gl.projection", Value("3d")).asString();
    if (projection == "3d")
        _projection = Projection::_3D;
    else if (projection == "2d")
        _projection = Projection::_2D;
    else if (projection == "custom")
        _projection = Projection::CUSTOM;
    else
        CCASSERT(false, "Invalid projection value");

    // Default pixel format for PNG images with alpha
    std::string pixel_format = conf->getValue("cocos2d.x.texture.pixel_format_for_png", Value("rgba8888")).asString();
    if (pixel_format == "rgba8888")
        Texture2D::setDefaultAlphaPixelFormat(Texture2D::PixelFormat::RGBA8888);
    else if(pixel_format == "rgba4444")
        Texture2D::setDefaultAlphaPixelFormat(Texture2D::PixelFormat::RGBA4444);
    else if(pixel_format == "rgba5551")
        Texture2D::setDefaultAlphaPixelFormat(Texture2D::PixelFormat::RGB5A1);

    // PVR v2 has alpha premultiplied ?
    bool pvr_alpha_premultipled = conf->getValue("cocos2d.x.texture.pvrv2_has_alpha_premultiplied", Value(false)).asBool();
    Image::setPVRImagesHavePremultipliedAlpha(pvr_alpha_premultipled);
}

另外一个关注点:

 glview = GLViewImpl::create("Cpp Tests");//初始化glview

整个cpp-tests到此才真正初始化了glview。

GLViewImpl* GLViewImpl::create(const std::string& viewName)
{
    auto ret = new (std::nothrow) GLViewImpl;
    if(ret && ret->initWithRect(viewName, Rect(0, 0, 960, 640), 1)) {
        ret->autorelease();
        return ret;
    }

    return nullptr;
}
我们可以看到GLViewImpl加入了自动释放池。这就解释了之前对其retain()的操作。在这里还可以更改生成的窗口大小。(在其它地方也能改)


最后一个需要关注的点是:

_testController = TestController::getInstance();//控制类 控制例子运行

这是所有在cpp-tests中进行的例子的控制器。转到该函数

TestController* TestController::getInstance()
{
    if (s_testController == nullptr)
    {
        s_testController = new (std::nothrow) TestController;

        initCrashCatch();//initCrashCatch();http://blog.youkuaiyun.com/starlee/article/details/6613424  目的大概是 让程序在崩溃时体面的退出
    }

    return s_testController;
}

在该函数中进行了TestController的首次初始化。其初始化代码

TestController::TestController()
: _stopAutoTest(true)
, _isRunInBackground(false)
, _testSuite(nullptr)
{
    _rootTestList = new (std::nothrow) RootTests;  //根界面
    _rootTestList->runThisTest();		//显示根界面      函数中运行了director->replaceScene(scene);
    _director = Director::getInstance();

    _touchListener = EventListenerTouchOneByOne::create();//给程序添加触摸回调机制  onebyone代表单点触摸
    _touchListener->onTouchBegan = CC_CALLBACK_2(TestController::blockTouchBegan, this);//绑定触摸回调函数
    _touchListener->setSwallowTouches(true);//设置触摸不可以向下传 简单点来说,比如有两个sprite ,A 和 B,A在上B在下(位置重叠),触摸A的时候,B不会受到影响

    _director->getEventDispatcher()->addEventListenerWithFixedPriority(_touchListener, -200);//触摸添加到监听,优先度 - 200 很高的
}


具体内容涉及到contoller.h的内容,较为复杂。在研究完mainloop()之后我会对其进行研究。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值