小ワザ
ラベル型 †
なんだかよくわからないラベル型。
サンプルがほとんどないので、とにかくいろいろ使ってみましょう。
簡単に言うと、gosub命令やgoto命令で使用するラベル*1を変数に入れることが出来るというものです。
たとえば、こんな記述をすることが出来ます。
1
2
3
4
5
6
7
|
| lb = *test goto lb stop
*test
mes "Hello, world!"
stop
|
ラベル型が本領発揮するパターンの一つに、配列での利用があります。
+
| | ラベル配列をつかってみる
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
|
#enum CmdId_DoNothing = 0
#enum CmdId_Attack
#enum CmdId_Escape
#enum CmdId_Max
*main
randomize
ldim cmdlist, CmdId_Max
cmdlist = *Cmd_DoNothing, *Cmd_Attack, *Cmd_Escape
idcmd = 0 name_hero = "ユーシャ"
title "チャバン・サーガ−闇夜の攻防−"
boxf : color 255, 255, 255
font msgothic, 12
objsize 120, 25
pos 18, 10 : mes "スライムがいるけど、"+ name_hero +"、どうする?"
pos 20, 30 : combox idcmd, 100, "様子をみる\n攻撃する\n逃げる"
pos 20, 60 : button gosub "実行!", *RunCommand
pos 20, 90
stop
*RunCommand
color , 255, 255
gosub cmdlist( idcmd )
color 255, 96, 96
gosub *ActEnemy return
*Cmd_DoNothing
mes name_hero +"は様子をみている。"
return
*Cmd_Attack
mes name_hero +"の袈裟斬り! スライムに"+ (rnd(200) + 1) +"ダメージを与えた。"
return
*Cmd_Escape
mes name_hero +"は逃げようと思ったが、周りの視線が気になるのでやめた!"
return
*ActEnemy
switch ( rnd(CmdId_Max) )
case CmdId_DoNothig : mes "スライムは"+ name_hero +"の様子を見ている。" : swbreak
case CmdId_Attack : mes "スライムの捨て身タックル! "+ name_hero +"はかゆみを覚えた!" : swbreak
case CmdId_Escape : mes "スライムは逃げた! ……しかし、"+ name_hero +"は追いついた。" : swbreak
swend
return
|
|
長いですが……。
このサンプルに「防御コマンド」を追加するのはとっても簡単で、CmdId_Block を追加し、*Cmd_Block を実装し、cmdlist への代入を一部書き換えるだけですみます。
一方、ラベル配列を使わない場合は、たとえば、コマンドを実行する部分が次のように変わります。
+
| | switchを使う場合
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
| *RunCommand
color , 255, 255
switch ( idcmd )
case CmdId_DoNothig : gosub *Cmd_DoNothing : swbreak
case CmdId_Attack : gosub *Cmd_Attack : swbreak
case CmdId_Escape : gosub *Cmd_Escape : swbreak
swend
color 255, 96, 96
gosub *ActEnemy return
|
|
ちょっと冗長ですね。
これにさらに防御コマンドを付けるには、コマンドが呼び出される場所をいちいち探したりする必要があり、すこし面倒です。
また、配列としてもっていれば、後述方法でユーザ定義命令に渡すことができます。
モジュールで使用するには、いろいろと注意が必要です。
- #deffuncや#defcfuncで定義する命令・関数の引数には、直接ラベル型を指定することが出来ません。
そのため、いったんラベル型変数にラベルを代入し、その変数を var の引数として渡すようにします。
しかし、マクロを使えばあたかもラベルを直接、命令の引数に指定したかのような記述が出来るようになります ( 下記の例を参照 )。
- ちなみに、引数タイプに label を指定できますが、これは動作しないので注意してください。
- あり得ない状況におけるバグではありますが、HSP3.1以前のバージョンでは、関数の引数にラベル・リテラルを書けません。
- return命令でラベル型を返すことは出来ません。
ラベル型を返したいときは、変数を介して返す必要があります。
使用例のサンプルを書いてみました。
+
| | モジュールサンプル
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
| #module
#deffunc _get_label var lb, var lb2
lb2 = lb
return #define global get_label(%1, %2) lb_temp@ = %1 : _get_label lb_temp@, %2
#global
a = *label1
_get_label a, lb gosub lb
get_label *label2, lb gosub lb
stop
*label1
mes "*label1 が呼ばれた。"
return
*label2
mes "*label2 が呼ばれた。"
return
|
|
もちろん受け取ったラベルを命令内から呼び出す事も出来ます。
+
| | モジュールサンプル2
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
| #module
#deffunc _get_label var lb
gosub lb
return
#define global get_label(%1) lb_temp@ = %1 : _get_label lb_temp@
#global
get_label *label stop
*label
mes "*label が呼ばれた。"
return
|
|
モジュール内に設置したラベルを モジュール外から呼び出すには少しコツが要ります。
モジュールの内部で定義した #deffunc や #defcfunc を呼び出す文がどこにもない場合、そのモジュールは不要なものと判断されて、最適化*2によって削除されてしまいます。
そのため、適当にダミーの命令を作って、呼び出されないような場所にでも書いておく必要があります。
また、モジュール内のラベルには、ラベル名に「@モジュール名」をつけないといけません。
+
| | モジュールサンプル3
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
|
#module mod1
#deffunc _module_saver1
return : _module_saver1
*label
mes "モジュール内部のラベルに来ました!"
return
#global
*main
gosub *label@mod1
gosub *label_at_mod2
stop
#module
*label_at_mod2@
mes "ラベルを含んだモジュールの位置は、呼び出し位置の下でもかまいません。"
return
#deffunc _module_saver2
return : _module_saver2
#global
|
|
出力メッセージにあるように、ラベルを含んだモジュールの位置は、実際にラベルが使われる場所よりも下でもかまいません。しかし、その場合は「*ラベル名@モジュール名」として参照できないので、定義をモジュールの外*3にする必要があります。
- ようやくラベル型を使う機会が出来たので書いてみました。詳しい人追記お願いします。 -- GENKI?
- まだここ利用してる人いたんだ。最適化はcmpoptで抑制可能です。 --