赞 | 65 |
VIP | 231 |
好人卡 | 2 |
积分 | 19 |
经验 | 35171 |
最后登录 | 2024-9-15 |
在线时间 | 1554 小时 |
Lv3.寻梦者
- 梦石
- 0
- 星屑
- 1912
- 在线时间
- 1554 小时
- 注册时间
- 2013-4-13
- 帖子
- 917
|
加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有帐号?注册会员
x
第三章 时空管理者的日常
我们从SceneManager.run(Scene_Boot)说起
当web页面加载完毕后这条语句就会被执行
Scene_Boot是一个特殊的场景(Scene)
我们暂且不提,
先来说说SceneManager这个游戏世界的时空主宰者的故事
SceneManager人如其名主要负责场景的加载和卸载
我们先来看看这个SceneManager.run方法都做了什么
- SceneManager.run = function (sceneClass) {
- try {
- this.initialize();
- this.goto(sceneClass);
- this.requestUpdate();
- } catch (e) {
- this.catchException(e);
- }
- };
复制代码
SceneManager.initialize做了很多检查错误和初始化场景的工作具体内容比如Graphics的内容会放到以后再说
SceneManager.goto(sceneClass)的作用是停止当前场景
创建新场景(根据传入的sceneClass类)并标记为_nextScene
- SceneManager.goto = function (sceneClass) {
- if (sceneClass) {
- this._nextScene = new sceneClass();
- }
- if (this._scene) {
- this._scene.stop();
- }
- };
复制代码 然后最后执行requestUpdate方法其中requestAnimationFrame方法可以理解为下一帧时执行传入的方法
但是这一帧并不一定是一个稳定的时间间隔, 对于游戏来说并不是可靠的帧
- SceneManager.requestUpdate = function () {
- if (!this._stopped) {
- requestAnimationFrame(this.update.bind(this));
- }
- };
复制代码 下面我们来看update方法:
- SceneManager.update = function () {
- try {
- this.tickStart();
- if (Utils.isMobileSafari()) {
- this.updateInputData();
- }
- this.updateManagers();
- this.updateMain();
- this.tickEnd();
- } catch (e) {
- this.catchException(e);
- }
- };
复制代码 其中tickStart和tickEnd使用了fpsMeter库的方法来计算requestAnimationFrame具体到底过了多少帧
其实主要我们在这里关心的只有:updateMain- SceneManager.updateMain = function () {
- if (Utils.isMobileSafari()) {
- this.changeScene();
- this.updateScene();
- } else {
- var newTime = this._getTimeInMsWithoutMobileSafari();
- var fTime = (newTime - this._currentTime) / 1000;
- if (fTime > 0.25) fTime = 0.25;
- this._currentTime = newTime;
- this._accumulator += fTime;
- while (this._accumulator >= this._deltaTime) {
- this.updateInputData();
- this.changeScene();
- this.updateScene();
- this._accumulator -= this._deltaTime;
- }
- }
- this.renderScene();
- this.requestUpdate();
- };
复制代码
其中updateInputData()是用来处理用户输入状态的, 跟平台是相关的
抛去和平台相关和处理帧率的代码, 最终总共呼叫了其他4个方法
changeScene();
updateScene();
renderScene();
requestUpdate();
先来看 changeScene
- SceneManager.changeScene = function () {
- if (this.isSceneChanging() && !this.isCurrentSceneBusy()) {
- if (this._scene) {
- this._scene.terminate();
- this._scene.detachReservation();
- this._previousClass = this._scene.constructor;
- }
- this._scene = this._nextScene;
- if (this._scene) {
- this._scene.attachReservation();
- this._scene.create();
- this._nextScene = null;
- this._sceneStarted = false;
- this.onSceneCreate();
- }
- if (this._exiting) {
- this.terminate();
- }
- }
- };
复制代码 这个方法主要负责场景的切换
如果有下一个场景, 那么当前场景中止, 场景管理将_scene指向_nextScene并将_nextScene清空
如果没有下一个场景, 那么整个游戏将被结束
isSceneChanging() 是检测是否存在this._exiting或this._nextScene的判断方法
也就是是不是要退出场景或者跳转到下一个场景
我们在呼叫run()的时候就创建了一个新场景并标记为this._nextScene
所以这里会第一次返回true
this.isCurrentSceneBusy()是判断当前场景是否在忙碌detachReservation, detachReservation是图像缓存相关的方法, 以后有机会再仔细分析
_scene.create是各个Scene类自己重载的初始化方法
接下来是updateScene()
- SceneManager.updateScene = function () {
- if (this._scene) {
- if (!this._sceneStarted && this._scene.isReady()) {
- this._scene.start();
- this._sceneStarted = true;
- this.onSceneStart();
- }
- if (this.isCurrentSceneStarted()) {
- this._scene.update();
- }
- }
- };
复制代码 这个方法调用了场景的update方法从而让场景的状态刷新
this._scene.isReady是判断资源是否加载完毕的, 每个Scene类都可以覆写这个方法
如果this._sceneStarted没有设置为true, 就需要进行一次初始化
执行_scene的start方法, 每个Scene类都可以覆写这个方法
如果已经started了, 那么就会执行this._scene.update()方法
一样这个方法各个不同的scene都可以覆写父类的规则
那么问题来了之前在changeScene里已经有了create这个方法
那么create和start有什么区别呢?
答案就是create不需要资源加载完毕, 而start必须资源加载完毕
因为资源加载是个异步的过程
在run的第一个requestAnimationFrame里_scene就已经create()了
但是下一requestAnimationFrame里_scene并不一定会执行start()
玩家会停留在loading界面里直到资源完全加载完毕, 使得this._scene.isReady()返回true
renderScene用来执行场景的图形渲染, 如果资源未加载完毕则渲染加载界面
图形部分留到以后再说吧~偷懒~
最后再一次呼叫requestUpdate让整个流程在下一个requestAnimationFrame里再循环
这就是一个简略的Game Loop的源码分析了
SceneManager除了run以外还有操作场景栈, 预加载, 暂停和恢复等等其他方法
由于篇幅的原因留到以后遇到了再说.
|
评分
-
查看全部评分
|