Aggressive Style 5

Aggressive Style 5

昨今はコミケ関係を中心に書いています。同人やニコニコ動画方面で活躍される方の相互リンクをお待ちしています。

過去に作った「RPGの戦闘プログラム」を書き直してみた(リファクタリング)

2010年頃に書いた「とりあえずRPGの戦闘システムをC言語で作ってみた」の方が一定の評価を得ている模様。その当時の記事を読んでみると、いつかの西川口の風俗跡地をレビューした時の酷さが再現されていた。折角見て頂いたid:moge32さんやid:jy97さんに申し訳無く、その改良版をここに掲載する事にした。

リファクタリングについて

プログラムをする上で最初の内は何をして良いか分からず、同じ処理やネットのサンプルをコピペで使い回したりする事がある。後で変更と言う時に該当箇所を全部改修と言う事になって、時間がかかることがある。今回は使い回している部分を切り分けたり、順序を整理するなどして色々と改善してみた。一旦完成したプログラムを細かく切り分けたりすると、新規機能が追加しやすくなる場合があるのでぜひお試しあれ。

このようにコンピュータプログラミングにおいて、プログラムの外部から見た動作を変えずにソースコードの内部構造を整理することをリファクタリングと言うそうだ。リファクタリングのやり方を知りたい場合は、「リファクタリング―プログラムの体質改善テクニック」を読んで見ると言いかも知れない。自分は当てはまる経験が良く書いてあったので、これは買いだと思って買ってしまった。Javaをある程度覚えたら改めて読み返してみたい限りだ。

リファクタリング―プログラムの体質改善テクニック (Object Technology Series)

リファクタリング―プログラムの体質改善テクニック (Object Technology Series)

  • 作者: マーチンファウラー,Martin Fowler,児玉公信,平澤章,友野晶夫,梅沢真史
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2000/05
  • メディア: 単行本
  • 購入: 94人 クリック: 3,091回
  • この商品を含むブログ (310件) を見る

そんなこんなでソースコードの改善を是非見て欲しい。ソースコードのgistはgist:5795884となる。

プログラムの概要

  1. 味方と敵で1対1の戦い。
  2. 味方は「攻撃」と「防御」しかできない。(逃げることもできない)
  3. 敵は乱数で「攻撃」「防御」を決めて来る
  4. 素早さの概念を追加(分かりやすさの為先攻のキャラを表示)

各変数関数の仕様

  1. 構造体character:キャラクターのHP,攻撃力,防御力をひとまとめにしたもの
  2. 関数set_parameter:キャラクターのパラメーター設定部分。Javaで言うコンストラクタのようなものだが、C言語の概念には無いので参照渡しで代用
  3. 関数strdef:ダメージの計算部分。単純に味方の攻撃力と相手の防御力の差をダメージとして算出
  4. 関数attack:キャラの状態に応じたダメージを計算している部分。
  5. [新]関数attackofcharacter:どちらかのキャラクターが攻撃する一連の流れ
  6. [新]関数firstattacker:素早さの値が大きい方を先に攻撃を行う
  7. 関数isdead:キャラが死んだかどうかの判定部分。
  8. 関数main:戦闘の流れを書いた部分。

ソースコード


#include
#include
/*2013.6.17 攻撃ないしは防御時のロジックが変な状況です*/
/*味方キャラクター及び敵キャラクターの構造体*/
typedef struct
{
int hp;//体力
int str;//攻撃力
int def;//防御力
int speed;//素早さ
int state;//コマンド状態
}character;

//パラメーターの設定(Javaで言うコンストラクタのようなもの)
void set_parameter(character* param,int hp,int str,int def,int speed,int state)
{
param->hp = hp;
param->str = str;
param->def = def;
param->speed = speed;
param->state = 0;
}

//攻撃力と防御力の定義
//自分の攻撃力< 敵の防御力のときダメージは0
//自分の攻撃力< 敵の防御力のときは自分の攻撃力-防御力を相手に与える
int strdef(int player_str,int enemy_def)
{
if(player_str < enemy_def)
{
return 0;
}
else
{
return(player_str - enemy_def);
}
}

//攻撃時のアクション
void attack(character* player,character* enemy){
//通常状態
//テスト用のコード
//printf("%d\n",strdef(player->str,enemy->def));
if(player->state == 0)
{
enemy->hp -= strdef(player->str,enemy->def);
}else
{
//防御状態
enemy->hp -= strdef(player->str,(enemy->def*2));
}
}

//攻撃時の処理の流れ
void attackofcharacter(character* attacker,character* defender,int command)
{
//自分が攻撃時の対応
if(command % 2 == 0)
{
attacker->state = 0;//必要かどうか不明
//攻撃
attack(attacker,defender);
}

//自分が防御時の対応
if(command % 2 == 1)
{
attacker->state = 1;//必要かどうか不明
}
}

//素早さに応じて先攻後攻を決める
void firstattacker(character* attacker,character* defender,int command)
{
//自分の素早さ > 相手の素早さのとき
if(attacker->speed > defender->speed)
{
printf("自分の先攻\n");
attackofcharacter(attacker,defender,command);
attackofcharacter(defender,attacker,rand());
}
else
{
printf("相手の先攻\n");
attackofcharacter(defender,attacker,rand());
attackofcharacter(attacker,defender,command);
}
}

//死亡かどうかの判定
int isdead(int hp)
{
if(hp < 1)
{
return 1;
}
else
{
return 0;
}
}

//死亡時点のメッセージの表示
void isdeadmessage(character player,character enemy)
{
//死亡判定(味方)
if(isdead(player.hp) == 1)
{
printf("you are dead\n");
}

//死亡判定(敵側)
if(isdead(enemy.hp) == 1)
{
printf("you win\n");
}
}

int main()
{
character player;
character enemy;
int command = 0;

//初期ステータスの入力
set_parameter(&player,100,30,15,10,0);
set_parameter(&enemy,100,30,15,20,0);

//一応味方先制
//最初は無限ループを書き、終了条件を先に記述
while(1)
{

//終了時の処理や条件を先に記述
if(isdead(player.hp) == 1 || isdead(enemy.hp) == 1)
{
isdeadmessage(player,enemy);
break;
}

printf("現在の味方のHP:%d,現在の敵のHP:%d\n",player.hp,enemy.hp);
printf("攻撃or防御?");
scanf("%d",&command);

firstattacker(&player,&enemy,command);
}
return 1;
}

実行結果

実行結果は相手は先攻の場合、上手く数値が加減算されてゲームが終了するかを確かめた。すると味方のHPが0になってゲームが終了したので無事に動作している。