シナリオ作成応用編


Q601. 敵を倒したら強化パーツを手に入れさせるにはどうすれば良いのですか?

 SRWなどでは、ボスを倒した時に強化パーツが手に入ります。
 これをSRCで再現するためには破壊ラベルを使いましょう。

破壊 (破壊されたユニットのパイロット名):
(強化パーツを手に入れるイベント)
Exit

 強化パーツを手に入れるイベントに関して以下に例を挙げます。

Item (強化パーツ名)
Talk システム
(強化パーツ名)を手に入れた
End

 まとめ
 ・敵を倒したかどうか判別するには…破壊ラベル
 ・強化パーツを手に入れるには…Itemコマンド

Q602. ステージ終了時の残りSPによる経験値ボーナスをやめることはできますか?

 SRCではステージを終了すると、
 ステージ終了時点のSPx2が経験値ボーナスとして
 自動で加算されるようになっています。

 ただ、毎回経験値が加算されてしまうと、
 レベル調整するのが難しくなってしまうので、
 これをやめたいという場合もあるかと思います。

<経験値加算が行われる条件>
・Continueコマンドを使った時点で
・"出撃"or"格納"状態になっている味方ユニット

 つまり、Continueコマンドを使う直前に
 Escapeコマンドで味方全体を"待機"状態にしてしまえば
 経験値が加算されませんし、表示自体も行われなくなります。

Escape 味方
Continue シナリオ02.eve

 直後がContinueコマンドになっていますので、
 味方の全滅イベントが発生する心配はありません。
 Destroyコマンドを使うと修理費がかかってしまうので
 気をつけましょう。

関連項目:
Q612. 戦闘時の獲得経験値をすべてゼロにする方法は?
      敵撃墜時の獲得資金をすべてゼロにする方法は?

Q603. 指定座標のビットマップ番号はどうやって調べれば良いですか?

 ChangeTerrainコマンドではビットマップ番号を指定する必要がありますが、
 Info関数ではビットマップ名しか調べられません。
  (ビットマップ名 = "remains1.bmp"、"base-1.bmp" など)

 ビットマップ名は必ず"文字列"+"数値"+"."+"拡張子"の順に並んでいますので、
 SRCのイベントコマンドと関数を利用すれば、番号だけの抽出が可能です。

# ビットマップ名取得
# (Info関数を使用してください)
mBMP = Info(マップ, X座標, Y座標, ビットマップ名)

# 拡張子切捨て
# ("文字列" + "ビットマップ番号" にする)
mBMP = Mid(mBMP, 1, (Instr(mBMP,".") - 1)) 

# ビットマップ番号抽出
# (数値 or "-" 以降の部分を抽出する)
For i = 1 To Len(mBMP)
 If Mid(mBMP,i,1) = "-" OR IsNumeric(Mid(mBMP,i,1)) Then
  mBMP_No = Mid(mBMP,i)
  Break
 Endif
Next

 結果
 ・"mBMP_No"がビットマップ番号になります。("1"とか"-1")

Q604. 全ての味方、敵、または特定グループIDのユニットに対し何かをするには?

 「ForEach」コマンドを使います。

# 全ての敵の気力を 10 下げる。
ForEach 敵
  IncreaseMorale -10
Next
# 全ての味方ユニットに搭乗する全パイロットの SP を回復させる。
ForEach 味方
  For i = 1 to CountPilot()
    RecoverSP PilotID(対象ユニットID,i) 100
  Next
Next
# 同じ名前のパイロットが複数いないならば、
# PilotID()関数のかわりに Pilot()関数でもかまいません。

 ただし、ForEachループの中に ForEachを入れることはできないので、ご注意ください。

 次は、特定グループに対しまとめて何かをする例です。

# グループID「防衛隊」の全出撃ユニットの思考ルーチン動作を変える
ForEach 防衛隊
  ChangeMode 待機
Next

 処理内容がやや複雑な例です。

# すべての行動済み味方ユニットを行動可能状態に戻すサブルーチン
全味方行動可能:
ForEach 味方
  If Action() = 0 Then //この「Action() = 0」は、"残り行動数が
                       // 0 か"をチェックする条件式です
    Action() = 1       //この「Action() = 1」は、"残り行動数に 1 を代入する"
                       //という意味で、「Action()」は関数の左辺値用法です
  EndIf
Next
Redraw                 // ユニットアイコンの網掛けをはずす
Return
# このサブルーチンは、2回行動には対応していません
 

 コマンドによっては、陣営名やグループIDをパラメータにすることによってまとめて処理できます。

