RPGツクールXP講座



RPGの作り方 Lv5

 さて、今までRPGの作り方をやってきましたが、今回のLv5で最終回です。だんだんややこしくなって、講座向けの内容ではなくなってきたので、このへんでやめておきます。(追加することはあるかもしれませんが)


始める前の下準備

 これから説明をしていくために、専用のプロジェクトを作ります。みなさんも、同じことをして確認する場合は、同じようにプロジェクトを作って準備してください。

 Lv4からデータを引き継ぎますが、区別するため、フォルダ名とタイトルは、ともに「test5」にします。


地名表示システム改良版

 Lv4の地名表示システムは、いくつか問題がありました。それを解決してみましょう。
 
 
◆地名表示中にセーブできるようにする
 前回は、地名表示中にセーブすると問題がおきるため、地名表示中はセーブできないようにしておきました。
 しかしそれでは、ちょっと不便なので、表示中もセーブできるようにしました。
 変更点は、処理を条件分岐で包んだだけです。下図を見てください。
 
▼コモンイベント 地名表示システム 修正後


 「$timei != nil」を条件とした条件分岐があります。
 $timeiは、地名を記録している変数です。この変数が、nil(データが入っていない)かどうかで分岐しています。
 データが入っているなら処理を行い、入っていないなら条件スイッチを切って、処理を中断するようにしています。
 ゲームを終了してロードしてきた時は、$timeiはnilになっていますので、中断され、地名表示は行われません。

 図の部分だけでなく、他の部分も条件分岐に入れています。
 並列処理の中にウェイトがあると、その部分でメニュー表示が割り込んでセーブできてしまいますので、ウェイトがある部分は、必ずウェイト終了後に、$timeiがnilかどうかチェック出来るようにしています。



◆メニュー表示時と戦闘開始時に地名表示を消す
 今の状態だと、地名表示中にメニューを表示したり戦闘になったりすると、メニューや戦闘画面の上のほうに、地名が消えずに残ってしまいます。
 そこで、メニュー表示時と戦闘開始時に地名を消すように、スクリプトに処理を付け足します。

 スクリプトエディタを開いて、スクリプト「Scene_Map」を見てください。「● メニューの呼び出し」という部分があります。
 そこを下図のように変更します。

▼スクリプト「Scene_Map」「● メニューの呼び出し」


 下記の部分が追加分です。条件スイッチをOFFにしてウィンドウを消す作業をしています。

# 地名表示システム追加分 ここから
 $game_switches[14] = false
 if $ti_w != nil
  $ti_w.dispose
  $ti_w = nil
  $timei = nil
 end
# 地名表示システム追加分 ここまで


 続いて、同じスクリプト内の「● バトルの呼び出し」にも同じものを追加します。
 下図の通りです。

▼スクリプト「Scene_Map」「● バトルの呼び出し」





◆動作確認
 実際に、地名表示中にセーブしたり、一旦終了させてロードしてみましょう。エラーが出なければうまくいっています。


戦闘 シンボルエンカウント

 前回、簡単なシンボルエンカウントシステムを作りましたが、今回は、もうちょっと複雑なものを作ります。
 ちょっとややこしくなりすぎて、講座向けではなくなってしまいましたが、一応説明しておきます。


◆仕様を決める
 シンボルエンカウントシステムをどんな仕様にするか決めます。

・マップ上をモンスターがうろうろと歩き回っている
・モンスターの動きは、ランダム、主人公を追いかける、逃げるなど様々
・モンスターと接触すると戦闘発生
・倒されたモンスターは、消滅する
・消滅したモンスターも、一定時間経過すると復活
・マップに入る度に、また復活するたびにモンスターの種類や位置が変わる
・主人公のレベルが高くなると、低レベルモンスターは、出現しにくくなったり、逃げることが多くなる
・接触した時の向きで、先制攻撃や不意打ちがある

 これらのことを実現しようと思うと、並列処理で動きをコントロールし、接触の判定も独自に行わなければなりません。多少複雑になりますが、順番に作っていきましょう。


◆モンスターを出現させる
 最初に、モンスターをマップ上に出現させます。
 Lv4のシステムでは、マップに入ったときにすでにモンスターが出現していましたが、それではモンスターの種類や出現位置を変えられませんし、またセーブして終了してしまうと、次にロードしてきた時、全部のモンスターが復活してしまいます。それでは困るので、出現していない状態から初めて、そのつど適切に判断して出現させていきます。

 まず、コモンイベントに、エンカウント出現待ちを作ります。このコモンイベントを、各モンスターのイベントから並列処理で呼び出します。

▼コモンイベント エンカウント出現待ちの内容 その1


 順番に説明します。

 最初に、変数を初期化しています。Lv4でもやりましたが、配列変数に[]を代入して、配列変数として設定します。(nilの場合のみ初期化。値が入っている場合は何もしない)
 $wait_timeは、待ち時間を記録する配列変数です。
 $enemy_numberは、現在出現しているモンスターの数を記録する変数です。
 $revival_countは、マップに入ってから、出現したモンスターの、のべ数を記録する変数です。

 次に、出現するモンスターの最大数を決める処理をしています。
 $enemy_number_maxという変数で条件分岐し、$enemy_number_maxが、nilの場合、つまりまだ値が設定されていない場合にのみ設定します。
 以下の処理で、出現最大数を設定します。

