ゲームを作ろう! ターン制バトルその1 魔王に行動させよう


プログラミングといえば、「ゲームを作りたい!」という方も多いでしょう。
Small Basicのプログラムギャラリーのページ(英語)にも、ゲームが多数掲載されています。
しかし、並んでいるのはアクションゲームとか、迷路とか、シューティングとか、パズルとか……だいたい、アクションかパズルのどっちかですね。諸々の都合で、言語を選ばないゲームが掲載されているんでしょうけど……。
「どうせならRPG作りたい!(RPGが好きだから)」
……という方は、素直にRPGを作成するためのソフトウェアを使った方が楽なはずです。w
RPGツクールとか、無料ならWOLF RPGエディターとか)
以降は、「Small Basicでプログラミングの勉強するぜ! でもどうせならRPG作りたい!」という方向けです。w

さて、いきなり大作RPGを作るのは難しいですね。
ここでは、RPGのターンバトルを再現するプログラムを考えてみたいと思います。
複雑なプログラムは止めて、ものすごーく簡単な感じにしましょう。

・プレイヤーキャラクターは1人、敵も1体のタイマンバトル。ここでは仮に「勇者」と「魔王」のバトルとします。
・「勇者」と「魔王」が必ず交互に攻撃をすることにする。
・「勇者」のコマンドは「戦う」「回復魔法」「攻撃魔法」の3つに絞る。「戦う」のみ、「通常攻撃」「会心の一撃」がランダムで出るようにする。
・「魔王」は「通常攻撃」「魔法攻撃」「必殺技」「様子を見る」の中からランダムで選んだ行動を行う。
・「勇者」と「魔王」にはHPを設定する。どちらかのHPが0になったら終了。
・「勇者」にはMPも設定する。「回復魔法」「攻撃魔法」を使う時に消費し、MPの回復はしない。
・とりあえず、メッセージウィンドウでのみの戦いとしてみる(ビジュアルを作るのは後回し)

プログラム全体はどんな感じになるか、メモってみましょう。

(1)最初に表示されるのは、勇者の行動を選択する「戦う」「回復魔法」「攻撃魔法」のボタンと、勇者のHPとMP、魔王のHP。

(2)ボタンを押して、勇者の行動を選択する。
(2-1)勇者「戦う」……80%で「通常攻撃」、魔王のHPを「通常攻撃」で与えたダメージ分減らす。20%で「会心の一撃」、魔王のHPを「会心の一撃」で与えたダメージ分減らす。
(2-2)勇者「回復魔法」……まず、勇者のMPが5以上かどうか判定し、5未満なら「MPが足りないので回復魔法は使えません」を表示しボタン選択に戻る。勇者のMPが5以上なら、勇者のHPを回復した後に、MPを-5する。
(2-3)勇者「攻撃魔法」……まず、勇者のMPが10以上かどうか判定し、10未満なら「MPが足りないので攻撃魔法は使えません」を表示しボタン選択に戻る。勇者のMPが10以上なら、魔王のHPを与えたダメージ分減らした後に、MPを-10する。

(3)勇者の行動が終了し、魔王のHPが0以下になっていたら勇者の勝利としてプログラムを終了。1以上なら魔王の行動ターンに移行するため、「魔王の行動」ボタンを表示する。

(4)「魔王の行動」ボタンが押されたら、魔王が以下を確率で選択し行動する。
(4-1)魔王「通常攻撃」……確率70%。ダメージ量は小さめ。勇者のHPを与えたダメージ分減らす。
(4-2)魔王「魔法攻撃」……確率15%。ダメージ量は中程度。勇者のHPを与えたダメージ分減らす。
(4-3)魔王「必殺技」……確率5%。ダメージ量は大きめ。勇者のHPを与えたダメージ分減らす。
(4-4)魔王「様子を見る」……確率10%。実質何もしない。「魔王は 高笑いをしている!」などのメッセージにしてもいいだろう。

(5)魔王の行動が終了し、勇者のHPが0以下になっていたら魔王の勝利としてプログラムを終了。1以上なら(1)に戻る。

rpg

上では確率をかなり適当に決めました。
実際にプレイして、バランスを調整する必要があるでしょう。

で、その確率ですが、どう考えたら良いでしょうか?
ここでは

Math.GetRandomNumber(maxNumber)

を使ってみます。
Math.GetRandomNumber(maxNumber)では、1 から maxNumber の間の乱数(maxNumber を含む)を取得します。
Math.GetRandomNumber(100)なら、1から100までのいずれかの数字をランダムで取得します。
例えば魔王の行動だったら、