# 出撃中の全ての味方を脱出させる。
Escape 味方

 ただし、この方法はコマンドごとの仕様に依存します。 特に慣れないうちはヘルプでしっかり確認してから使うことをおすすめします。

Q605. ユニットが装備する全アイテムを調べ、処理するには?

 「CountItem」関数で装備アイテム数を調べ、「For〜Next」ループや「Do〜Loop」ループを使います。

 以下の例では、メインパイロット名が「パイロットA」のユニットのアイテムの名称を連想配列「Aアイテム」に入力します。

Set Aアイテム
For i = 1 To CountItem(パイロットA)
  Aアイテム[i] = Item(パイロットA, i)
Next

 ループの実行中にアイテムの番号が変化するかもしれないときは注意が必要です。 以下は、パイロットAの持つアイテムのうち装備個所が「武器」であるアイテムを削除します。

For i = CountItem(パイロットA) To 1 Step -1
  If Info(アイテム, Item(パイロットA, i), 装備個所) = "武器" Then
    RemoveItem パイロットA i
  EndIf
Next

 For〜Next、ForEach〜Next、Do〜Loop は繰り返し構造と呼ばれ、パラメータを変えながら繰り返し順番に実行していきます。 しばしば誤解されますが、決して「当てはまる要素に対して一度に実行する」というものではありません。
 したがって、上と同じ目的で以下のようにするのは誤りです。

For i = 1 To CountItem(パイロットA)   // まちがい
  If Info(アイテム, Item(パイロットA, 1), 装備個所) = "武器" Then
    RemoveItem パイロットA 1
  EndIf
Next

 これだと、ループを繰り返すなかで RemoveItem されたときアイテムの番号がずれてしまい、チェックされないアイテムが出てきます。
 あえて正順でやりたい場合は、たとえば次のようにします。

Set i
Do While i <= CountItem(パイロットA)
  If Info(アイテム, Item(パイロットA, i), 装備個所) = "武器" Then
    RemoveItem パイロットA i
  Else
    Incr i                // 順番がずれないときだけ、i を増やす
  EndIf
Loop

Q606. ユニットがマップの特定領域に入ったときに何かを起こすには?

 ユニットが特定領域に存在するとき処理したい場合は、Q.607を参照してください。

 「特定領域」がたった一つの座標の場合は、単純に「進入イベント」を使います。

# 味方ユニットが X = 5、Y = 7 に入ったときにイベントを起こす
進入 味方 5 7:
  (イベント内容)
Exit
 

 座標が複数あるときは、「進入イベントラベル」を並べます。

# これらのイベントは合わせて1回しか起こらない。
進入 味方 5 7:
進入 味方 4 7:
進入 味方 5 8:
  (イベント内容)
 ClearEvent "進入 味方 5 7"
 ClearEvent "進入 味方 4 7"
 ClearEvent "進入 味方 5 8"
Exit

 ClearEventコマンドのパラメータを省略すると、イベント内容を引き起こしたイベントラベルだけを消去します。 並べられたイベントラベルをすべて消去したい場合は、上のように記述してください。

 座標がもっと多い場合などには、「進入イベント」内部で座標を判別させます。
 以下は「特定領域」の X座標が 5 以下、Y座標が 4 以上 8 未満の場合にイベントを起こします。

進入 味方 全 全:
  If X() <= 5 And Y() >= 4 And Y() < 8 Then
    (イベント内容)
  EndIf
Exit

 「特定領域」が特定の地形の場合には、以下のようになります。

進入 味方 地形名称:
  (イベント内容)
Exit

 これを応用して、terrain.txt にイベント用の地形を記述してマップ上に配置するという手段もあります。

 

Q607. ユニットがマップの特定領域に存在するときに何かを起こすには?

 (この項は、Q606.ユニットがマップの特定領域に入ったときに何かを起こしたいときには?と共通事項が多いので、そちらも参照してください)。

 これには、X 関数と Y 関数を使ってユニットの表示位置を出し、それを判別します。
 以下は、味方ターン冒頭に X座標が 5 以下、Y座標が 4 以上 8 未満のユニットの HP を回復させます。

ターン 全 味方:
  ForEach 味方 出撃
    If X() <= 5 And Y() >= 4 And Y() < 8 Then
      RecoverHP 対象パイロット HP回復率
    EndIf
  Next
Exit

Q608. 発動に追加条件が付いたイベントを設定するには?

 ここでは、
「敵を破壊したとき、敵数が5体以下のときだけイベントを実行したい」
「敵ユニットが特定パイロットに破壊されたときだけ、何かをさせたい」
など、イベントラベルで表される条件以外の追加条件をイベントに付加する方法を説明します。

 一般には 「If」コマンド を使います