$enemy_number_max = 0           # 出現最大数に0を代入して初期化
 for event in $game_map.events.values  # マップイベントのデータを読み込んでループ
  if event.name[/encount/]       # イベント名に"encount"という文字列が含まれれば
   $enemy_number_max += 1       # 出現最大数に1加算

   key = [@map_id,event.id,"A"]    # keyに、このイベントのセルフスイッチAを設定
   if $game_self_switches[key] == true # keyに設定したセルフスイッチがONなら
    $enemy_number += 1        # 現在出現中のモンスター数に1加算
   end
  end
 end
$enemy_number_max /= 2          # 出現最大数を2で割る

 始めてみる人は、「for event in $game_map.events.values」の部分が良く分からないと思います。
 「for 〜 end」は、繰り返し処理を行うループ構造で、一定の範囲だけ繰り返し処理を行うのに使います。
 例えば、
for count in 3..5
 p count
end
 と書いたとします。この場合、3から5までの範囲で繰り消し処理を行い、変数countの値は、一巡目は3に、二順目は4に、三順目は5になります。
 p count というのは、変数countの値を表示するという命令です。("p"は表示命令です) 
 ですから、このスクリプトを実行すると、3と表示され、次に4と表示され、5と表示されて終了します。

 さて、では「for event in $game_map.events.values」は、どういう意味でしょうか? この場合、「event」は、値を受ける変数です。先の例で言うと「count」と同じ役割の変数です。
 「$game_map.events.values」は、マップイベントのデータが入った変数です。ここに、現在居るマップのマップイベントのデータが入っています。
 したがって、この「for 〜 end」は、「$game_map.events.values」のデータの範囲内でループします。
 例えば、現在居るマップに、マップイベントが3つあるなら、一巡目はひとつ目のイベントのデータが「event」に読み込まれ、二順目は二つ目のイベントのデータが、三順目は三つ目のイベントのデータが読み込まれます。そして、読み込むデータがなくなったらループを終了します。

 ここでは、「for 〜 end」の間に、「event.name」と「event.id」の2つのデータを使っています。(ただし、「event.name」は、標準の設定では読めないので、後でスクリプトを少し改造します)

 次の条件分岐、
if event.name[/encount/]
 $enemy_number_max += 1
 この部分は、イベントの名前に"encount"という文字列が含まれるかどうかで条件分岐するものです。
 このシステムでは、モンスターとそれ以外のイベントを区別するために、イベントの名前を使います。エンカウント用のモンスターイベントは、イベントの名前に"encount"と書いておきます。
 この条件分岐は、イベントの名前に"encount"が含まれていれば、$enemy_number_maxに1加算するというものですので、これでマップイベントの中で、名前に"encount"が含まれるイベントの数をカウントすることが出来ます。

 次の処理、
key = [@map_id,event.id,"A"]
if $game_self_switches[key] == true
 $enemy_number += 1
end
 この部分は、「event.id」のイベントのセルフスイッチAがONになってるかどうかで条件分岐し、なっているなら$enemy_numberに1加算するというものです。
 これは、セーブしロードしてきた場合に備えての処理です。このシステムでは、モンスターが出現するとセルフスイッチAをONにするため、すでに出現しているモンスターのイベントのセルフスイッチAは、ONになっています。
 その状態でセーブすると、ロードしてきた時も、セルフスイッチAはONのままですから、最初から出現している状態でゲームが再開されます。
 しかし、変数$enemy_numberは、ゲームを終了すると値が失われ、ロードするとnilから始まりますので、実際に出現しているモンスター数と、カウント数にズレが生じます。
 それを補正するために、セルフスイッチAがONになっているイベントの数を、$enemy_numberに入れて、数を合わせます。


▼コモンイベント エンカウント出現待ちの内容 その2


 順番に説明します。

 最初に、現在のプレイ時間を取得します。

 次に、待機時間が設定されていないなら、待機時間を設定します。

if $wait_time[@event_id] == nil  # 待機時間がnilなら
 sec = 3+rand(8)         # 変数secに3と乱数を足したものを代入
 sec += Graphics.frame_count/Graphics.frame_rate # 現在のプレイ時間を加算
 $wait_time[@event_id] = sec   # 待機時間にsecを代入
end

 これで、待機時間が、現在のプレイ時間+3+乱数(0-7)に設定されます。

 次に、出現するかどうかの判定を行います。
 ここでは、条件分岐が3つ重なっています。つまり、3つの条件が揃った時のみ、モンスターを出現させる処理をするわけです。

 最初の条件「$wait_time[@event_id] <= @sec」は、待機時間が現在のプレイ時間以下になったら、というものです。つまり待機時間が切れたら、出現条件の一つを満たすわけです。

 二つ目の条件「$enemy_number < $enemy_number_max」は、現在の出現数が最大出現数を下回っている場合は、というものです。モンスターの出現数が、最大出現数以上にならないようにするためです。
 この条件には、条件を満たさなかった場合の処理もあり、その場合、再び待機時間を設定します。その処理は、下記のようなものです。
 
