ゲーム内部のイベント処理にはマクロやスクリプトを使用するのが一般的ではないでしょうか。
例えば、一度きりのよう会話を実現するなら以下の様な感じです。
if flag[0] message "○○" flag[0] = false; endif
ただし、よくよく考えるとJavaScript自信がスクリプトなので、さらにスクリプトを用意する必要はありません。
実際、JavaScriptにはeval()
等、後からスクリプトを評価する仕組みもあります。
イベント
イベントを分析すると、イベントの種類(会話、宝箱、マップ移動)、イベントを発生させるための条件チェック、後処理などの属性が思いつきます。
[Event|type||condition,post,trigger]
イベントの種類の追加や関数の追加はそのままJavaScriptで記述することにします。実際の記述は後述します。
データ形式
まず、イベントはJSONで保存しておくことにします。
JSON
{ 'type' : "message", 'message' : "○○", 'condition' : "flag[0]", 'post' : "flag[0]=true" }
このデータからイベントクラスを作成します。
Event = function(options) { for (var nm in options) { if (options.hasOwnProperty(nm)) { this[nm] = options[nm]; } }
イベントの種類に応じた処理はストラテジに任せることにします。ストラテジの実装方法については既に何度か記述しているので割愛します
フラグ
イベントを発生させるかを判定するためにcondition
をeval
で評価します。
先のJSONの内容を見るとflag[0]
となっていますが、flagをグローバル変数として用意するべきでしょうか。
グローバル変数(window名前空間)はあまり汚したくないものです。
そうするとconditionを関数として評価する方法が思いつきます。
{ 'type' : "message", 'message' : "○○", 'condition' : "return flag[0]", 'post' : "flag[0]=true" }
Event.prototype.trigger = function(world) { ///<summary> /// イベントを実行する ///</summary> ///<param name="world" type="DQ.World"> /// 共通名前空間を指定 ///</param> var fn = new Function('world', 'flag', this.condition); if (fn.apply(this, [world, world.flag]) { /// イベント処理を実行 ... /// 後処理 var post = new Function('world', 'flag', this.post); fn.apply(this, [world, world.flag]); } }
ただ、実際に自家製のライブラリに採用したのは以下の方法です。
{ 'type' : "message", 'message' : "○○", 'condition' : "flag[0]", 'post' : "flag[0]=true" }
Event.prototype.trigger = function(world) { ///<summary> /// イベントを実行する ///</summary> ///<param name="world" type="DQ.World"> /// 共通名前空間を指定 ///</param> var flag = world.flag, party = world.party, player = world.party[0]; if ( eval(this.condition) ) { /// イベント処理を実行 ... /// 後処理 eval(this.post); } }
イベントの拡張はストラテジの追加として実現します。
そのため、イベントクラス生成時のストラテジの割り当て処理を汎用化します。
イベントの拡張
Event.table = [ {type : 'message', strategy : DQ.Event.MessageStrategy }, {type : 'load', strategy: DQ.Event.MapLoadStrategy }];
Event.prototype._buildStrategy = function(type) { if (Event.table[type]) { return new Event.table[type](this); } else { return new Event.Strategy(this); } }
後からストラテジを追加する場合、Event.table.push({type: 'hoge', strategy: DQ.Event.Hoge})
のように記述します。
関数の追加
conditionやpost等で使用する関数を追加する場合、JavaScriptでそのまま記述します。ただし、専用の名前空間に定義するぐらいのルールは必要でしょうか。
World.property.MacroOrNewAPI = function(hoge) { /// macroやAPI相当を記述 }
呼び出しの記述方法は以下の通り。
{ post : 'flag[0] = world.MacroOrNewAPI("foo");' }