# 敵ユニットが5体以下になったときに何かを起こす
破壊 敵:
  If 敵数 <= 5 Then
    (動作内容)
  EndIf
Exit
# パイロットAが出撃中かどうかを追加条件にする場合は、
(イベントラベル):
  If パイロットA Then
    (動作内容)
  EndIf
Exit
# となります。「パイロットA」はパイロットの名称または愛称です。
# (ザコ)または(汎用)でパイロットを特定できない場合、
# 予想外の動作になることがあります。
# 第3ターン以降毎ターンの味方フェイズに何かを起こします。
ターン 全 味方:
  If ターン数 >= 3 Then
    (動作内容)
  EndIf
Exit
# ユニットAが武器「豆腐の角」で倒されたときのイベントです。
破壊 ユニットA:
  If 相手ユニット使用武器 = 豆腐の角 Then
    (動作内容)
  EndIf
Exit
# 味方ユニットが属性「音」の武器を使った後、何かを起こします。
使用後 味方 対象ユニット使用武器:
  If Info(ユニット, 対象ユニット, 武器, 対象ユニット使用武器, 属性所有, 音) = 1 Then
    (動作内容)
  EndIf
Exit
# イベントラベルの最後のパラメータが「全」だとアビリティやスペシャルパワーなど
# にも反応してしまうので、システム変数「対象ユニット使用武器」を使います。
 

 If コマンドを使うとき注意すべきは、「If の効果は EndIf を使うまでは有効だ」ということです。 EndIf の書き忘れは非常によくあるミスなので、ご注意ください。 このミスを減らすためにも「If」「ElseIf」「Else」「EndIf」のあいだの行は字下げすることを強くおすすめします。

 初心者向け注意:イベント冒頭の「If」はしばしば誤解されます。 これは、イベントそのものに発生条件を付けるわけではありません。 「If」実行時にはすでにイベントは始まっているが、イベントが始まったとたんに「If」の条件が付けられた、ということです。
 とりわけ、ClearEvent の置き場所はしばしばまちがえられます。

# 以下は、パイロットAが敵を破壊した場合に1回だけ起こるイベントです。
 破壊 敵:
  If 相手パイロット = パイロットA Then
    (動作内容)
    ClearEvent
  EndIf
Exit

# そのつもりで以下のようにするのはまちがいです。これだと、
# ステージ最初に敵が破壊されたとき、破壊したのが誰であろう
# と ClearEvent されてしまいます
破壊 敵:
  If 相手パイロット = パイロットA Then
    (動作内容)
  EndIf
  ClearEvent
Exit
 

 追加条件を変化させたり判定させたりするタイミングが別のイベントの場合は、フラグや判別用変数を用います。Q609.Q610.Q613.の(3)(4)などを参照してください。

関連項目:
Q608.1. イベント内で条件に応じ違ったことをさせる方法
Q609.あるできごとが起こってから数ターン後にイベントを起動させるには?
Q610.敵と中立の両方が全滅したときにイベントを起こすには?
Q613.複雑な条件分岐を設定する方法は?

Q608.1. イベント内で条件に応じ違ったことをさせる方法

「敵全滅のとき、ボス登場済みかどうかで動作を変えたい」
「ターンによって勝利条件表示を変えたい」
など、条件によってイベント内容を変えるやり方です。

 最もよく使うのは 「If」コマンド を使う方法です。

# 敵全滅時、まだボスが登場していなかったらボスを登場させ、
# すでに登場していたら別 のできごとを起こしたいときには、
# 次のようになります。
全滅 敵:
  If ボス登場 = 0 Then
    (ボス登場動作内容)
    Set ボス登場
  Else
    (それ以外の時の動作内容)
  EndIf
Exit
# ターンによって勝利条件表示を変える例です。
勝利条件:
  If ターン数 < 5 Then
    Talk
      (4ターンまでの勝利条件表示)
    End
  Else
    Talk
      (5ターン以降の勝利条件表示)
    End
  EndIf
Exit
# 敵を倒したとき、撃墜数に応じたイベントを実行します
# スタートイベントなどで前もって変数「撃墜数」を作っておきます
スタート:
  Set 撃墜数 0
Exit

破壊 敵:
  Incr 撃墜数
  If 撃墜数 >= 20 Then
    (撃墜数20以上のときの動作)
  ElseIf 撃墜数 >= 10 Then
    (撃墜数10以上20未満のときの動作)
  Else
    (それ以外のときの動作)
  EndIf