sec = 0                 # 初期化
sec += $revival_count * 5        # 今までの出現のべ回数に5をかけて加算
sec += rand(15)             # 乱数を加算
for i in 0..$game_party.actors.size-1  # パーティに居る主人公キャラの人数でループ
 sec += $game_party.actors[i].level * 3 # 主人公キャラのレベルに3をかけて加算
end
if sec <= 5               # もしsecが5以下なら
 sec = 5                # secを5に設定
end
sec += Graphics.frame_count/Graphics.frame_rate # 現在のプレイ時間を加算
$wait_time[@event_id] = sec           # 待機時間に代入

 「sec += $revival_count * 5」は、今までの出現数が多いほど、次の待機時間を長くするための処理です。あまりモンスターが多く出現してもプレイしにくいので、だんだんと出現率を下げるためにこうしています。
 仮に、すでにモンスターが10回出現しているなら、10*5=50で、50秒出現が遅れることになります。

 下記の処理、
for i in 0..$game_party.actors.size-1
 sec += $game_party.actors[i].level * 3
end
 これは、主人公キャラのレベルが高いほど、次の待機時間を長くするための処理です。
 主人公が4人で全員レベル4なら、4*4*3=48で、48秒待機時間が長くなります。
 これは、主人公のレベルが上がったら、弱いモンスターを出現しにくくするためにそうしています。

 「if sec <= 5 sec = 5」この処理は、待機時間が余りにも短すぎると困るので、最低でも5秒以上にするため処理です。


 三つ目の条件「$game_map.events[@event_id].x != $game_player.x or $game_map.events[@event_id].y != $game_player.y」は、主人公と座標が重なっていない場合は、というものです。
 主人公キャラと重なって出現すると変なので、座標が違う場合のみ出現させます。
 この条件には、条件を満たさなかった場合の処理もあり、その場合、再び待機時間を設定します。その処理は、下記のようなものです。

sec = Graphics.frame_count/Graphics.frame_rate + 3
$wait_time[@event_id] = sec

 つまり、待機時間を3秒に設定します。



 出現条件を満たしたら、出現させます。

▼コモンイベント エンカウント出現待ちの内容 その3


 順番に説明します。

 各種カウント($revival_countと$enemy_number)に加算します。

 $wait_time[@event_id]に、0を代入して、待機時間を初期化します。

 $game_map.events[@event_id].opacityを0にして、透明にします。

 次に、現在のキャラグラフィックを、このイベントの1ページ目のキャラグラフィックと同じものに設定します。

$game_map.events[@event_id].character_name =
$game_map.events[@event_id].event.
pages[0].graphic.character_name  

 これは、3行に分かれていますが、実は長い1行のスクリプトです。つまり、こういうことです。

$game_map.events[@event_id].character_name = $game_map.events[@event_id].event.pages[0].graphic.character_name 

 「$game_map.events[@event_id].character_name」というのが、現在のキャラグラフィックで、それに1ページ目のグラフィックである「$game_map.events[@event_id].event.pages[0].graphic.character_name」を設定します。
 「pages[0]」とありますが、これが1ページ目の指定です。0から始まりますので、1ページ目が2、2ページ目が1ということになります。
(ただし、「$game_map.events[@event_id].event.pages[0].graphic.character_name」は、標準の設定では読めないので、後でスクリプトを少し改造します)

 次に、画面内で出現する場合は、効果音を鳴らします。
 このイベントが、画面内に居るかどうかを調べる条件分岐の条件は、下記の2つです。
$game_map.events[@event_id].screen_x >= 16 and $game_map.events[@event_id].screen_x <= 624
$game_map.events[@event_id].screen_y >= 32 and $game_map.events[@event_id].screen_y <= 480

 「screen_x」と「screen_y」は、画面座標です。画面上のどの位置にいるかを知ることが出来ます。
 イベントが、画面の左上隅に居る場合は、画面座標は、x=16 y=32になります。
 イベントが、画面の右下隅に居る場合は、画面座標は、x=624 y=480になります。
 したがって、イベントの画面座標が、その範囲内にある場合、画面内で出現したと判断し、効果音を鳴らします。


▼コモンイベント エンカウント出現待ちの内容 その4


 順番に説明します。

 不透明度を上げる、で少しづつ不透明度を上げて、姿を現します。
 その後、セルフスイッチをONにして、出現した時の処理をするページに切り替えます。

 最後に、イベントの一番最後で、ウェイトを20フレームかけています。
 このイベントは、多数のイベントから、常に呼び出され続けるものですから、ウェイトを多めにして負荷を減らしています。