(4-1)魔王「通常攻撃」……確率70%。Math.GetRandomNumber(100)で得た数値が1〜70の時に行動する。
(4-2)魔王「魔法攻撃」……確率15%。Math.GetRandomNumber(100)で得た数値が71〜85の時に行動する。
(4-3)魔王「必殺技」……確率5%。Math.GetRandomNumber(100)で得た数値が86〜90の時に行動する。
(4-4)魔王「様子を見る」……確率10%。Math.GetRandomNumber(100)で得た数値が91〜100の時に行動する。

とすればよさそうです。
まず、この「魔王の攻撃を表示するプログラム」だけ作ってみましょうか。
下では日本語の入力部分がありますが、Small Basic上では日本語入力が不可能なので、テキストエディタ(メモ帳)に日本語で書いたものをコピーアンドペーストして入力しています。

GraphicsWindow.Title = "勇者VS魔王"
GraphicsWindow.Width = 300
GraphicsWindow.Height = 200

maouturn = Controls.AddButton("魔王の攻撃", 10, 10)
Controls.ButtonClicked = OnClick

Sub OnClick
  maoukoudou = Math.GetRandomNumber(100)
  
  If 1 <= maoukoudou And maoukoudou <= 70 Then
    GraphicsWindow.BrushColor = "white"
    GraphicsWindow.FillRectangle(0, 0, 200, 300)
    GraphicsWindow.BrushColor = "black"
    GraphicsWindow.DrawText(10, 40, "魔王の攻撃!")
    GraphicsWindow.DrawText(50, 60, "のダメージを与えた。")
    GraphicsWindow.DrawText(10, 60, 1399 + Math.GetRandomNumber(201))
  EndIf
  
  If 71 <= maoukoudou And maoukoudou <= 85 Then
    GraphicsWindow.BrushColor = "white"
    GraphicsWindow.FillRectangle(0, 0, 200, 300)
    GraphicsWindow.BrushColor = "black"
    GraphicsWindow.DrawText(10, 40, "魔王はなんかすごい魔法を唱えた!")
    GraphicsWindow.DrawText(50, 60, "のダメージを与えた。")
    GraphicsWindow.DrawText(10, 60, maoukoudou * 153)
  EndIf
  
  If 86 <= maoukoudou And maoukoudou <= 90 Then
    GraphicsWindow.BrushColor = "white"
    GraphicsWindow.FillRectangle(0, 0, 200, 300)
    GraphicsWindow.BrushColor = "black"
    GraphicsWindow.DrawText(10, 40, "魔王はなんかすごい必殺技を放った!")
    GraphicsWindow.DrawText(50, 60, "のダメージを与えた。")
    GraphicsWindow.DrawText(10, 60, maoukoudou * 257)
  EndIf
  
  If 91 <= maoukoudou And maoukoudou <= 100 Then
    GraphicsWindow.BrushColor = "white"
    GraphicsWindow.FillRectangle(0, 0, 500, 500)
    GraphicsWindow.BrushColor = "black"
    GraphicsWindow.DrawText(10, 40, "魔王は様子を見ている。")
  EndIf
EndSub

rpg

実行するとこんな画面になるので、「魔王の攻撃」ボタンをひたすら連打してみてください。

rpg

rpg

rpg

rpg

魔王がランダムにダメージを与えているかのような文章がひたすら出てきます。
ちょっとだけRPGのバトルっぽさが出てきた? 気がします。w
上のプログラムでのポイントは、ダメージ量です。

maoukoudou = Math.GetRandomNumber(100)

の数字によって行動を4パターンに分けていますが、ダメージを与える場合は、このランダムな数字に更に適当な数字を掛け算して、与えるダメージ量としてみました。
例えば

    GraphicsWindow.DrawText(10, 40, "魔王の攻撃!")
    GraphicsWindow.DrawText(50, 60, "のダメージを与えた。")
    GraphicsWindow.DrawText(10, 60, maoukoudou * 123)

では、ランダムな数字maoukoudouに123を掛け算した結果を、ダメージ量としています。
何故123にしたのか? 適当です。w
100とかぴったりの数字にしたらランダム感が出ません(試しにやってみるとわかります)。
とはいえ、これは「1〜70のいずれかに123をかけた結果」なので、通常攻撃のくせにやたらダメージのブレ幅が大きくなってしまいますね。
「魔王の通常攻撃の値は1500程度にしたい」時はどうするか?
例えば1400以上1600未満なら、1400に、0〜200のランダムな数字を足せば良いでしょう。

    GraphicsWindow.DrawText(10, 40, "魔王の攻撃!")
    GraphicsWindow.DrawText(50, 60, "のダメージを与えた。")
    GraphicsWindow.DrawText(10, 60, 1400 + Math.GetRandomNumber(201) - 1)