Exit
# サポートアタックがパイロットAにより行われたとき、
# それ以外のパイロットによるとき、サポートアタックが行われない
# ときそれぞれに、違った動作をさせます
使用後 全 対象ユニット使用武器:
  If Pilot(サポートアタックユニットID) = "" Then
    (サポートアタック不成立時の動作)
  ElseIf Pilot(サポートアタックユニットID) = パイロットA Then
    (パイロットAが行ったときの動作)
  Else
    (パイロットA以外がサポートアタックしたときの動作)
  EndIf
Exit
 

 パラメータの値によっていろいろなできごとを起こしたいときには、「Switch」が便利です。

# 次の例は、敵全滅のたびに違ったできごとを起こします。
スタート:
  Set 全滅回数 0
Exit

全滅 敵:
  Incr 全滅回数
  Switch 全滅回数
  Case 1
   (全滅1回目で発生する動作)
  Case 2
   (全滅2回目で発生する動作)
  …(中略)
  EndSw
Exit
# 以下は、ユニットAが破壊されたとき、撃墜したパイロット
# ごとに違ったできごとを起こします。
破壊 ユニットA:
  Switch 相手パイロット
  Case パイロットA
    (パイロットAが撃墜したときの動作)
  Case パイロットB
    (パイロットBが撃墜したときの動作)
  …(中略)
  Case Else
    (それら以外のパイロットが撃墜したときの動作)
  EndSw
Exit

関連項目:
Q608.発動に追加条件が付いたイベントを設定するには?
Q613.複雑な条件分岐を設定する方法は?

Q609. あるできごとが起こってから数ターン後にイベントを起動させるには?

 これには、ターン判別用の変数を用意しておいて判定します。

 以下は、ユニットAが破壊された5ターン後にイベントを起こす二つの方法です。

<方法1>

# まず、ステージの最初に、
# ユニットA破壊まで条件が満たされないよう
# 変数「イベント起動時間」をセットします。
# 変数未定義でも条件が満たされない場合、この部分は省略可能です
# (実はこの例もそうです)。
スタート:
  Set イベント起動時間 -1
Exit

# ユニットA破壊時、イベント起動予定ターンをセットします。
破壊 ユニットA:
  イベント起動時間 = ターン数 + 5
Exit

# そして、ターンイベントで判別します。
ターン イベント起動時間 味方:
  (イベント内容)
Exit

<方法2>

# ステージの最初に ClearEvent を使い
# ターンイベントが起こらないようにします。
スタート:
  ClearEvent "ターン イベント起動時間 味方"
Exit

# ユニットA破壊時、変数をセットし、
# RestoreEvent でターンイベントを復活させます。
破壊 ユニットA:
  イベント起動時間 = ターン数 + 5
  RestoreEvent "ターン イベント起動時間 味方"
Exit

ターン イベント起動時間 味方:
  (イベント内容)
Exit

関連項目:
Q608.発動に追加条件が付いたイベントを設定するには?

Q610. 敵と中立の両方が全滅したときにイベントを起こすには?

 「敵と中立の両方が全滅したときにイベントを起こす」ということは、「敵全滅時、もし中立が全滅していればイベントを起こし、中立全滅時、もし敵が全滅していれば同じイベントを起こす」と同じことです。 したがって、「全滅 敵」と「全滅 中立」の二つのイベントを作り、もう一方がすでに全滅していることを追加条件にすればよいわけです。

全滅 敵:
  If 中立全滅 = 1 Then
    Call 双方全滅イベント
  EndIf
  Set 敵全滅
Exit

全滅 中立:
  If 敵全滅 = 1 Then
    Call 双方全滅イベント
  EndIf
  Set 中立全滅
Exit
# 「Set 〜」は「If〜EndIf」内の「Else」節に入れても可です。

双方全滅イベント:
  (イベント内容)
Return

 フラグ「敵全滅」「中立全滅」を Set して判別するかわりに、システム変数「敵数」「中立数」がゼロかどうかで判別する方法もあります。

 同じことをもっと短く書くこともできます。

全滅 敵:
全滅 中立:
  If 敵数 + 中立数 = 0 Then
    (イベント内容)
  EndIf
Exit

関連項目:
Q608.発動に追加条件が付いたイベントを設定するには?

Q611. 攻撃イベントや攻撃後イベントで味方の仕掛けた戦闘と敵が仕掛けた戦闘を判別するには?

 よく使われる方法は二つあります。

 <方法1>
 以下のように、イベントを二つ作成する方法です。

攻撃 ユニットA ユニットB:
  (AからBへの攻撃イベント内容)
Exit

攻撃 ユニットB ユニットA:
 (BからAへの攻撃イベント内容)
