シェルスクリプトでRPG風ゲームを作ってみる【前編】

だしまき
2025-04-21
2025-04-21

はじめに

寒暖差に情緒を破壊されております。

どうもだしまきです。

シェルスクリプト、皆さんは使われてますでしょうか。
私はフューチャースピリッツに入社するまでシェルスクリプトを使ったことがほぼ無く、
現在は業務の中で頻繁に使う機会があるので、理解を深めている最中です。

ということで今回はシェルスクリプトを使って、
RPG風ゲームを作ってみたいと思います。


RPGを作ってみよう

早速作っていきましょう、環境はLinuxを使います。

RPGを作ってみました

こちらが出来上がりの物になります。

#!/bin/bash

# プレイヤーのステータス
player_hp=100
player_max_hp=100

# 敵のステータス
enemy_hp=100

echo "========================"
echo "=== バトルスタート! ==="
echo "========================"

while [ $player_hp -gt 0 ]; do
  echo
  echo "あなたのHP: $player_hp / $player_max_hp "
  echo "モンスターのHP: $enemy_hp"
  echo "1: 攻撃  2: 回復"
  read -p "→ 行動を選んでください: " action

  if [ "$action" = "1" ]; then
    damage=$((RANDOM % 41))  # 0〜40のダメージ
    echo "あなたの攻撃!モンスターに $damage ダメージ!"
    enemy_hp=$((enemy_hp - damage))
  elif [ "$action" = "2" ]; then
    heal=$((RANDOM % 31 + 10))  # 10〜40HPを回復
    player_hp=$((player_hp + heal))
    [ "$player_hp" -gt "$player_max_hp" ] && player_hp=$player_max_hp
    echo "あなたは $heal 回復した!"
  else
    echo "無効な入力"
    continue
  fi

  # モンスターが倒された際の処理
  if [ $enemy_hp -le 0 ]; then
    echo "モンスターを倒した!"
    enemy_hp=$((RANDOM % 50 + 100))  # 新しい敵
    echo "新たなモンスターが現れた!(HP: $enemy_hp)"
    continue
  fi

  # 敵の攻撃ターン
  enemy_damage=$((RANDOM % 31))  # 0〜30のダメージ
  echo "敵の攻撃!あなたに $enemy_damage ダメージ!"
  player_hp=$((player_hp - enemy_damage))

  if [ $player_hp -le 0 ]; then
    echo "あなたは倒れた… ゲームオーバー"
    break
  fi
done

3分クッキングも驚きの早さです、というのも振り返りの意味も込めて解説を書くと
長すぎて前後編になりそうなので、出来上がりを書いた後2回に分けて解説を書こうと思った次第です・・・

解説(前編)

それでは振り返っていきたいと思います。
まずはコマンドラインにてシェルファイル(rpg.sh)を作ります。

$ vi rpg.sh

シェルファイルが作れたら早速コードを書いていきましょう。
まずは1行目にシェバン行を記述します。

#!/bin/bash

シェバン行はどのプログラムでファイルを実行するのかを指定できるもので、
#! の後に /bin/bash を付けてこのスクリプトは /bin/bash で実行してねと伝えています。

次にプレイヤーのHPとプレイヤーの最大HP、敵のHPを設定します。(今回はプレイヤーも敵も100)

# プレイヤーのステータス
player_hp=100
player_max_hp=100

# 敵のステータス
enemy_hp=100

HPの設定が出来たら、バトル開始の合図を出して

echo "======================="
echo "==== バトルスタート! ===="
echo "=======================""= バトルスタート! ==="

メインの処理を書いて行きます。
戦闘が終わるまでプレイヤーのターンと敵のターンを繰り返すので、
while文を使って無限ループさせます。

while [ $player_hp -gt 0 ]; do