◆スクリプトを変更する
 先に書いたとおり、スクリプトを少し変更します。
 標準の設定では取得できない、次の二つの情報を取得できるようにするためです。
event.name #イベントの名前
$game_map.events[@event_id].event.pages[0].graphic.character_name #イベントの1ページ目のキャラグラフィックのファイル名

 まず、スクリプトエディタを開いて、「Game_Event」というスクリプトを開きます。
 最初の方にいくつか追加します。図を見てください。

▼スクリプト「Game_Event」の内容


 この図で言うと、15〜17行目の下記の部分、
attr_reader  :name           # 追加分
attr_reader  :event          # 追加分
attr_reader  :pages          # 追加分 

 そして、32行目の下記の部分です。
@name = @event.name # 追加分

 これで、情報が取得できるようになります。



◆エンカウントイベントを設定する
 さて、それでは、実際にエンカウント用のモンスターイベントを作ってみましょう。
 全部で4ページになりますが、まず最初の3ページです。

▼エンカウントイベントの内容 1ページ目


 最初のページは、ただモンスターのグラフィックを設定するだけです。このページは、出現しませんので、設定は何でもかまいません。
 ただ、先に書いたとおり、出現時にこのページのモンスターグラフィックが使われますので、キャラグラフィックだけは、正しく設定しておく必要があります。

 また、イベントの名前が、「encount スライム」になっていることに、注目してください。
 先に書いたとおり、エンカウント用のイベントの名前には、「encount」という文字列が含まれている必要があります。エンカウント用のイベントか、通常のイベントかを区別していますので、間違えないようにしておきます。(ちなみに、encountの前や後に、他のことが書いてあっても大丈夫です)

▼エンカウントイベントの内容 2ページ目


 2ページ目の設定で注目すべきは、「すり抜け」です。すり抜けになっていると、他のモンスターが上を素通りできます。
 ツクールXPでは、キャラグラフィックが無しになっているイベントの上を、主人公キャラは素通りできます。しかし、他のイベントが移動ルートの設定などで移動する場合は、素通りできません。そこで、すり抜けにして、他のモンスターの通行の邪魔にならないようにしておきます。

 また、「並列処理」になっており、コモンイベント「エンカウント出現待ち」を呼び出し続けます。
 これで、「エンカウント出現待ち」で出現条件を満たせば、セルフスイッチAがONになって、出現します。

▼エンカウントイベントの内容 3ページ目


 3ページ目には、まだ、イベント実行内容は設定していません。後で、設定します。
 とりあえず、キャラグラフィックを設定することと、条件にセルフスイッチAを設定しておきます。


◆動作確認
 この状態で、動作確認してみます。エンカウント用イベントをいくつかコピーして、実行してみてください。
 うまくいけば、数秒で出現するはずです。出現数は、設置したエンカウント用イベント数の半分になるはずです。





◆モンスターを移動させる
 セルフスイッチAがONになると、3ページ目に切り替わります。3ページ目は、モンスターを行動させるためのページです。
 エンカウントイベントの3ページを下記のように設定します。
 これも、並列処理でコモンイベントを呼び出し続けます。
 このページの移動速度は、移動する際の一歩歩く速度に影響しますが、移動頻度は移動の間隔には影響しませんので注意してください。 

▼エンカウントイベントの内容 3ページ目


 順番に説明します。

 最初にまず、配列変数を初期化しています。nilの場合空の配列を代入します。

 次に、行動タイプを設定します。
 $action_type[@event_id]は、行動のタイプを決める値を代入する変数です。
 とりあえず、下記の8タイプを用意しました。
0=完全停止
1=ノーマル
2=好戦的
3=消極的 
10=向き変えのみ
11=ランダムのみ
12=近づくのみ
13=逃げるのみ


 次に行動速度を設定します。
 $action_speed[@event_id]は、行動の間隔を決める値です。フレーム単位で設定します。
 この値を40にすれば、40フレームごとに一歩移動します。
 この値は、動き終わってから次に動くまでの時間ではなく、動き始めてから次に動くまでの時間です。したがって、一歩動くのに40フレームかかれば、次の一歩は動き終わった直後に始まります。

 最後に、コモンイベント「エンカウント行動」を呼び出します。


◆コモンイベント「エンカウント行動」を作る
 コモンイベントの「エンカウント行動」を作ります。
 内容は下図の通り。

▼コモンイベント エンカウント行動の内容 その1


 ●変数の初期化
 最初に、例によって変数を初期化しています。
 $move_mode[@event_id]は、移動モードを設定する変数です。
 移動モードは、下記の5つです。
0.停止
1.近づく
2.ランダム
3.逃げる
4.向き変えのみ
 
 $wait_time[@event_id]は、出現待ちのときに待機時間を記録していた変数ですが、ここでは行動時間を記録するのに使います。

 $move_judg[@event_id]は、移動モードを決定する際の判定用の変数です。



