笔记十 :Egret动画式加载场景(基于通用MVC框架)

时间:2024-05-19 14:39:07

前言:由于H5游戏很多时候需要大量加载网络资源,所以加载的过程处理好是一件很重要的事情,而把加载的过程制作成一个流畅的动画是一个非常好的解决方案。大到3A大作《巫师》系类《COD》系列...都把加载过程弄成一个过场动画,小到微信小游戏海盗来了,把加载动画设置成云雾的散去。

思路:

1.先加载LoadingScene以及对应的LoadingView,LoadingView遮挡住后面的内容。

2.在LoadingView的背后加载场景Scene以及场景View的过程中,同时在LoadingView前面显示进度

3.加载完成后,以动画的形式,消除掉LoadingView遮挡的内容,顺便关闭掉LoadingScene。

示例:(这里演示的是简单的过渡动画,可以自行替换成深度自定义的动画)

笔记十 :Egret动画式加载场景(基于通用MVC框架)

这篇笔记基于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>

 

步骤五:测试运行