Exit

 <方法2>
 システム変数「対象ユニットID」などを Party関数に入れ、陣営を判別します。攻撃イベントでは、「対象パイロット」「対象ユニットID」に攻撃を仕掛けた側のデータが、「相手パイロット」「相手ユニットID」に攻撃を仕掛けられた側のデータが入ります。

攻撃 味方 敵:
  If Party(対象ユニットID) = 味方 Then
    (味方から敵への攻撃イベント内容)
  Else
    (敵から味方への攻撃イベント内容)
  EndIf
Exit

Q612. 戦闘時の獲得経験値をすべてゼロにする方法は?
      敵撃墜時の獲得資金をすべてゼロにする方法は?

 両方とも、おもに二つの方法があります。

(1) すべての敵ユニットの「修理費」または「経験値」をゼロにします。 味方ユニットが暴走したり憑依されたり ChangeParty する可能性があるときは、味方ユニットも同様にします。
(2) すべての味方メインパイロットにパイロット用特殊能力「資金獲得Lv-10」を付けます。 またはすべての味方パイロットにパイロット用特殊能力「素質Lv-10」を付けます。(味方パイロットが獲得資金・経験値を増加させるスペシャルパワー・特殊能力を持っていればはずしておきます)

関連項目:
Q602. ステージ終了時の残りSPによる経験値ボーナスをやめることはできますか?

Q613. 複雑な条件分岐を設定する方法は?

(1)And や Or 、Not を使う
 複数の条件をともに満たしたときに動作させたいのなら And演算子を、どちらかを満たしたときに操作させたいのなら Or演算子を、条件が満たされないときに動作させたいときは Not演算子を使います。

# メインパイロットがパイロットPのユニットがアイテムAとアイテムBの両方を
# 装備しているなら、何かを起こす
If IsEquiped(パイロットP,アイテムA) = 1 And IsEquiped(パイロットP,アイテムB) = 1 Then
  (処理内容)
EndIf
# アイテムAかアイテムBのどちらかを装備しているなら何かを起こす
If IsEquiped(パイロットP,アイテムA) = 1 Or IsEquiped(パイロットP,アイテムB) = 1 Then
  (処理内容)
EndIf
# 相手ユニットがユニットAでもユニットBでもないとき何かを起こす
If Not (相手ユニット = ユニットA Or 相手ユニット = ユニットB) Then
  (処理内容)
EndIf
# パイロットAが出場していないとき何かを起こす
If Not パイロットA Then
  (処理内容)
EndIf

 以下はもっと複雑な例です。

# パイロットAが座標 (2, 3) か座標 (5, 7)にいるなら何かを動作させます
If X(パイロットA) = 2 And Y(パイロットA) = 3 Or X(パイロットA) = 5 And Y(パイロットA) = 7 Then
  (動作内容)
EndIf

 こうした場合注意したいのは、演算子の優先順位です。 演算子は優先順位の高い順に処理され、この順番を変えるためには半角括弧「(」「)」でくくらなくてはなりません。
 優先順位は、その他の演算子、Not、And、Or の順ですので、上の例のように Or の項の中に And を入れる場合には括弧は不必要です。 下の例のように And の項の中に Or を入れる場合は項を括弧でくくらなくてはいけません。

# パイロット「パA」の X座標が 3 か 4 で、Y座標が 1 か 20以上なら何かを起こします。
If (X(パA) = 2 Or X(パA) = 3) And (Y(パA) = 1 Or Y(パA) >= 20) Then
 (動作内容)
EndIf

# この条件式の括弧を省略すると、Or より And が優先されるので、
# X(パA) = 2 Or (X(パA) = 3 And Y(パA) = 1) Or Y(パA) >= 20
# という意味になってしまいます。

 演算子と優先順位の詳細は、ヘルプの「シナリオの作成」->「式」のページの「演算子」をご覧ください。

(2)If の入れ子
 「条件1が成立したとき動作1を行い、さらに条件2も成立するなら動作2も行う」など、追加動作がある場合に便利な方法です。

# メインパイロットがパイロットPであるユニットがアイテムAの装備しているなら
# 処理Aを起こし、さらにアイテムBも装備しているなら処理Bも起こす
If IsEquiped(パイロットP,アイテムA) = 1 Then
  (処理内容A)
  If IsEquiped(パイロットP,アイテムB) = 1 Then
    (処理内容B)
  EndIf
EndIf

 (1)の方法とくらべ、個々の条件式は単純になるけれど行数は長く複雑になりがちです。場合により、(1)と使い分けます。


(3)フラグを使う
 特定のできごとがすでに起こったかどうかを条件にする場合は、フラグを使います。 ヘルプの「シナリオの作成」->「変数」の最初のほうをご覧ください。
 以前のステージのできごとを条件にするには、フラグをグローバル変数にします。 Set コマンドは変数の値を 1 にセットしますが、Global コマンドは空文字列(数値として扱う場合は 0)がセットされます。