こう変更すれば良さそうです。Math.GetRandomNumberでは「1から○までのランダムな数字」が取得できるため、1から201までの間のランダムな数字を計算し、最後に1を引いています。
この、魔王の通常攻撃の値も後々でいじることになるでしょうから、変数で決めておいた方が良いでしょうね。

GraphicsWindow.Title = "勇者VS魔王"
GraphicsWindow.Width = 300
GraphicsWindow.Height = 200

maoutuujou = 1400
maoumahou = 2800
maouhissatu = 5200

maouturn = Controls.AddButton("魔王の攻撃", 10, 10)
Controls.ButtonClicked = OnClick

Sub OnClick
  maoukoudou = Math.GetRandomNumber(100)
  
  If 1 <= maoukoudou And maoukoudou <= 70 Then
    GraphicsWindow.BrushColor = "white"
    GraphicsWindow.FillRectangle(0, 0, 200, 300)
    GraphicsWindow.BrushColor = "black"
    GraphicsWindow.DrawText(10, 40, "魔王の攻撃!")
    GraphicsWindow.DrawText(50, 60, "のダメージを与えた。")
    GraphicsWindow.DrawText(10, 60, maoutuujou + Math.GetRandomNumber(201) - 1)
  EndIf
  
  If 71 <= maoukoudou And maoukoudou <= 85 Then
    GraphicsWindow.BrushColor = "white"
    GraphicsWindow.FillRectangle(0, 0, 200, 300)
    GraphicsWindow.BrushColor = "black"
    GraphicsWindow.DrawText(10, 40, "魔王はなんかすごい魔法を唱えた!")
    GraphicsWindow.DrawText(50, 60, "のダメージを与えた。")
    GraphicsWindow.DrawText(10, 60, maoumahou + Math.GetRandomNumber(301) - 1)
  EndIf
  
  If 86 <= maoukoudou And maoukoudou <= 90 Then
    GraphicsWindow.BrushColor = "white"
    GraphicsWindow.FillRectangle(0, 0, 200, 300)
    GraphicsWindow.BrushColor = "black"
    GraphicsWindow.DrawText(10, 40, "魔王はなんかすごい必殺技を放った!")
    GraphicsWindow.DrawText(50, 60, "のダメージを与えた。")
    GraphicsWindow.DrawText(10, 60, maouhissatu + Math.GetRandomNumber(401) - 1)
  EndIf
  
  If 91 <= maoukoudou And maoukoudou <= 100 Then
    GraphicsWindow.BrushColor = "white"
    GraphicsWindow.FillRectangle(0, 0, 500, 500)
    GraphicsWindow.BrushColor = "black"
    GraphicsWindow.DrawText(10, 40, "魔王は様子を見ている。")
  EndIf
EndSub

これでひとまず、魔王の攻撃ターンっぽいものができました。
ついでなので、勇者のHPも表示しておき、与えたダメージ分減らすようにしましょう。
「勇者のHPが0になったら、『魔王の勝ち!』と表示してゲーム終了」というのも入れたいですね。

GraphicsWindow.Title = "勇者VS魔王"
GraphicsWindow.Width = 300
GraphicsWindow.Height = 200

maoutuujou = 1400
maoumahou = 2800
maouhissatu = 5200

yuusyaHP = 20000
GraphicsWindow.BrushColor = "black"

GraphicsWindow.DrawText(110, 10, "勇者の残りHP:")
GraphicsWindow.DrawText(190, 10, yuusyaHP)

maouturn = Controls.AddButton("魔王の攻撃", 10, 10)
Controls.ButtonClicked = OnClick