▼コモンイベント エンカウント行動の内容 その2


 ●移動モードの設定

 移動モードの設定を行います。
 $wait_time[@event_id]の値で条件分岐しています。
 行動時間が残っているなら設定は行わず前回の設定のままもう一度移動し、行動時間が残っていないなら、改めて移動モードの設定を行う、そのための条件分岐です。

 移動モードの設定では、まず$move_judg[@event_id]に乱数を代入し、1〜100の範囲の値を設定します。
 それに、さらに主人公の合計レベルを加算します。これは、主人公のレベルが高いほど、モンスターが逃げる確率を高くするためです。

 次に、$move_mode[@event_id]に、移動モードを代入して設定します。
 この処理は、行動タイプにより設定方法が変わるため、$action_type[@event_id]の値によって条件分岐します。
 例えば、行動タイプが0の場合、$move_judg[@event_id]の値に関わらず、必ず$move_mode[@event_id]に0が代入されます。なぜなら、行動イプの0は、完全停止で動かないからです。そのため、$move_mode[@event_id]には、0が代入され、移動モードは「0.停止」になるわけです。
 行動タイプが1の場合は、$move_judg[@event_id]の値により、設定される移動モードが変わります。
 $move_judg[@event_id]が、1〜25の場合、$move_mode[@event_id]は0に
 $move_judg[@event_id]が、26〜50の場合、$move_mode[@event_id]は1に
 $move_judg[@event_id]が、51〜75の場合、$move_mode[@event_id]は2に
 $move_judg[@event_id]が、76以上の場合、$move_mode[@event_id]は3に
 それぞれ設定されます。
 つまり、行動タイプが1の場合は、4つの移動モードがほぼ均等の確率で選択されるわけです。ただし、主人公のレベルが$move_judg[@event_id]に加算されますので、レベルが上がるほど「3.逃げる」が選択される確率が高くなります。

 移動モードが設定された後に、行動時間が設定されます。「$wait_time[@event_id] = 8+rand(8)」という処理です。これで、行動時間が8〜15の範囲で設定されます。
 つまり、8〜15回、同じ移動モードで移動し、その後新たに移動モードが設定され、また8〜15回、同じモードで動く、ということを繰り返すことになります。


▼コモンイベント エンカウント行動の内容 その3


 ●向きの変更

 モンスターの向きを変えます。
 このシステムでは、まず向きを変えてから、一歩前進させて移動させます。
 例えば、ランダムに移動させる場合、「ランダムに移動」で移動させるのではなく、「ランダムに方向転換」させた後に、「一歩前進」で移動させます。なぜ、わざわざ二つに分けているかといえば、向きを変えてから一歩前進する前に、主人公キャラとの接触判定をするからです。


▼コモンイベント エンカウント行動の内容 その4


 ●接触判定

 接触判定をしますが、その前に、また変数の初期化をします。
 何故ここでするかというと、この前の処理(向きの変更)で、ウェイトを使っているからです。並列処理の中にウェイトがあると、そこでセーブされる可能性があります。ゲームを終了した時には、変数が初期化されるので、初期化されてもいいように、ここで改めて今後使用する変数の初期化をしてやります。

 $move_mode[@event_id]は、前にも使いました。移動モードを記録する変数です。

 $my_x[@event_id]と$my_y[@event_id]は、エンカウント用イベントの座標を記録する変数です。

 $touch_mode[@event_id]は、接触したかどうかを記録する変数です。

 ▼コモンイベント エンカウント行動の内容 その5


 ●接触判定のつづき

 接触判定の処理です。まず、エンカウント用イベントの座標を$my_xと$my_yに代入します。

 次に、エンカウント用イベントの向きによって分岐し、調べる座標を調整します。
 「$game_map.events[@event_id].direction」というのが、向きが記録されている変数で、2なら下向き、4なら左向き、6なら右向き、8なら上向きです。
 エンカウント用イベントの一歩前に、主人公キャラが居るかどうか調べたいので、調べる座標が一歩前になるように、座標に1を加算したり減算したりして調整します。

 次に、調査する座標(エンカウント用イベントの一歩前)と主人公キャラの座標が同一かどうか調べて、同一なら$touch_mode[@event_id]に1を代入します。1は、接触したという意味です。

 $touch_mode[@event_id]が1の場合、不意打ちの判定をします。不意打ちは、接触時の向きで判断します。
 主人公キャラの横や後ろから接触した場合は不意打ちになります。
 不意打ちの場合は、$encount_modeに1が代入され、不意打ちでない場合は、$encount_modeに0が代入されます。

 不意打ち判定が終わったあと、セルフスイッチのBをONにし、イベント処理の中断でイベントを終了させます。
 セルフスイッチのBは、エンカウント用イベントの4ページ目の条件に指定しておき、セルフスイッチのBがONになると、自動実行で戦闘が始まるようにしておきます。


▼コモンイベント エンカウント行動の内容 その6


 ●移動処理

 接触しなかった場合、移動処理を行います。
 まず、移動前に現在のエンカウント用イベントの座標を$my_xと$my_yに代入します。後で判定に使うためです。

 次に、一歩前進させます。この移動ルートの設定には、「移動できない場合は無視」のチェックをつけておきます。
 この一歩前進は、条件分岐の中に入っています。この条件は、「$move_mode[@event_id] >= 1 and $move_mode[@event_id] <= 3」です。
 つまり、移動モードが1から3の間の場合は、一歩前進するというものです。移動モードが0の場合は、停止状態なので移動させないようにするためです。