(4)判別用変数を使う
 これはフラグの応用で、条件判別のための変数を準備し、この変数をさまざまなできごとや状態に応じて変化させ、判別時に使う方法です。

# 味方ユニットの座標(2,3)への進入・ユニットAの破壊・
# 味方ユニットBの母艦格納の3条件のうち二つを満たした後、
# 最初の味方フェイズに何かを起こします
スタート:
  Set 判別変数 0
Exit

進入 味方 2 3:
破壊 ユニットA:
収納 ユニットB:
  Incr 判別変数
  ClearEvent
Exit

ターン 全 味方:
  If 判別変数 >= 2 Then
    (できごと)
  EndIf
Exit
# 以下では、敵ユニットを倒すたびにそのランクに応じた勝利ポイントを
# 与え、勝利ポイントが 20 以上でエピローグイベントに移ります
スタート:
  Set 勝利P 0
Exit

破壊 敵:
  Incr 勝利P Rank(対象ユニットID)
  If 勝利P >= 20 Then
    Continue 次のイベントファイル名
  EndIf
Exit
 

(5)Switch を使う
 変数の値によってさまざまに分岐させるには、「Switch」コマンドが便利です。

# ターン数を判別し、第1〜3ターン、第4〜5ターン、それら以外、
# で別の処理を行います
Switch ターン数
  Case 1 2 3
    (1〜3ターンの処理)
  Case 4 5
    (4〜5ターンの処理)
  Case Else
    (その他のときの処理)
EndSw
 

(6)多くの条件の組み合わせで分岐させる
 これはさらに複雑な場合で、多くの条件がたがいにからみあいながら分岐させます。 これには、諸条件の状態を工夫して一つの判別用変数に整理するとすっきりします。

# 三つの条件、条件A・条件B・条件Cがあり、全て不成立・条件Aのみ成立・
# ABが成立…などなどありえる組み合わせすべてで分岐させる

# まず、判別用変数をセットします。
判別変数 = IIf(条件式A, 1, 0) + IIf(条件式B, 2, 0) + IIf(条件式C, 4, 0)

# これにより、たとえば条件BCのみが成立するとき「判別変数」の値は
# 0 + 2 + 4 = 6 になります。
# あとはこの変数を使って Switch か IF で分岐させればよいだけです。
Switch 判別変数
  Case 0
    (全て不成立のときの処理)
  Case 1
    (Aのみ成立のときの処理)
  Case 2
    (Bのみ成立のときの処理)
  Case 3
    (AB成立のときの処理)
  …(中略)
EndSw

# この例では判別変数を省略して、
Switch (IIf(条件式A, 1, 0) + IIf(条件式B, 2, 0) + IIf(条件式C, 4, 0))
…(後略)
# とすることもできます。が、判別変数をきっちり出しておいたほうが、
# デバッグ作業や機能拡張・改変がしやすいです。

# 判別変数の値を文字列にする手もあります。
判別変数 = IIf(条件式A, "o", "x") & IIf(条件式B, "o", "x") & IIf(条件式C, "o", "x")

# この場合、たとえば条件BCだけが成立するとき「判別変数」の値は
#  "xoo" になります。
# この方法では、Like 演算子と If を組み合わせることによって、
# 柔軟な判別が可能です。
# たとえば以下は、条件ACが成立、Bはどちらでもよいときの判別です。

If 判別変数 Like "o?o" Then
…
 

(7)複数の分岐で処理内容が重複している場合
 サブルーチンを活用します。

# 一つ目の分岐では処理Aと処理B、二つ目では処理Bと処理C、
# 三つ目では処理Cと処理Aを、この順番で行います。
If (条件式1) Then
  Call 処理A
  Call 処理B
ElseIf (条件式2) Then
  Call 処理B
  Call 処理C
Else
  Call 処理C
  Call 処理A
EndIf

 もちろん同じコマンド群を繰り返して書いてもかまいませんが、変更や書き換え作業が煩雑になり、また行数が長くなる分プログラムの見通しが悪くなります。
 しばしば、Call サブルーチンの代わりに Goto を使いたくなりますがおすすめできません。 処理の流れが錯綜し、If〜EndIf や Switch〜EndSw などがどこで終了するのかもわかりづらい、非常にバグが出やすく検査のしにくいプログラムになってしまいます。