とはいえプレイヤーのHPが0になっているにも関わらず戦い続けるゾンビ状態は嫌なので、
$player_hp -gt 0 を記述します。
-gt(greater than)はシェルスクリプトで使われる比較演算子で、AよりBが大きいかを判定します。
ここではプレイヤーのHPが0より大きい(1以上)かどうかを判断して、
繰り返し続けるという事になります。
最初 -gt が〇〇以上の意味だと思っていたのですが、
〇〇以上は -ge (greater than or equal to)という演算子を使うようです。ややこしや・・・

while文が書けたら、まずプレイヤーの行動処理から記述します。

  echo
  echo "あなたのHP: $player_hp / $player_max_hp "
  echo "モンスターのHP: $enemy_hp"
  echo "1: 攻撃  2: 回復"
  read -p "→ 行動を選んでください: " action

最初のechoで見やすいように1行空白を開けて、
現在のプレイヤーのHP/プレイヤーの最大HP(100)表示。
その下に敵の現在HPを表示し、攻撃と回復の選択肢を表示。
最後の【read -p "→ 行動を選んでください: " action】は、
readがユーザーからの入力を受け取るコマンドで、
-pオプションで【→行動を選んでください:】の文を表示し、
ユーザーに何をして欲しいかを伝えます。
最後に、ユーザーが入力したものをactionという変数に保存します。

ここから先ほどの入力内容によって処理を分岐させます。

  if [ "$action" = "1" ]; then
    damage=$((RANDOM % 41))  # 0〜40のダメージ
    echo "あなたの攻撃!モンスターに $damage ダメージ!"
    enemy_hp=$((enemy_hp - damage))
  elif [ "$action" = "2" ]; then
    heal=$((RANDOM % 31 + 10))  # 10〜40HPを回復
    player_hp=$((player_hp + heal))
    [ "$player_hp" -gt "$player_max_hp" ] && player_hp=$player_max_hp
    echo "あなたは $heal 回復した!"
  #1or2以外の選択肢が選ばれた場合
  else
    echo "無効な入力"
    continue
  fi

まず先程の入力内容が「1」の攻撃だった場合は、
敵にランダムに0~40のダメージを与え、与えたダメージ分現在の敵のHPを減らす処理を行っています。
次に入力内容が「2」の回復だった場合は、
プレイヤーのHPを10~40ランダムに回復し、回復した分プレイヤーのHPを増やす処理を行っています。

RANDOMは、Bashに最初からあるランダムな整数を返す変数で、
今回の攻撃のように((RANDOM % 41))と指定すると41で割った余りを出してくれる。
そのためダメージは0~40の中からランダムに選ばれるようになっています。
回復を選択した場合は((RANDOM % 31 + 10))と指定しているので、
31で割った余りの0~30の中からランダムに選ばれた数値に10を足した数値を回復するように指定しています。
ですが、ただ単に増やすだけだと無限にHPが回復してしまうので・・・


    [ "$player_hp" -gt "$player_max_hp" ] && player_hp=$player_max_hp

上記の処理を入れています。
[ "$player_hp" -gt "$player_max_hp" ]は先程も使った -gt で、
ここでは、プレイヤーHPが最大HPより大きいかを見ています。
その後の && は前の条件が真(true)であれば、後ろの処理を実行する意味があります。
なのでここでは、プレイヤーHPが最大HPより大きければプレイヤーHPを最大HP(100)に戻すという処理にしています。
これで回復連打で上限を超えて無限にHPが増えることを防げました。

  #1or2以外の選択肢が選ばれた場合
  else
    echo "無効な入力"
    continue
  fi

最後に1の攻撃か2の回復以外を選んだ場合は、無効な入力というメッセージを返して
ループの最初に戻るように設定しています。
continueがループの最初に戻す役割を果たしてくれます。

これでプレイヤー側の行動パターンはOKです!

この後、敵側の行動とプレイヤーor敵のどちらかが倒された時の処理が必要ですが、
長くなりそうなので今回はここまでにしておきます!
後編でお会いしましょうーそれでは!

 

......

先にちょっと遊んでみた・・・


想定していた処理になりました!