Sub OnClick
  maoukoudou = Math.GetRandomNumber(100)
  
  If 1 <= maoukoudou And maoukoudou <= 70 Then
    GraphicsWindow.BrushColor = "white"
    GraphicsWindow.FillRectangle(0, 30, 200, 300)
    GraphicsWindow.BrushColor = "black"
    GraphicsWindow.DrawText(10, 40, "魔王の攻撃!")
    GraphicsWindow.DrawText(50, 60, "のダメージを与えた。")
    mdamage = maoutuujou + Math.GetRandomNumber(201) - 1
    GraphicsWindow.DrawText(10, 60, mdamage)
    yuusyaHP = yuusyaHP - mdamage
    If yuusyaHP <= 0 Then
      GraphicsWindow.Clear()
      GraphicsWindow.BrushColor = "black"
      GraphicsWindow.FontSize = 20
      GraphicsWindow.DrawText(80, 80, "魔王の勝ち!")
    Else
      GraphicsWindow.BrushColor = "white"
      GraphicsWindow.FillRectangle(190, 10, 40, 20)
      GraphicsWindow.BrushColor = "black"
      GraphicsWindow.DrawText(190, 10, yuusyaHP)
    EndIf
  EndIf
  
  If 71 <= maoukoudou And maoukoudou <= 85 Then
    GraphicsWindow.BrushColor = "white"
    GraphicsWindow.FillRectangle(0, 30, 200, 300)
    GraphicsWindow.BrushColor = "black"
    GraphicsWindow.DrawText(10, 40, "魔王はなんかすごい魔法を唱えた!")
    GraphicsWindow.DrawText(50, 60, "のダメージを与えた。")
    mdamage = maoumahou + Math.GetRandomNumber(301) - 1
    GraphicsWindow.DrawText(10, 60, mdamage)
    yuusyaHP = yuusyaHP - mdamage
    If yuusyaHP <= 0 Then
      GraphicsWindow.Clear()
      GraphicsWindow.BrushColor = "black"
      GraphicsWindow.FontSize = 20
      GraphicsWindow.DrawText(80, 80, "魔王の勝ち!")
    Else
      GraphicsWindow.BrushColor = "white"
      GraphicsWindow.FillRectangle(190, 10, 40, 20)
      GraphicsWindow.BrushColor = "black"
      GraphicsWindow.DrawText(190, 10, yuusyaHP)
    EndIf
  EndIf
  
  If 86 <= maoukoudou And maoukoudou <= 90 Then
    GraphicsWindow.BrushColor = "white"
    GraphicsWindow.FillRectangle(0, 30, 200, 300)
    GraphicsWindow.BrushColor = "black"
    GraphicsWindow.DrawText(10, 40, "魔王はなんかすごい必殺技を放った!")
    GraphicsWindow.DrawText(50, 60, "のダメージを与えた。")
    mdamage = maouhissatu + Math.GetRandomNumber(401) - 1
    GraphicsWindow.DrawText(10, 60, mdamage)
    yuusyaHP = yuusyaHP - mdamage
    If yuusyaHP <= 0 Then
      GraphicsWindow.Clear()
      GraphicsWindow.BrushColor = "black"
      GraphicsWindow.FontSize = 20
      GraphicsWindow.DrawText(80, 80, "魔王の勝ち!")
    Else
      GraphicsWindow.BrushColor = "white"
      GraphicsWindow.FillRectangle(190, 10, 40, 20)
      GraphicsWindow.BrushColor = "black"
      GraphicsWindow.DrawText(190, 10, yuusyaHP)
    EndIf
  EndIf
  
  If 91 <= maoukoudou And maoukoudou <= 100 Then
    GraphicsWindow.BrushColor = "white"
    GraphicsWindow.FillRectangle(0, 30, 500, 500)
    GraphicsWindow.BrushColor = "black"
    GraphicsWindow.DrawText(10, 40, "魔王は様子を見ている。")
    GraphicsWindow.BrushColor = "white"
    GraphicsWindow.FillRectangle(190, 10, 40, 20)
    GraphicsWindow.BrushColor = "black"
    GraphicsWindow.DrawText(190, 10, yuusyaHP)
  EndIf
EndSub

新たに、
yuusyaHP = 20000
で、勇者の初期HPを20000として、右上で常に表示されるようにしました。
また、IfElse構文を使い、「勇者のHPが0以下なら全てのボタンや文章を削除した後に『魔王の勝ち!』と表示して、それ以外では勇者の残りHPを表示」というプログラムを追加しています。
これを実行して、「魔王の攻撃」ボタンを連打すると、勇者のHPがひたすら減り続け、最終的に『魔王の勝ち!』と表示され、「魔王の攻撃」ボタンも消去されるためにゲーム終了となります。

rpg

rpg

……これじゃ「ずっと魔王のターン!」状態です。w
ということで、次回は勇者の攻撃ターンを考えてみます。

また、これで魔王の行動部分のみですから、勇者の行動を書き加えると長いプログラムになりそうです。
適宜、コメント文で、これが何の行動だと説明を入れていく方が良いでしょう。

次:その2 勇者に行動させよう


▲TOPへ戻る