▼コモンイベント エンカウント行動の内容 その7


 ●移動後の調整

 前の処理でウェイトが入りましたので、例によって変数がnilになっていた場合の初期化をします。
 ここで初期化するのは、$action_speedです。これは、エンカウント用イベントの方で設定される値ですが、これがnilになっていた場合は、仮に10という値を与えてやります。

 次に、休止します。
 「@wait_count = $action_speed[@event_id]」で、$action_speed[@event_id]の値分の、ウェイトがかかります。

 ウェイトがかかったので、また、nilになっていた場合の初期化作業をします。


▼コモンイベント エンカウント行動の内容 その8


 ●移動後の調整のつづき

 つっかえ判定をします。
 移動前に記録した座標と、今の座標を比べ、変わっていなければ、障害物につっかえていると判断し、強制的に移動モードを「2.ランダム」に変えます。
 ただし、移動モードが「0.停止」の場合と、「4.向き変えのみ」の場合は、座標は変わらないので、処理しません。

 最後に、移動時間を1減らします。
 「$wait_time[@event_id] -= 1」という処理です。一回行動するごとに、移動時間が減っていく仕組みです。



◆バトルの設定
 エンカウント用イベントに4ページ目を作って、バトルの設定をします。
 条件に、セルフスイッチのBを指定し、トリガーを自動実行にします。コモンイベント「エンカウント行動」の中で、プレイヤーと接触すると、セルフスイッチのBがONになるように設定しました。
 このページは、自動実行で開始されますから、セルフスイッチのBがONになると即座にバトルが発生するわけです。


▼エンカウントイベントの内容 4ページ目


 見ての通り、バトルの処理でバトルを発生させるだけのシンプルな処理です。
 勝った場合、逃げた場合、負けた場合に、それぞれコモンイベントを呼び出すようにしてあります。
 勝った場合は、コモンイベントを呼び出す前に、$wait_time[@event_id]に値を代入します。これは、次に復活する前の待機時間を算出するための基礎となる数値で、この値が小さいほど早く復活します。マイナスでもかまいません。

 コモンイベントの内容を説明します。

▼コモンイベント バトルに勝利したときの内容 その1


 最初に、モンスターを消します。効果音を鳴らし、徐々に透明にしていきます。
 その後、ランダムに方向転換し、一歩前進を繰り返します。これは、消えた位置と次の出現位置を少しずらすためです。


▼コモンイベント バトルに勝利したときの内容 その2


 変数を初期化します。

 次に、$enemy_numberから1減算し、出現数を減らします。モンスターが1体消えたわけですから、その分減らすわけです。

 次に、復活までの待機時間を設定します。

sec = $wait_time[@event_id]    # エンカウント用イベントで設定した基本地を代入
sec += $revival_count * 5     # のべ出現回数に5をかけて加算
sec += rand(15)          # 乱数を加算
for i in 0..$game_party.actors.size-1   # プレイヤーのレベルに3をかけて加算
 sec += $game_party.actors[i].level * 3
end
if sec <= 5            # 待機時間が5以下なら5に設定
 sec = 5
end
sec += Graphics.frame_count/Graphics.frame_rate # 現在のプレイ時間を加算
$wait_time[@event_id] = sec           # 待機時間に代入


 最後に、セルフスイッチAとBをOFFにして、出現待ちの状態に戻します。


 ▼コモンイベント バトルで逃げたときの内容


 逃げた時は、移動モードを0にして、行動時間を2にします。これは、逃げた直後は少しモンスターを休止状態にするためです。

 最後に、セルフスイッチBをOFFにして、行動ループに戻します。

 
 負けた時は、ゲームオーバーにするだけです。



◆動作確認
 動作確認してみます。エンカウント用イベントをいくつかコピーして、実行してみてください。
 うまくいけば、モンスターから接触した時、戦闘が起きるはずです。
 モンスターから接触するように、行動タイプを2や12にしておくとよいでしょう。



◆プレイヤーからの接触判定
 今の状態では、モンスター側からは接触しますが、プレイヤー側からの接触はありません。
 そこで、プレイヤー側からの接触を行うようにします。
 スクリプトエディタを開いて「Game_Player」というスクリプトを選択してください。ここに、「● 接触イベントの起動判定」というのがあります。ここに下記のように追加します。

 ▼スクリプト 「Game_Player」


 順に説明します。