Q614. パイロットのパラメータをイベントで変更する方法は?

 ここでは、パイロットのパラメータ(格闘・射撃・命中・回避・技量・反応)をイベントで変更する方法を列挙します。 それぞれ性質が異なりますので使い分けてください。 項目はじめに「」をつけたものが比較的よく使われます。
 パラメータそのものを変化させる手段のほか、修正値を与える手段も含みます。
 下記のうち特殊能力に関連したものは、さらに多様な調整方法を持っています。 → Q616Q617

Q615. ユニットのパラメータをイベントで変更する方法は?

 ここでは、ユニットのパラメータ(HP・EN・装甲・運動性・移動力)をイベントで変更する方法を列挙します。 それぞれ性質が異なりますので使い分けてください。 項目はじめに「」をつけたものが比較的よく使われます。
 下記のうち特殊能力に関連したものは、さらに多様な調整方法を持っています。 → Q616.Q617.

Q616. パイロット用特殊能力をイベントで付加・強化などする方法は?

関連項目:ヘルプ補足/パイロットデータ/パイロット用特殊能力

Q617. ユニット用特殊能力をイベントで付加・強化などする方法は?

関連項目:ヘルプ補足/ユニットデータ/ユニット用特殊能力

Q618. 命中・回避・クリティカル、反撃オプション、特殊能力の発動など、戦闘時に起こったことを取得するには?

 一般的なやり方は、SetMessageコマンドを使う方法です。

# 切り払い時に気力を1増やす
*攻撃 全 全:
  SetMessage 相手ユニットID 切り払い $(Call(Sub2))
Exit

Sub1:
  IncreaseMorale 相手パイロット 1
Return

 ユニットの組み合わせを限定するときには、*攻撃イベントのパラメータを調整します。
 メッセージデータに直接書き込む手段もあります。 こちらは、特定キャラクターだけの動作に向いていますが、設定できるシチュエーションはより豊富です。
 どのようなシチュエーションで可能かなど、詳細はヘルプの「データの作成」->「メッセージデータ」および「SetMessageコマンド」をお読みください。

 似たようなことは、戦闘アニメデータ・特殊効果データでも可能ではあります。 ただし、以下のことに注意する必要があります。
・ 戦闘アニメは、プレイヤーの選択によりオフされることもあります
・ 特殊効果は、戦闘アニメがオンのとき、戦闘アニメと重複していると実行されません


 なお、使われた反撃オプションの検知は、システム変数「相手ユニット使用武器」で知ることもできます。

Q619. さまざまな乱数の生成方法は?

(1) 1以外から始まる乱数
 これは修正値をつければいいだけです。

# 4から9までの乱数
i = Random(6) + 3
# -3から6までの乱数
i = Random(10) - 4
 

(2) 「連続的な(稠密な)」値域の乱数
 コンピュータというものの性質上、厳密に連続的な乱数は不可能です。 しかし、引数を十分に大きな数にすれば、擬似的に表現することはできます。 (ただし、VBの仕様により、2 ^ 22 ≒約1670万以上にしても精度は上がりません: 詳しくはRandom関数を参照してください)

# 0以上 1未満の実数を返す乱数です。

# シナリオの最初などで、定数を初期化しておきます。実行時間を気にしないのなら、
# この部分は省いて、そのかわり LargeInt を関数本体で逐一求めてもかまいません
Global LargeInt
LargeInt = 2 ^ 20

# 関数本体
RealRnd:
Return ((Random(LargeInt) - 1) / LargeInt)
 

(3) 山型の確率分布の乱数
 両端よりも中央の確率が大きい乱数です。 単純な乱数よりも安定した結果が出、ゲーム上の使い勝手が良いのでしばしば使われています。
 やり方はいろいろありますが、かんたんなのは複数の乱数の和か差を使う方法です。

i = Random(6) + Random(6)

 上の例は、6面サイコロを二つ振ったのと同じです。

i = Random(6) - Random(6)

 差の場合も分布の形は和の場合とまったく同じですが、平均値・中央値はちょうどゼロになります。

i = Random(6) + Random(6) + Random(6)

 このように3つ以上の乱数を使ってもかまいません。 このほうが中央部の確率がより大きくなります。
 乱数2つのときは二等辺三角形の形の確率分布になりますが、3つ以上だと丸みをおびた形になり、数が大きくなるほど正規分布曲線に近づきます。

(4) 下端または上端が大きい確率分布の乱数
 これもいろいろやり方がありますが、比較的かんたんなやり方を紹介します。
 下記の例はいずれも 1から 10までの整数値を返します。

 <方法1>

i = Random(Random(10))

 この方法は偏りが激しいのが特徴です。 上の例だと、1だけで29.29%、1か2になる確率は48.58%にもなります。他方、6以上は17.72%にすぎません。

 三つ以上乱数を重ねて

