Kuina-chan

くいなちゃん2018年12月11日


6さいからのプログラミング」、今回はC言語でRPGを作ります!

1RPG

題材にするのは、RPG(ロールプレイングゲーム)です。 とはいえテキストだけのRPGで、しかもラスボス戦のみとなります(図1-1)。
テキストRPG
図1-1: テキストRPG
勇者「Kuina」がラスボス「Demon」に挑むストーリーです。 「0」を入力すると攻撃し、「1」で力を溜めて攻撃力アップ(戦闘が終わるまで持続します)、「2」で回復です。
なぜ今回RPGを題材にしたかと言いますと、プログラムの流れがシンプルで解りやすく改造もしやすいため、プログラミングの学習に適していると考えたからです。
少し長いですが、ソースコードは図1-2の通りです。
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. struct param
  5. {
  6.   char name[8];
  7.   int life, attack, defense;
  8. };
  9.  
  10. void act(struct param* actor, struct param* target, int command)
  11. {
  12.   int point;
  13.   switch (command)
  14.   {
  15.     case 0:
  16.       point = actor->attack - target->defense;
  17.       target->life -= point;
  18.       printf("%s attacks! %s takes %d damage points!\n", actor->name, target->name, point);
  19.       break;
  20.     case 1:
  21.       point = 20;
  22.       actor->attack += point;
  23.       printf("%s casts Boost! %s's Attack increases by %d!\n", actor->name, actor->name, point);
  24.       break;
  25.     case 2:
  26.       point = 50;
  27.       actor->life += point;
  28.       printf("%s casts Heal! %s's Life increases by %d!\n", actor->name, actor->name, point);
  29.       break;
  30.   }
  31. }
  32.  
  33. int main(void)
  34. {
  35.   struct param you = { "Kuina", 100, 100, 100 };
  36.   struct param enemy = { "Demon", 1000, 100, 50 };
  37.   printf("%s appears!\n", enemy.name);
  38.   for (; ; )
  39.   {
  40.     int command;
  41.     printf("%s: Life=%d, Attack=%d, Defense=%d\n", you.name, you.life, you.attack, you.defense);
  42.     printf("%s: Life=%d, Attack=%d, Defense=%d\n", enemy.name, enemy.life, enemy.attack, enemy.defense);
  43.     printf("(0) Attack\n(1) Boost\n(2) Heal\n");
  44.     printf("Command:");
  45.     scanf("%d", &command);
  46.     act(&you, &enemy, command);
  47.     if (enemy.life <= 0)
  48.     {
  49.       printf("%s is defeated!\n", enemy.name);
  50.       return 0;
  51.     }
  52.     act(&enemy, &you, rand() % 3);
  53.     if (you.life <= 0)
  54.     {
  55.       printf("%s has been killed...\n", you.name);
  56.       return 0;
  57.     }
  58.   }
  59. }
図1-2: rpg.c
このソースコードは大まかには、4~8行目の構造体「struct param」と、10~31行目の関数「act」と、33~59行目の関数「main」から成ります。

2struct param

4~8行目の「struct param」は、味方と敵のパラメータを管理する構造体となっています。 メンバのnameはキャラクターの名前、lifeはライフ、attackは攻撃力、defenseは守備力です。
このstruct param型の変数として、関数mainの開始直後の35~36行目で、味方「you」と敵「enemy」を作成しています。 各メンバには列挙した値が順番に代入されるので、例えばenemyのメンバは、nameが"Demon"、lifeが1000、attackが100、defenseが50となります。

3メインループ

その直後、38~58行目では、for文により半永久的に処理が繰り返されます。 ゲームのプログラムでは、ゲームオーバーになるまでこのように同じ処理を繰り返すことが多く、この繰り返しのことは「メインループ」と呼ばれます。
今回のプログラムでは、47~51行目で敵のライフが0以下になれば勝利とし、53~57行目で味方のライフが0以下になれば負けとし、そのどちらでもなければメインループを回り続ける流れとなっています。
メインループの中では、45行目でまずプレイヤーからの入力を受け取って46行目のact関数で味方側の行動を行い、52行目のact関数で敵側の行動を行います。

4act関数

味方や敵の行動を行うact関数は、10~31行目に書かれています。 関数の引数は「actor」「target」「command」ですが、それぞれ「行動するキャラ」「行動の対象となるキャラ」「行動の種類」です。
13行目のswitch文で、行動の種類であるcommandによって処理を分けます。 0なら攻撃、1なら力溜め、2なら回復を行います。

4.1攻撃



攻撃の処理は15~19行目です。 16行目で攻撃によって与えるダメージを計算し、変数pointに入れます。 ダメージの計算方法は、行動するキャラ「actor」の攻撃力「attack」から、行動の対象となるキャラ「target」の守備力「defense」を引いた値となっています。
17行目で対象者「target」のライフ「life」から、ダメージであるpointの値を減らし、その状況を18行目で画面に出力しています。

4.2力溜め



力溜めは、単純に攻撃力を上げるだけの処理で、20~24行目です。 変数pointに20を入れ、その値を22行目で行動者「actor」の攻撃力「attack」に加算しています。

4.3回復



回復は、単純にライフを増やすだけの処理で、25~29行目です。 通常のRPGのライフには最大値があり、それ以上の回復はできないようになっていますが、このプログラムでは省略しています。 つまり、いくらでも回復ができます。

5act呼び出し

さて、act関数を理解したところで、再度46行目と52行目の呼び出し側を見てみましょう。
46行目ではプレイヤーが入力した行動を味方に行わせるために、行動者actorには味方「you」を、対象者targetには敵「enemy」を、行動の種類commandにはプレイヤーが入力した値を入れてact関数を呼び出しています。
対して52行目では敵を行動させるために、行動者actorには敵「enemy」を、対象者targetには味方「you」を、行動の種類commandには「rand() % 3」という値を入れてact関数を呼び出しています。 「rand() % 3」とは、「0~2の乱数を生成する」という意味です。 これにより敵は、攻撃、力溜め、回復の行動をランダムに選んで行います。
補足すると、rand関数は「0~非常に大きい数」の整数の乱数を生成します。 これを3で割った余りを求めることで、「0~2」の範囲の乱数にしています。

6プログラムの改造

以上、流れとしては「プレイヤーの入力」→「味方の行動」→「敵の行動」→「プレイヤーの入力」→…を繰り返しているだけのプログラムです。 市販のゲームはこれより遙かに複雑に見えるかもしれませんが、やっていることはこのプログラムと大差ありません。
さて、このRPGを実際に実行してみると、敵があまりに強すぎてなかなか勝てないと思います。 そこで、このゲームをより面白くするために、プログラムを改造することを考えてみてください。 何をどう書き換えれば勝てるようになるでしょうか。 既存のプログラムを改造することは、プログラミングに慣れる重要な一歩となるでしょう。
1544536343jaf