接上文,在进入主循环之前会进行相关初始化。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()之后我会对其进行研究。