i = Random(Random(Random(10)))

とすると偏りはもっと激しくなります。

 <方法2>

i = Min(Random(10), Random(10))

 方法1とくらべて偏りは小さくなります。 上の例だと、1は19%、2は17%、以下2%づつ小さくなります。6以上は25%です。
 三つ以上の乱数の最小値(または最大値)をとってもかまいません。

 <方法3>

i = Int(RealRnd ^ 2 * 10) + 1

 上記(2)の RealRnd関数を使う方法です。 累乗のパラメータは2乗に限定する必要はなく、小数でも1以下でもよいので柔軟な設定ができます。

(5) 「カード」のシャッフル(ランダムな順列)
 カードのシャッフルや、あらかじめ決められた複数の役割りにユニットを割り振る、たくさんのアイテムを各ユニットに一つづつ配る、などの方法です。
 大量のユニット、アイテムなどなどから重複無しに数個選ぶ(ランダムな組み合わせ)方法としても使えます。

# 52枚のカードをシャッフルします。
# ここでは連想配列「順番[カードナンバー]」で
# カードの順番を表現します。

# 順番を適当に初期化しておきます。
# 2回目以降のシャッフルでは、初期化は不要です。
Set 枚数 52
Set 順番
For i = 1 To 枚数
  順番[i] = i
Next

# シャッフル
For i = 枚数 To 2 Step -1
  Swap 順番[i] 順番[Random(枚数)]
Next

 まず最初のループで、52枚目のカードをランダムに選ばれたカードと入れ替えます。 これでどのカードも52枚目になる確率は1/52になり、このカードは「確定」としておきます。
 次のループで、51枚目のカードと入れ替える相手を、「確定」分をのぞいた残る51枚からランダムに選び、入れ替えます。どのカードも未確定である確率は51/52で同じ、どの未確定カードも51枚目になる確率は1/51で同じで、結局、どのカードも51枚目になる確率は同じです。
 以下、数を減らしながらこれを繰り返します。

Q620.マス目座標とピクセル座標との変換

 SRC では、おもに二種類の座標系が使われています。
 一つは、ユニットのマップ上の位置特定などに使われ、マップ左上隅のマス目を (1, 1) としてマス目単位で数えられる座標です。
 もう一つは、グラフィックなどで使われ、マップウインドウ左上隅または (BaseX, BaseY) を (0, 0) としてピクセル単位で数えられる座標です。システム変数 MouseX, MouseY もこの座標系によるものです。
 この二つの座標系は、数える単位も、基準位置も違います。

 これらの座標を変換するには、WX(), WY()関数を利用します。

# マップ座標 mx, my → ピクセル座標 px, py の変換
# マス目(mx, my) の左上隅の表示上のピクセル位置を求める
px = (mx - 1) * 32 + WX(1)
py = (my - 1) * 32 + WY(1)
# ピクセル座標 px, py → マップ座標 mx, my の変換
# ピクセル位置(px, py)が属しているマス目を求める
mx = Int((px - WX(1)) / 32) + 1
my = Int((py - WY(1)) / 32) + 1
# (この式は (px, py) がマップ外なら、
# マップ座標を上下左右に拡張した値を返します)

# (px, py) が必ずマップ内ならば、下の式でもかまいません。
# しかし、マップ外でマップ上方・左方のとき、答えが 1 ずれます
mx = (px - WX(1)) \ 32 + 1
my = (py - WY(1)) \ 32 + 1

 「Int(変数 / 32)」 と 「変数 ¥ 32」の違いについては、演算子 ¥, Modを参照してください。

# クリック地点のマップ座標を (ClickX, ClickY) に入れるサブルーチン
# マップ内をクリックした時 1 を返し、マップ外クリック・右クリック・
# キーボード押下の場合は 0 を返す。
# (ずっと機能拡張されたコマンドが 2008/04/08、リクエスト掲示板[2648]
# にてリクエスト中です)

ClickPoint:
Wait Click
If KeyState(1) Then
  ClickX = Int((MouseX - WX(1)) / 32) + 1
  ClickY = Int((MouseY - WY(1)) / 32) + 1
  If ClickX > 0 And ClickX <= Info(マップ, 幅) And _
     ClickY > 0 And ClickY <= Info(マップ, 高さ) Then
    Return 1
# Else
# (拡張用:必要ならここにマップ外クリック時の動作)
  EndIf
#ElseIf KeyState(2) Then
#(拡張用:必要ならここに右クリック時の動作
# Talk コマンドなどを行う場合、その前に Wait Click が必要です)

#Else
#(拡張用:必要ならここにキーボード押下時の動作)
EndIf
Return 0

コメント