Egret源码分析-主循环

前言

学习一个游戏引擎,最好的做法就是先看它的主循环!了解主循环,基本就了解了引擎的各个模块的执行方式。

游戏启动

在游戏的indxe.html中有下面几行代码。

1
2
3
4
egret_h5.preloadScript(egret_file_list, "libs/");
egret_h5.preloadScript(game_file_list, "bin-debug/src/");
// 加载玩脚本之后,启动游戏
egret_h5.startLoading();

egret_h5.startGame方法

这个方法在egret_loader.js中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
egret_h5.startGame = function () {
// 初始化各中context,从它们的名字可以看出它们的功能
var context = egret.MainContext.instance;
context.touchContext = new egret.HTML5TouchContext();
context.deviceContext = new egret.HTML5DeviceContext();
context.netContext = new egret.HTML5NetContext();

// 初始化屏幕显示的参数
egret.StageDelegate.getInstance().setDesignSize(GAME_WIDTH, GAME_HEIGHT);
context.stage = new egret.Stage();
var scaleMode = egret.MainContext.deviceType == egret.MainContext.DEVICE_MOBILE ? egret.StageScaleMode.SHOW_ALL : egret.StageScaleMode.SHOW_ALL;
context.stage.scaleMode = scaleMode;

// 这里设置游戏的渲染部分采用canvas,而不是webgl
//WebGL是egret的Beta特性,默认关闭
var rendererType = 0;
if (rendererType == 1) {// egret.WebGLUtils.checkCanUseWebGL()) {
console.log("使用WebGL模式");
context.rendererContext = new egret.WebGLRenderer();
}
else {
context.rendererContext = new egret.HTML5CanvasRenderer();
}

egret.MainContext.instance.rendererContext.texture_scale_factor = 1;

// 启动游戏的大循环(在里面注册了定时器)
context.run();

// 将文档类加到舞台(stage上)
// 这个文档累,就是在egretProperties.json里面写的document_class
var rootClass;
if(document_class){
rootClass = egret.getDefinitionByName(document_class);
}
if(rootClass) {
var rootContainer = new rootClass();
if(rootContainer instanceof egret.DisplayObjectContainer){
context.stage.addChild(rootContainer);
}
else{
throw new Error("文档类必须是egret.DisplayObjectContainer的子类!");
}
}
else{
throw new Error("找不到文档类!");
}

//处理屏幕大小改变
var resizeTimer = null;
var doResize = function () {
context.stage.changeSize();
resizeTimer = null;
};
window.onresize = function () {
if (resizeTimer == null) {
resizeTimer = setTimeout(doResize, 300);
}
};
};

MainContext.run方法

1
2
3
4
5
6
7
8
9
10
MainContext.prototype.run = function () {
egret.Ticker.getInstance().run();
// 在Ticker中注册:主循环函数,优先级最低(最后被执行)
egret.Ticker.getInstance().register(this.renderLoop, this, Number.NEGATIVE_INFINITY);
// 每一帧刚开始被触发的函数,优先级最高(最先被执行)
egret.Ticker.getInstance().register(this.broadcastEnterFrame, this, Number.POSITIVE_INFINITY);
this.touchContext.run();
// 左上角显示FPS之类的文字,就是靠它了
this._profileInstance = egret.Profiler.getInstance();
};

MainContext.renderLoop方法

这个就是本篇文章的主角了!游戏的主循环。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
MainContext.prototype.renderLoop = function (frameTime) {
// 延迟到渲染开始之前执行的函数,可以通过egret.callLater来注册
if (egret.__callLaterFunctionList.length > 0) {
var functionList = egret.__callLaterFunctionList;
egret.__callLaterFunctionList = [];
var thisList = egret.__callLaterThisList;
egret.__callLaterThisList = [];
var argsList = egret.__callLaterArgsList;
egret.__callLaterArgsList = [];
}
var stage = this.stage;
// 派发egret.Event.RENDER事件
var event = MainContext.cachedEvent;
event._type = egret.Event.RENDER;
this.dispatchEvent(event);
if (egret.Stage._invalidateRenderFlag) {
this.broadcastRender();
egret.Stage._invalidateRenderFlag = false;
}
if (functionList) {
this.doCallLaterList(functionList, thisList, argsList);
}
if (egret.__callAsyncFunctionList.length > 0) {
this.doCallAsyncList();
}

// 执行渲染(渲染这部分,会单独写一篇文章介绍)
var context = this.rendererContext;
context.onRenderStart();
context.clearScreen();
MainContext.__DRAW_COMMAND_LIST = [];
MainContext._renderLoopPhase = "updateTransform";
stage._updateTransform();
MainContext._renderLoopPhase = "draw";
event._type = egret.Event.FINISH_UPDATE_TRANSFORM;
this.dispatchEvent(event);
if (MainContext.__use_new_draw) {
this._draw(context);
}
else {
stage._draw(context);
}
event._type = egret.Event.FINISH_RENDER;
this.dispatchEvent(event);
if (this._profileInstance._isRunning) {
this._profileInstance._drawProfiler();
}
context.onRenderFinish();
//~ 渲染结束
};

转载本站文章请注明作者(xtutu)和出处 xtutu