Toolkit for CreateJS & Haxe : フレームに配置したサウンドへの対応
Flash CS にてムービークリップのタイムライン上にサウンドファイルを配置したとします。その後 Toolkit for CreateJS 1.1 を用いてパブリッシュを行い、出力された素材データを Haxe で操作しようとすると一点問題が発生する事に気づきました。
今回はその問題に対する対処法を記述します。
サンプル作成
以下の様な fla ファイルを作成したとします。
以前の記事で作成してきたサンプル fla ファイルとほぼ同等の内容です。今回は shooting.player.View ムービークリップ内の se レイヤーの 5フレーム目に shooting.se.PowerMax サウンドクラスを配置しました。
swf を作成する際、タイムライン上に配置するだけのサウンドファイルにはクラス設定を行わないことが多いです。しかし先日の記事のように、Toolkit for CreateJS にてサウンドファイル手動差し替えを行う事を考慮するのであれば、タイムライン上に配置するだけのサウンドファイルにもクラス設定を行なっておいたほうが良しとなります。
Toolkit for CreateJS からパブリッシュを行うと、以下のファイルディレクトリが作成されます。
├ view.fla ├ view.html ├ view.js ├ images/ │ ├ _0.png │ ├ _1.png │ ├ _2.png │ └ _3.png │ └ sounds/ └ shootingsePowerMax.png
問題点
出力された view.js 内で、以下の playSound と書かれている行が問題箇所となります。
…略… (lib.shootingplayerView = function(mode,startPosition,loop) { this.initialize(mode,startPosition,loop,{},true); // timeline functions: this.frame_4 = function() { playSound("shootingsePowerMax"); } // actions tween: this.timeline.addTween(cjs.Tween.get(this).wait(4).call(this.frame_4).wait(3)); …略…
shootingplayerView クラスのタイムラインフレームが 4 になったら playSound メソッドを呼び出す、という内容になっています。(CreateJS 上ではタイムラインのフレーム数は 0 から数えるため、サウンド再生フレームの数値は 5 ではなく 4 となっています。)
そして playSound メソッドはどこにあるかというと、view.html 内 以下のように定義されています。
function playSound(name, loop) { createjs.SoundJS.play(name, createjs.SoundJS.INTERRUPT_EARLY, 0, 0, loop); }
先日 blog に記述した「Toolkit for CreateJS と Haxe による Flash 開発工程の流れに沿った html5 サイト開発手順 1~3」では、view.html は外部テキストファイルとして読みこむだけです。そのままですと playSound メソッドが見つからずエラーとなってしまうため、「Haxe 側で playSound メソッドを定義」する方法を用いて対処します。
Haxe でのサウンド再生用クラス
まずは汎用的に使用するための以下の SoundEffectMap.hx を作成します。
package lib.sound; import createjs.soundjs.SoundJS; import createjs.soundjs.SoundInstance; class SoundEffectMap { private var map:Hash<SoundInstance>; public function new(){ map = new Hash(); } public function play( soundId:String, interrupt:String, ?delay:Int = 0, ?offset:Int = 0, ?loop:Int = 0, ?volume:Float = 1){ var soundInstance:SoundInstance = map.get(soundId); if(soundInstance == null){ soundInstance = SoundJS.play(soundId, interrupt, delay, offset, loop); map.set(soundId, soundInstance); } else soundInstance.play(); soundInstance.setVolume(volume); } }
以下の記事の「確認されている問題」の項を参考に、再生後のサウンドインスタンスを再利用するようにしています。
SoundJSでSoundInstanceオブジェクトを指定して再生する : FumioNonaka.com
http://fumiononaka.com/Business/html5/FN1209009.html
次に、Flash 側でサウンドファイルを配置した同パッケージ内に以下の SoundEffect.hx を作成します。
package shooting.se; import createjs.soundjs.SoundJS; import lib.utils.ClassUtil; import lib.sound.SoundEffectMap; import js.Lib; class SoundEffect { private static var SOUND_PACKAGE:String; private static var soundEffectMap:SoundEffectMap; public static function initialize(){ SOUND_PACKAGE = ClassUtil.getPackageNamesWithClass(SoundEffect).join(""); soundEffectMap = new SoundEffectMap(); var className = Type.getClassName(SoundEffect); js.Lib.eval("window.playSound = function(name, loop){ " + className + ".playForFrameSound(name, loop); }"); } private static function playForFrameSound(soundId:String, ?loop:Int = 0){ soundEffectMap.play(soundId, SoundJS.INTERRUPT_EARLY, 0, 0, loop); } private static function play( soundClassName:String, ?volume:Float = 1, ?delay:Int = 0, ?offset:Int = 0, ?loop:Int = 0){ soundEffectMap.play(SOUND_PACKAGE + soundClassName, SoundJS.INTERRUPT_EARLY, delay, offset, loop, volume); } public static function playForPowerMax(){ play("PowerMax"); } }
Flash 側で定義した PowerMax サウンドクラスの他、例えば PowerDown というサウンドクラス設定を行った場合、以下の様な playForPowerDown メソッドを追加すれば良しとなります。
public static function playForPowerDown(){ play("PowerDown"); }
内部で利用している ClassUtil クラスに関しましては、以下の先日の記事をご参考ください。
Toolkit for CreateJS & Haxe : パッケージ名取得からのクラス生成処理共通化
http://www.dango-itimi.com/blog/archives/2013/001149.html
そして注目点は以下の箇所です。
…略… var className = Type.getClassName(SoundEffect); js.Lib.eval("window.playSound = function(name, loop){ " + className + ".playForFrameSound(name, loop); }"); } private static function playForFrameSound(soundId:String, ?loop:Int = 0){ soundEffectMap.play(soundId, SoundJS.INTERRUPT_EARLY, 0, 0, loop); } …略…
これにより view.js 内から playSound メソッドを呼び出すと、SoundEffect.hx 内の playForFrameSound メソッドの内容が実行されるようになります。playForFrameSound メソッド内では SoundEffectMap 経由でのサウンド再生となるため、SoundJS でのサウンド再生メモリ問題の対処にもなっています。