イベントリスト
目次
イベントリスト
イベントリストを使用すると、オブジェクトノードにあらかじめ設定した動きをさせることができます。 メインループ内では何もする必要はありません。
移動を伴わない姿勢やポーズの場合は、モーションを使用すると便利です。 それと同様に、移動を伴うような決まった動きをさせたい場合は、イベントを使用すると便利です。 モーション同様に事前に決まった動きを定義しておくだけなので、決まった順路をランダムに移動する敵や同じ動作を繰り返す背景のオブジェクトなどを手軽に配置することができます。 モーションと同様、メインループ内で毎ループ制御する必要がありません。
イベントの設定方法
イベントリストの作成はnewevent
でイベントIDを宣言してから、event_
系命令でイベント(処理)を登録すれば完成です。
newevent イベントID
event_… イベントID, オプション (動作内容を登録)
…
event_… イベントID, オプション (動作内容を登録)
作ったイベントリストをオブジェクトノードに適用するには、setevent
またはgpclone
を使用します。
setevent オブジェクトID, イベントID
とりあえず動くやつを
; イベントテスト
#include "hgimg4.as"
title "HGIMG4 Test"
randomize
gpreset
setcls CLSMODE_SOLID, $808080 ; 画面クリア設定
setpos GPOBJ_CAMERA, 0, 4, 10 ; カメラ位置を設定
; 箱ノードを追加
gptexmat id_texmat, "res/qbox.png"
gpbox id_box, 1, -1, id_texmat
setpos id_box, 0, 4, 0
; 床ノードを追加
gpfloor id_floor, 30,30, $404040
; イベントリストを登録
newevent ev1
event_pos ev1, 60*2, 5, 0.5, 0
; event_pos ev1, 60*2, 5, 0.5, 0, 1
event_wait ev1, 60*2
event_pos ev1, 60*2, -5, 0.5, 0
event_wait ev1, 60*2
event_jump ev1, 0
; イベントを設定
setevent id_box, ev1
repeat
stick key,15
if key&128 : end
; カメラを自機に向ける
getpos id_box,dx,dy,dz
gplookat GPOBJ_CAMERA, dx,dy,dz
redraw 0 ; 描画開始
gpdraw ; シーンの描画
redraw 1 ; 描画終了
await 1000/60 ; 待ち時間
loop
実行すると、箱が左右に動く動作を繰り返します。 メインループでは一切何もしていません。事前準備だけでこういうのが作れると、メインループ内を作る作業が楽になっていいですね。 うまく作ると弾幕系シューティングの弾幕みたいなのも作れそうです。
まずは、event_pos
の動作を少し掘り下げておきます。
補間オプションを指定すると動きのつなぎ方が変わるようです。「スプライン補間(絶対値)」に書き換えてみます。
event_pos ev1, 60*2, 5, 0.5, 0, 1
なめらかな動き。いいですね。 そして、2,3は現在位置からの相対座標指定なので、左右に移動しながら徐々に上に上がっていきます。
イベントスロットを使ってみます。 イベントリストは、1つのオブジェクトに0~3までの4つ存在するイベントスロットに登録して使用しています。 複数のイベントリストを登録すると、それらを同時に動かすことができるようです。
setevent
で登録する際に、何も指定しないと開いているイベントスロットIDに登録されます。
複数のイベントを切り替えて使いたい場合は、注意が必要ですね。
; イベントリストを登録
newevent ev1
event_pos ev1, 60*2, 5, 0.5, 0, 1
event_wait ev1, 60*2
event_pos ev1, 60*2, -5, 0.5, 0, 1
event_wait ev1, 60*2
event_jump ev1, 0
newevent ev2
event_ang ev2, 65, 0, deg2rad(90), 0
event_wait ev2, 65
event_ang ev2, 65, 0, 0, 0
event_wait ev2, 65
event_jump ev2, 0
; イベントを設定
setevent id_box, ev1
setevent id_box, ev2
箱が左右に首振りしながら移動します。移動と首振りは、時間をずらしてあるので徐々にタイミングのズレが大きくなっていきます。
ここでは注意しなければならない点があります。ev2でもposグループを書き換える命令を使うと、ev1で指定したposグループの値が上書きされてしまう点です。
hgimg4側は、イベントリストにしたがって適切なタイミングでオブジェクトノードが持っている変数(posやangなど)を書き換えているだけです。
ev1とev2でevent_pos
を使うと、event_pos
を実行した直後や、event_wait
での待機中に、オブジェクト1つにつき1つしか持っていないposグループの値が再度変更されてしまいます。これでは正常な動作は期待できません。
ev1とev2にevent_pos
を設定して、リサージュ曲線軌道を描くというような使用方法はできないというわけです。
複数のイベントリストを重ねる場合は、posとangなど同時に指定しても問題ない組み合わせを使ったほうが安全なようです。
制御系
event_jump
ジャンプイベントを追加
event_wait
待ち時間イベントを追加
event_pos
以外の命令の説明をする前に、制御系のevent_
系命令について触れておきます。
まず説明しやすくするため、イベント番号の考え方について説明します。
event_
系命令でイベントを追加すると、追加した順にイベント番号という行番号のような0から始まる番号が割り当てられます。
さきほどの例の行頭にイベント番号を書き込んでみました。こんな感じです。
newevent ev1
0: event_pos ev1, 60*2, 5, 0.5, 0, 1
1: event_wait ev1, 60*2
2: event_pos ev1, 60*2, -5, 0.5, 0, 1
3: event_wait ev1, 60*2
4: event_jump ev1, 0
hgimg4は、イベント番号を実行すると直ちに次のイベント番号を実行します。
event_wait
この例では、イベント番号0で「変化までのフレーム数」に120指定していますが、変化が終わるまで120フレーム待機しません。直ちに次のイベント番号1を実行します。
イベント番号1では、何もせず待機する命令です。ここで120フレーム待機してから次のイベント番号を実行します。
もしここで待機時間を半分にしてみると、event_pos
で設定された移動は中断されて、イベント番号2で更新された移動目標を使った移動が開始されます。
event_jump
最後のイベント番号4でevent_jump
が実行されると、次はジャンプ先として指定されたイベント番号0が実行されます。
この例の場合は、同じ処理を無限に繰り返すループになります。この場合は、goto命令と同じ役割をしています。
またevent_jump
命令は、処理の流れを分岐する機能も持っています。分岐は確率を指定したランダムで行われます。
複雑な条件分岐はできませんが、複雑な動きをしているように見せかけることができます。
複雑な条件分岐を行いたい場合は、メインループ内で判定して別のイベントリストに差し替える必要があります。 手間に感じるかもしれませんが、あらかじめ決めておいた動作に切り替えるだけなのでお手軽だと思います。このあたりはモーションも同じですね。
ang、angr、dir、pos、scale、work
分類 | 命令 | 概要 |
---|---|---|
追加 | event_addang | angグループ加算イベントを追加 |
追加 | event_addangr | angグループ加算イベントを追加 |
追加 | event_adddir | dirグループ加算イベントを追加 |
追加 | event_addpos | posグループ加算イベントを追加 |
追加 | event_addscale | scaleグループ加算イベントを追加 |
追加 | event_addwork | workグループ加算イベントを追加 |
設定 | event_setang | angグループ設定イベントを追加 |
設定 | event_setangr | angグループ設定イベントを追加 |
設定 | event_setdir | dirグループ設定イベントを追加 |
設定 | event_setpos | posグループ設定イベントを追加 |
設定 | event_setscale | scaleグループ設定イベントを追加 |
設定 | event_setwork | workグループ設定イベントを追加 |
変化 | event_ang | angグループ変化イベントを追加 |
変化 | event_angr | angグループ変化イベントを追加 |
変化 | event_dir | dirグループ変化イベントを追加 |
変化 | event_pos | posグループ変化イベントを追加 |
変化 | event_scale | scaleグループ変化イベントを追加 |
変化 | event_work | workグループ変化イベントを追加 |
event_
系命令ってたくさんあって、よくわからないんですよね。まずは基本的なものを整理してみます。
基本的には、命令名の後半で取り扱う種類が決まっています。 ここは名前のとおりです。
ang | 姿勢 [rad] |
angr | 姿勢(0~255=0~365度) |
dir | 移動速度 |
pos | 表示座標 |
scale | 表示倍率 |
work | ワーク値 |
命令名の前半で、値をどの様にセットするのかを表しています。
event_add~ | 加算 | 今の値に指定の値を加算 add~系相当の命令。 |
event_set~ | 設定 | 指定範囲内から乱数で値を作成して設定 set~系相当の命令。 |
event_~ | 変化 | 指定された目標値まで徐々に変化させる 移動中の補間計算方法は、オプションで指定できる。 |
event_
~系だけが少し特殊で、時間経過とともに設定値に近づいていきます。
パラメーター設定
event_prmset パラメーター設定イベントを追加
event_prmon パラメータービット設定イベントを追加
event_prmoff パラメータービット消去イベントを追加
ノードオブジェクトが持つパラメーターを設定、消去できます。
パラメーターには、32bit整数値のものとビット管理するものがあるので、設定にはevent_prmset
とevent_prmon
の2つの命令が用意されています。
設定できる内容は、次の通り。
パラメーターID | 内容 | 設定値 |
---|---|---|
PRMSET_FLAG | オブジェクト登録フラグ | ビット(1~4) |
PRMSET_MODE | モード値 | ビット(OBJ_~) |
PRMSET_ID | オブジェクトID | 整数値(0~) |
PRMSET_ALPHA | 透明度(α値) | 整数値(0~255) |
PRMSET_TIMER | タイマー値 | 整数値(0~) |
PRMSET_MYGROUP | 自身のコリジョングループ | ビット(0~0xFFFF 16個) |
PRMSET_COLGROUP | 衝突検出するコリジョングループ | ビット(0~0xFFFF 16個) |
PRMSET_SHAPE | 形状ID | 整数値? |
PRMSET_USEGPMAT | マテリアルID | 整数値? |
PRMSET_COLILOG | コリジョンログID | 整数値? |
PRMSET_FADE | フェードパラメーター | 整数値 |
PRMSET_SPRID | ソースバッファID(スプライトのみ) | 整数値? |
PRMSET_SPRCELID | ソースのセルID(スプライトのみ) | 整数値? |
PRMSET_SPRGMODE | コピーモード(スプライトのみ) | 整数値? |
説明した通り整数とビットが混在していますね。改めて、各命令の機能はこんな感じです。
命令 | 機能 | 通常のノード向け命令 |
---|---|---|
event_prmset | 値を上書き | gpsetprm |
event_prmon | 指定ビットをON | gpsetprmon |
event_prmoff | 指定ビットをOFF | gpsetprmoff |
通常のノードオブジェクトと同じような操作ができる様です。
設定できるパラメーターの内容
設定できるパラメーターの内容を、主なものを書き出してみました。 基本的には、gpsetprm、gpsetprmon で使用するものと変わりません。
PRMSET_FLAG
フラグ値 | 内容 |
---|---|
1 | オブジェクトが有効 |
2 | オブジェクトの表示が有効 |
4 | オブジェクトの自動移動が有効 |
PRMSET_MODE
詳しくは、HGIMG4プログラミングガイド「オブジェクトのモード設定」を参照。
ラベル | 内容 |
---|---|
OBJ_HIDE | 非表示(画面から消す) |
OBJ_CLIP | 3Dクリッピングを有効にする |
OBJ_XFRONT | 正面属性(常に画面に正面を向く) |
OBJ_WIRE | ワイヤーフレームで描画する |
OBJ_MOVE | 自動移動を行なう(XYZ移動量を参照する) |
OBJ_FLIP | ボーダー領域で反転する |
OBJ_BORDER | ボーダー領域を有効にする |
OBJ_2D | 2Dスプライト |
OBJ_TIMER | タイマーを有効にする |
OBJ_LATE | 後から描画される(半透明オブジェクト用) |
「OBJ_XFRONT」ビルボード…こんなところにいたのか。とおもったらYは固定されないのね。そしてこの名前なのに、カメラ方向を向いているのはZ軸。
→ カメラのX回転軸に合わせているという意味。HGIMG3から引き続き使用しています。変更の予定はないようです。
PRMSET_TIMER
指定したフレーム数が経過すると、ノードオブジェクトが削除されます。
使用するときは、OBJ_TIMERでタイマーを有効にする必要があります。
; イベントリストを登録
newevent ev1
event_prmon ev1, PRMSET_MODE, OBJ_TIMER
event_prmset ev1, PRMSET_TIMER, 1000 ; フレーム数
event_pos ev1, 60*2, 5, 0.5, 0, 1
event_wait ev1, 60*2
event_pos ev1, 60*2, -5, 0.5, 0, 1
event_wait ev1, 60*2
event_jump ev1, 2
; カメラを自機に向ける
objexist id_box
if stat = 0 {
getpos id_box,dx,dy,dz
gplookat GPOBJ_CAMERA, dx,dy,dz
}
redraw 0 ; 描画開始
gpdraw ; シーンの描画
pos 10, 10
objexist id_box
if stat = 0 {
gpgetprm v, id_box, PRMSET_TIMER
mes "PRMSET_TIMER値:" + v
} else {
mes "削除されました。"
}
PRMSET_FADE
フレームごとに指定した値を透明度(α値)に加算します。
透明度(α値)がゼロになると、ノードオブジェクトは破棄されます。
半透明になるので、OBJ_LATEの指定もセットで使用する必要があります。
; イベントリストを登録
newevent ev1
event_prmon ev1, PRMSET_MODE, OBJ_LATE
event_prmset ev1, PRMSET_FADE, -1
event_pos ev1, 60*2, 5, 0.5, 0, 1
event_wait ev1, 60*2
event_pos ev1, 60*2, -5, 0.5, 0, 1
event_wait ev1, 60*2
event_jump ev1, 2
これもオブジェクトが消えてしまうので、objexistでチェックが必要です。
パラメーターって色々できてすごいですね。しかし、ここではイベントリスト関連についてまとめたいので、これ以上は掘り下げません。
フェード
event_fade
だったら無くてもいいのでは?って思いますよね。私もそう思います。 しかし使用頻度の高さと、HDLで詳しい説明が読める点を考えるとこれはこれで。
さてこの命令は、フレームごとの透明度(α値)の変化量を設定する命令です。指定した値によって透明度の変化の仕方が変わってきます。
-255 | 非表示にして廃棄 |
マイナス | フェードアウト(徐々に消える) |
0 | 現状維持 |
プラス | フェードイン(徐々に表示される) |
255 | 表示(不透明) |
フェードイン、フェードアウト…自機がダメージ受けたときの点滅表現に使えそうですね。
さて、忘れがちですが、α値が0になるとオブジェクトが破棄されます。event_fade
を使ったオブジェクトはいつの間にか消えることがある点に注意です。
この事実を頭に入れておかないと、イベントの設定値を間違えて「あれ?表示されない??」とか、消えたオブジェクトをgetpos
しようとして「なぜエラー?!」と混乱することがあります。
(サンプル作りながら混乱しました。)
削除
event_delobj
オブジェクト削除イベントを追加
event_suicide
オブジェクト破棄イベントを追加
このイベントが実行されると、ノードオブジェクトは破棄されます。
2つありますが、どちらも同じ機能を持った命令で、違いについての説明はありません。
event_suicideは、今後段階的に廃止となる予定だそうです。
event_suicide
は、hgimg4から登場した命令ですが、HGIMG4プログラミングガイドには記述がありません。event_delobj
の方だけ記述があります。
名前が良くなかったのかな…?Google検索すると検索結果に心配されてしまうし。
まとめ
複雑な条件分岐はできませんが、通常のノードオブジェクト向けの命令とほとんど同じ機能が用意されています。 複雑な条件分岐がしたいなら、メインループ内で少し手を加えるだけでできそうです。
動きはオブジェクトひとつひとつ個別に制御されるので、オブジェクトごとのイベント開始タイミングが異なると動きがバラバラになるので、見た目の動きが自然です。 同じことをメインループ内でやろうとするととても面倒くさい事になります。 全部同じタイミングで同じ動作なら簡単ですが、個別にタイミングを制御するのはおそらくすごく大変です。
行動に思考を伴わないような敵や物などに複雑な動きをつけるには、とても良い機能だと思います。