# エンカウントシステムの接触判定 追加分 ここから
if event.x == x and event.y == y
 # ジャンプ中以外で、起動判定が正面のイベントなら
 if not event.jumping? and not event.over_trigger?
  if event.name[/encount/]             # 接触したイベントの名前に"encount"が含まれるなら
   # 不意打ち判定
   @e_d = $game_map.events[event.id].direction   # 接触したイベントの向きを代入
   @p_d = $game_player.direction          # 主人公キャラの向きを代入
   $encount_mode = 2         # とりあえず$encount_modeを2(主人公側の不意打ちの設定)に設定
   if @e_d == 2 and @p_d == 8     # 接触したイベントと主人公が向き合っているなら
   $encount_mode = 3         # $encount_modeを3(通常のエンカウント)に設定
   end
   if @e_d == 8 and @p_d == 2
   $encount_mode = 3
   end
   if @e_d == 4 and @p_d == 6
   $encount_mode = 3
   end
   if @e_d == 6 and @p_d == 4
   $encount_mode = 3
   end
   key = [$game_map.map_id,event.id,"B"] # 接触したイベントのセルフスイッチBをkeyに設定
   $game_self_switches[key] = true    # セルフスイッチBをONに
   $game_map.need_refresh = true     # マップをリフレッシュ(リフレッシュしないとすぐに戦闘が起きないため)
  end
 end
end
# 追加分 ここまで

 これで、プレイヤーから接触した場合も、戦闘が起きるようになります。


◆不意打ち
 今まで、不意打ちの判定をして、「$encount_mode」に値を記録してきました。
 $encount_modeが、1ならモンスター側の不意打ち、2ならプレイヤー側の不意打ちです。
 これを、実際にバトルに反映させます。

 まず、新しいステートを作るので、データベースを開いて、ステートタブをクリックしてください。

 ▼データベースの設定 ステート


 上手のように、「不意打ち」というステートを設定しました。
 ポイントは、「制約」の項目を「行動できない」にすること、そして解除条件で、0ターンで100%解除されるようにしておくことです。こうすれば、最初のターンだけ行動不能にすることができます。
  
 次に、バトルイベントを編集します。データベースを開いて、トループタブをクリックしてください。

 ▼データベースの設定 トループ


 上図のように設定します。バトルイベントの条件を「ターン0」にします。つまり、最初のターンにのみ発動するようにします。
 あとは、コモンイベント「バトル0ターン目の処理」を呼び出すだけです。これは、全モンスター共通の処理なので、すべてのトループに同じように設定します。

 コモンイベント「バトル0ターン目の処理」の内容は、下記の通りです。

 ▼コモンイベント バトル0ターン目の処理


 このイベントは、シンプルですね。
 $encount_modeの値で分岐して、ステートを変化させるだけです。



◆動作確認
 これで、エンカウントシステムは、完成です。以下のようなことを確認してみてください。
・ちゃんとモンスターが出現するか
・プレイヤーからの接触判定は正常か
・モンスターからの接触判定は正常か
・横や後ろから接触した時の不意打ち判定は正常か
・勝利した時や逃げた時の処理は正常か
・消えたモンスターはちょんと復活するか
・セーブしてゲームを終了しロードしてきても正常に動作しているか



◆モンスターを配置する時の注意
 モンスターをマップ上に配置する時、少し注意が必要です。
 マップ上には、他のイベントもあります。マップ移動イベントや宝箱などです。これらのイベントがある場所にモンスターが近づいてこれると、トラブルの元になります。
 例えば、出口にモンスターがつっかえて邪魔になるとか、宝箱を調べている間に、モンスターが集まってきて囲まれてしまうとか。
 それもまた良いという考え方もありますが、他のイベントの周りからモンスターを排除したい場合は、グラフィックに何も指定しない透明なイベントを配置します。
 イベントが移動ルートの設定などで、イベントが動く場合、他のイベントには重ならないという特性があります。これを利用して、透明なイベントでブロックするわけです。
 これで、プレイヤーは通過できるが、モンスターは通過できない見えない壁ができますので、うまくモンスターの進入を防ぎましょう。


岩を転がす

 洞窟内のちょっとした仕掛けとして、岩を転がすパズルのようなものを作ってみます。


◆押すと移動する岩を作る
 最もシンプルな「押すと移動する岩」は、下記のように設定すれば出来ます。 

▼転がし岩のイベント


 トリガーの設定を、「プレイヤーから接触」にしておき、接触したら「移動ルートの設定で」プレイヤーから遠ざかるようにすればいいだけです。

 これで、一応移動する岩は出来るのですが、これだけではちょっと寂しいので、もう少しそれらしくしたいと思います。下記のようにします。

 ・Cボタンを押した時は移動はせずにメッセージが出る
 ・転がる時にゴロゴロと音を出す
 ・障害物につっかえたときはぶつかった音を出す
 ・主人公キャラもいっしょに移動する

 上記を踏まえて修正しました。岩のイベントの名前は、すべて「転がし岩」にしておきます。

