在上一篇中,简单的使用界面元素快速实现了一个游戏中的二级页面,这种直接在游戏页面上做UI的做法并不太好,原因是,UI会让游戏的压力变大,即使它是隐蔽的,如果同样的功能在其它的地方也是一样的,那么就要写多个同样的逻辑吗?例如设置界面,游戏中的设置界面基本上功能都是一样,如果每个UI中都做一遍,是多么愚蠢的办法?在UI的代码设计中,一般来说,单独的功能不会在其它的地方用到,如GameOver,就直接写在UI里,而如果是通用功能,则最好的做法是做一个通用的单例类或者工厂类在需要的时候将它们初始化,在多个UI中复用逻辑规则。我们就直接用声音设置来实现上面的核心思想,通用类的UI制作,在开始之前,先把SoundMenager类准备好,顾名思义声音管理者,来管理这些声音。
声音管理和播放
请确保你的assets里有sound目录,里面的mp3都在,如buttonclick.mp3
直接实现下面的类:
class SoundMenager { private static shared: SoundMenager; public static Shared(): SoundMenager { if(SoundMenager.shared == null) SoundMenager.shared = new SoundMenager(); return SoundMenager.shared; } _word: egret.Sound;_right: egret.Sound;_wrong: egret.Sound;_bgm: egret.Sound;_bgm_channel: egret.SoundChannel; constructor() { this._click = new egret.Sound(); ); this._bgm = new egret.Sound(); ); this._right = new egret.Sound(); ); this._wrong = new egret.Sound(); ); this._word = new egret.Sound(); ); } public PlayBGM() { if(this.IsMusic) { this._bgm_channel = this._bgm.play(0,0); } } public StopBGM() { if(this._bgm_channel != null) { this._bgm_channel.stop(); } } public PlayClick() { if(this.IsSound) { this._click.play(0,1); } } public PlayRight() { if(this.IsSound) { this._right.play(0,1); } } public PlayWrong() { if(this.IsSound) { this._wrong.play(0,1); } } public PlayWord() { if(this.IsSound) { this._word.play(0,1); } } IsMusic(value) { if(!value) { egret.localStorage.setItem(,); this.StopBGM(); } else { egret.localStorage.setItem(,); this.PlayBGM(); } } public get IsMusic(): boolean { ); if(b == null || b == "") { return true; } else { ; } } IsSound(value) { if(value) { egret.localStorage.setItem(,); } else { egret.localStorage.setItem(,); } } public get IsSound(): boolean { ); if(b == null || b == "") { return true; } else { ; } } }
我想这个代码就不做太多的解释了,它是用了异步load声音文件,通过几个Play方法来播放,实现了两个属性:IsSound和IsMusic,来控制是否静音和播放音乐,这个类里_bgm_channel保存了bgm的声音通道,当静音的时候就会stop声音,确保UI交互是正确的。
将它们加到Begin.ts里
运行一下,你会发现出现了这个错误:
大概的意思是和它所写的不太一样,如果你有耐心跟踪断点会有惊喜,在这里就不卖关子,出这个错误的原因是,egret.Sound.load方法中初始化的一个属性是null,所以,避免这个问题的方式也很简单,在LoadingUI的构造函数中调用SoundMenager.Shared()完成预先加载。
public constructor() { super(); //预先加载声音 SoundMenager.Shared(); this.createView(); }
这个时间差异其实只有几个毫秒,但是能正确的让声音输出,估计是底层的问题,就不深究其原因了,反正能解决就行,对于异步加载还是预先加载,这属于个人习惯问题,但声音在现在的手机游戏中并不是主要的组成部分,每次打开在加载游戏声音上耗费大量时间得不偿失,不如先玩起来再播放体验来的好。
在你想要加的地方都加上声音,这里就不一一列举,只需要提一下关于错误声音,需要在SceneGame类里做一个判断: