前言:由于H5游戏很多时候需要大量加载网络资源,所以加载的过程处理好是一件很重要的事情,而把加载的过程制作成一个流畅的动画是一个非常好的解决方案。大到3A大作《巫师》系类《COD》系列...都把加载过程弄成一个过场动画,小到微信小游戏海盗来了,把加载动画设置成云雾的散去。
思路:
1.先加载LoadingScene以及对应的LoadingView,LoadingView遮挡住后面的内容。
2.在LoadingView的背后加载场景Scene以及场景View的过程中,同时在LoadingView前面显示进度
3.加载完成后,以动画的形式,消除掉LoadingView遮挡的内容,顺便关闭掉LoadingScene。
示例:(这里演示的是简单的过渡动画,可以自行替换成深度自定义的动画)
这篇笔记基于Egret通用MVC框架(详情请看笔记一),下载打开通用框架。
源代码有时间我会放到“我的资源”中。
步骤一:在Main.ts中配置好Loading相关事项。
打开:\src\Main.ts:
确认LoadingScene注册上了:
/**
* 初始化所有场景
*/
private initScene(): void {
App.SceneManager.register(SceneConsts.LOADING, new LoadingScene());
//App.SceneManager.register(SceneConsts.UI, new UIScene());
// App.SceneManager.register(SceneConsts.UI, new UIScene());
//App.SceneManager.register(SceneConsts.Game, new GameScene());
//App.SceneManager.register(SceneConsts.Demo, new DemoScene()); //rongqingmei
App.SceneManager.register(SceneConsts.RpgGame, new RpgGameScene());
}
确认Loading模块注册上了:
/**
* 初始化所有模块
*/
private initModule(): void {
App.ControllerManager.register(ControllerConst.Loading, new LoadingController());
}
确认在游戏场景加载入口有开启LoadingScene:
/**
* 主题文件加载完成
*/
private onThemeLoadComplete(): void {
//模块初始化
this.initModule();
//设置加载进度界面
App.SceneManager.runScene(SceneConsts.LOADING);
//开启游戏
new RpgTest();
//new ActTest();
//new ProtoBufTest();
//new EUITest();
//new StarlingSwfTest();
//new DemoTest();
}
步骤二:增加新的加载场景方式。之前是删除旧场景,再增加新场景,现在的新方式是,增加新场景,延迟删除旧场景。
先理顺加载逻辑
\src\example\test\RpgTest.ts
RpgTest()中的构造函数中有一句函数:
App.ResourceUtils.loadGroups(groupName, subGroups, this.onResourceLoadComplete, this.onResourceLoadProgress, this);
这句函数的意思是开启加载资源,加载完成会执行SceneManager,载入新的场景
this.onResourceLoadComplete:
/**
* 资源组加载完成
*/
private onResourceLoadComplete(): void {
this.initModule();
App.Init();
//音乐音效处理
App.SoundManager.setBgOn(true);
App.SoundManager.setEffectOn(true);
//进入游戏
App.SceneManager.runScene(SceneConsts.RpgGame, this.mapId);
}
这里面的SceneManager.runScene是一个删除旧场景,再增加新场景的方法,现在我们要增加一个类似的方法,名叫SceneManager.LoadingrunScene,意思是增加新场景,延迟删除旧场景。
修改的地方:\src\core\scene\manager\SceneManager.ts
SceneManager.ts添加函数 LoadingrunScene()
/**
* 延时切换场景(加载场景加载完成后)
* @param key 场景唯一标识
*/
private DelayOldScene:BaseScene;
public LoadingrunScene(key:number,time:number, ...param:any[]):void {
var nowScene:BaseScene = this._scenes[key];
if (nowScene == null) {
Log.trace("场景" + key + "不存在");
return;
}
//记录旧的场景的代号,用于之后来销毁退出
this.DelayOldScene = this._scenes[this._currScene];
//设定定时器用来一定时间后退出旧的
var timer: egret.Timer = new egret.Timer(time, 1);
//timer.addEventListener(egret.TimerEvent.TIMER, this.timerFunc, this);
timer.addEventListener(egret.TimerEvent.TIMER_COMPLETE, this.timerComFunc, this);
timer.start();
//载入新的场景
nowScene.onEnter.apply(nowScene, param);
this._currScene = key;
}
private timerComFunc():void{
if (this.DelayOldScene) {
//console.log("this.DelayOldScenexxxxxxxxxxxxxxx",this.DelayOldScene);
this.DelayOldScene.onExit();
}
}
其中与原来的runScene函数对比,增加了一个time参数,就是加载了新场景后,经过time:number之后的时间,旧的场景才会被移除。(Loading场景需要播放完动画才会被移除)
修改的地方:\src\example\test\RpgTest.ts
加载资源完成后,新场景的进入模式换为我们写好的SceneManager.LoaingrunScene。
this.onResourceLoadComplete:
修改 “//进入游戏” 下面的内容
/**
* 资源组加载完成
*/
private onResourceLoadComplete(): void {
this.initModule();
App.Init();
//音乐音效处理
App.SoundManager.setBgOn(true);
App.SoundManager.setEffectOn(true);
//进入游戏
App.SceneManager.LoadingrunScene(SceneConsts.RpgGame,3000, this.mapId);
}
步骤三. 修改LoadingScene.ts的Layer层级,以及重写Exit()函数。
因为新旧场景会同时存在一段时间,所以两个场景要分好层级,LoadingScene在上,新场景在下。
而且由于LoadingScene.ts原先的Exit()函数会关闭掉当前所有的Scene,所以要进行重写,只关闭掉自己的LoadingScene,别把新加载进来的Scene也关闭了。
修改Layer层级:
1.修改的地方:\src\example\scene\LoadingScene.ts 中的onEnter()函数
this.addLayer(LayerManager.UI_Main),改为:this.addLayer(LayerManager.Game_Loading);
参考代码:
/**
* 进入Scene调用
*/
public onEnter():void{
super.onEnter();
//添加该Scene使用的层级
this.addLayer(LayerManager.Game_Loading);
//初始打开Loading页面
App.ViewManager.open(ViewConst.Loading);
}
2. 这个Game_Loading需要添加到:\src\example\scene\LayerManager.ts:
/**
* Loading层
* @type {BaseEuiLayer}
*/
public static Game_Loading:BaseEuiLayer = new BaseEuiLayer();
3.LoadingController修改View挂载的层级
\src\example\module\loading\LoadingController.ts 的constructor()构造函数
//初始化UI
this.loadingView = new LoadingView(this, LayerManager.Game_Loading);
4.RpgGameScene添加对Game_Loading的layer层级的支持,不然加载完新的场景,Game_Loading层级就被压到底下不显示了
\src\example\scene\RpgGameScene.ts 的onEnter()函数:
this.addLayer(LayerManager.Game_Loading);
修改onExit()函数:
/**
* 退出Scene调用
*/
public onExit():void{
//super.onExit();
//关闭loadingScene中的所有View
App.ViewManager.close(ViewConst.Loading);
//移除自身所有的layer
this.removeAllLayer();
}
步骤四,LoadingView.ts中加载完成之后,播放相应的动画
之前的步骤已经能实现,加载新场景后,旧场景3s后自动消失,现在要做的是消失前,LoadingView完成一个动画。
\src\example\module\loading\LoadingView.ts:
1.修改setProgress()函数:
public setProgress(current: number, total: number): void {
this.txtMsg.text = "资源加载中..." + current + "/" + total;
if (current == total) {
this.playDoneAinma();
}
}
2.添加播放动画的函数:
private playDoneAinma(): void {
if (this.flag) {
this.flag = false;
let self = this;
//左挡板
let temp1x = self.zuoRect.x;
let Tween1 = egret.Tween.get(self.zuoRect).to({ x: temp1x - 600 ,alpha:1.0}, 2000);
//右挡板
let temp2x = self.youRect.x;
let Tween2 = egret.Tween.get(self.youRect).to({ x: temp2x + 600 ,alpha:1.0}, 2000);
//文字
let Tween3 = egret.Tween.get(self.txtMsg).to({ alpha: 0 }, 1400);
}
}
3.修改LoadingView的皮肤文件LoadingUISkin.exml
\resource\skins\LoadingUISkin.exml
<?xml version='1.0' encoding='utf-8'?>
<e:Skin class="LoadingUISkin" width="500" height="1000" xmlns:e="http://ns.egret.com/eui" xmlns:w="http://ns.egret.com/wing">
<e:Group width="482" height="397" anchorOffsetX="0" anchorOffsetY="0" horizontalCenter="1" verticalCenter="-1.5">
<e:Rect id="zuoRect" width="694.67" height="1065.34" x="-281.67" anchorOffsetX="0" anchorOffsetY="0" scaleX="1" scaleY="1" verticalCenter="14" fillColor="0xf4f4f4"/>
<e:Rect id="youRect" width="659.67" height="1052" x="75" anchorOffsetX="0" anchorOffsetY="0" fillColor="0xffffff" scaleX="1" scaleY="1" verticalCenter="3.5"/>
<e:Label id="txtMsg" text="资源加载中..." width="249" size="40" verticalAlign="middle" textAlign="center" scaleX="1" scaleY="1" textColor="0x000000" verticalCenter="0" horizontalCenter="0" bold="true"/>
</e:Group>
</e:Skin>
步骤五:测试运行