▼転がし岩のイベント 修正


 まず、条件分岐でCボタンを押しているかどうかで分岐します。
 これで、Cボタンを押してイベントを開始した時と、接触してイベントを開始した時の処理を分けることが出来ます。

 次に、下記の処理で、このイベントの座標を記録します。
 @iwax = $game_map.events[@event_id].x
 @iway = $game_map.events[@event_id].y

 次に、このイベントとプレイヤーを「移動ルートの設定」で移動させます。
 イベント→プレイヤーの順で設定します。プレイヤーが移動しません。
 イベントの方の「移動ルートの設定」で向き固定のOFFをしているのは、そうしないと転がっているアニメーションが表示されないからです。これは、オプションで「向き固定」を設定しているためです。なぜ、「向き固定」にしたかというと、Cボタンでイベントを開始した場合、「向き固定」にしていないと、向きが変わって岩が動いたように見えてしまうからです。

 次に、移動前に記録した座標と現在の座標を比べて、座標が変わっているかどうかで条件分岐します。
 変わっていれば、移動したということですので、ゴロゴロという音を鳴らします。
 変わっていなければ、移動していないので、ぶつかったような音を出します。
 
 最後に、ウェイトをかけて、調整します。
 このウェイトが長いと、一度押してから次に押せるまでの間隔が開きます。


◆動作確認
 岩を配置して動かしてみましょう。
 ちゃんと動くか、音は出るか、障害物にぶつかった時も正しく音が出るか、Cボタンでイベントを開始した時メッセージが出るかなどを確認します。


◆コモンイベント化
 転がし岩は、いくつも作りますので、例によってコモンイベントに移します。


◆スイッチ床を作る
 主人公キャラや岩を乗せるとスイッチがONになる床を作ります。
 これで、扉を開ける仕掛けを作ります。

 まず、下図のようにマップを作ります。

▼マップ


 色の変わっている床の部分に、主人公キャラか岩が乗っかると、扉が開くようにします。

 色の変わっている床の部分に、透明なイベントを作り、下図のように設定します。

▼スイッチ床のイベント その1


 オプションで、すり抜けを設定しておくのを忘れないでください。そうしないと、他のイベントが重なることが出来ないので、岩を乗せることが出来ません。

 トリガーは、並列処理にして、常に上に何か乗っかってないか監視し続けます。

 イベント実行内容を順番に説明します。

 まず、このイベントの座標を変数に代入します。これは、必ずしも必要な処理ではありません。このイベントの座標を表す変数「$game_map.events[@event_id].x」が、長すぎて始末が悪いので、短い名前の変数に値を移して使うだけです。

 次に、主人公キャラの座標と、このイベントの座標が同じかどうか調べ、同じなら(つまり主人公が乗っかっているなら)イベントIDが12のイベントのセルフスイッチAをONにします。なぜ、12かというと、扉のイベントのイベントIDが12だからです。扉のイベントのIDが12ではない場合は、当然その数字に書き換えてください。
 これで、扉のイベントのセルフスイッチをONにして、扉が開く処理をしてやります。

 主人公キャラが、乗っかっていない場合は、岩が乗っかっていないか調べます。次の処理です。
 マップ上にあるイベントを順番に調べて、名前が転がし岩で、なおかつ自分自身と同じ座標にあるイベントがあっちゃ場合、変数@onに1を代入して終了するという処理です。

for event in $game_map.events.values     # マップイベントのデータでループ
 @on = 0                   # 変数を初期化
 if event.name[/転がし岩/]          # イベントの名前に"転がし岩"が含まれれば
  if @ix == $game_map.events[event.id].x   # X座標が同じなら
   if @iy == $game_map.events[event.id].y  # Y座標が同じなら
    @on = 1                # 変数@onに1を代入
    break                 # ブレイクしてループを抜ける
   end
  end
 end
end


▼スイッチ床のイベント その2


 続きです。
 変数@onが、1かどうかで分岐します。
 1なら、イベントIDが12のイベント(扉のイベント)のセルフスイッチAをONにします。

 1ではないなら、扉のイベントのセルフスイッチBがONになっている場合、セルフスイッチCをONにします。


◆扉のイベントを作る 
 扉のイベントは全部で4ページになります。
 1ページ目は、閉じている状態。
 2ページ目は、自動的に扉を開ける処理。
 3ページ目は、開いている状態。
 4ページ目は、自動的に扉を閉める処理。
 となっています。

▼扉のイベント 1ページ目



▼扉のイベント 2ページ目



▼扉のイベント 3ページ目



▼扉のイベント 4ページ目




◆動作確認
 スイッチ床に乗ったり降りたりして、扉が開閉するか確認しましょう。
 また、岩を乗せてみて、開閉するか確認しましょう。


Lv5のまとめ

 これで、「RPGの作り方 Lv5」は、終わりです。
 ひとまず、「RPGの作り方」は、これで終了です。

 ここまで作った分を、下記からダウンロードできます。

 サンプルゲーム「test5.exe」363KB


 エンカウントシステムがかなり重かったので、ちょっと軽量化したものを作りました。
 これでもまだ少し重めかもしれませんねえ・・・。
 サンプルゲーム「test5-2.exe」




Last Updated : 2004-10-19

Copyright © 2004 noziko irie. All rights reserved.
http://gcg.sakura.ne.jp/tt/tt_top.htm