トップページ > 過去ログ > 記事閲覧
ターン制ゲームについて
名前:獅子 日時: 2011/08/13 23:26

ターン制(厳密には若干違いますが)のゲームを作ろうと思い以下のようなコードを書きました。 (関係ない場所は省略しました //以下バトルモードのプログラム extern int money; extern int clear; extern int miss; void BATTLE() //戦闘モードクラス { #define START 0 #define JUGHGE 1 #define MY_TURN 2 #define ENEMY_TURN 3 const int DIREY_ATK = 3000; const int DIREY_ITEM = 2000; const int DIREY_SCF = 3500; int CheckHitKey( int KeyCode ); int Turn; int Hero; int Ats[2]; int Cr; HeroModel hero; hero.hp = 10000;//主人公体力 hero.str = 1300;//攻撃力 hero.ats = 1000;//アーツ(魔法攻撃力) hero.def = 2200;//防御力 hero.atd = 2000;//アーツ防御力 hero.sp = 200;//スピード hero.direy = 0;//ディレイ EnemyModel enemy; enemy.hp = 11000;//敵体力 enemy.str = 300;//攻撃力 enemy.ats = 1000;//アーツ enemy.def = 2100;//防御力 enemy.fad = 200;//火耐性 enemy.aad = 100;//水耐性 enemy.ead = 50;//風耐性 enemy.tad = 500;//地耐性 enemy.atd = 1000;//アーツ防御力 enemy.sp = 180;//スピード enemy.direy = 0;//ディレイ Turn = START; Hero = 0; //0=通常 1=アーツ駆動状態 Ats[0] = 0;//クリムゾンレイ(攻撃アーツ Ats[1] = 0;//ティアラ(回復アーツ while( ProcessMessage() == 0 ) { // 画面を初期化(真っ黒にする) ClearDrawScreen() ; // もしもZキーが押されていたらSクラフト発動 if( CheckHitKey( KEY_INPUT_Z ) ){ // 画面に描かれているものを一回全部消す ClsDrawScreen(); DrawString( 250 , 220 - 32 , "必殺技発動!" ,GetColor(255,0,0)); hero.direy += DIREY_SCF / hero.sp; //ディレイ算出 int dm_a,dm_b,dm_c,dm; int iryoku; iryoku = 700; dm_a = hero.str * ( iryoku / 100 ); //攻撃値を求める dm_b = ( dm_a * 5 - enemy.def * 2.5) / 2; //基本ダメージ if( dm_b < 0 ){ //基本ダメージがマイナスの場合ダメージを0に dm_b = 0; } dm_c = ( dm_b ) / 15; //ランダム値 dm = dm_b + dm_c; //最終ダメージ enemy.hp -= dm; if( enemy.hp < 0){ //残りHPが0以下になったら0に修正 enemy.hp = 0; } DrawFormatString( 250, 240 - 32, Cr, "敵に %5d のダメージ!!", dm); DrawFormatString( 250, 260 - 32, Cr, "敵の残りHP %5d", enemy.hp); if( enemy.hp > 0 ){ Turn = JUGHGE; } else { DrawString( 250 , 280 - 32 , "敵を倒した!!!" , Cr ); money += 100; clear++; WaitKey() ; return; } WaitKey(); break; } switch(Turn) { case START : //戦闘開始処理 DrawString(260,100,"敵が現れた!",GetColor(255,0,0)) ;//戦闘開始時のメッセージの表示など if(hero.sp >= enemy.sp) { Turn = MY_TURN; } else { Turn = ENEMY_TURN; } WaitKey() ; // キーの入力待ち(『WaitKey』を使用) break ; case JUGHGE: if(hero.direy <= enemy.direy) { Turn = MY_TURN; } else { Turn = ENEMY_TURN; } break; case MY_TURN: if( Hero == 0){ // 白色の値を取得 Cr = GetColor( 255 , 255 , 255 ) ; // 文字列の描画 DrawString( 250 , 240 - 32 , "主人公のターン!!" , Cr ); DrawString( 50 , 100 - 32 , "A:攻撃 S:逃げる D:回復アイテム F:アーツ" , Cr ); WaitKey(); if( CheckHitKey (KEY_INPUT_S) == 1 ){ // 画面に描かれているものを一回全部消す ClsDrawScreen(); DrawString( 250 , 220 - 32 , "にげます。" , Cr ); miss++; WaitKey() ; // キーの入力待ち(『WaitKey』を使用) return; } if( CheckHitKey (KEY_INPUT_A) == 1 ){ // 画面に描かれているものを一回全部消す ClsDrawScreen(); DrawString( 250 , 220 - 32 , "主人公の攻撃!" , Cr ); hero.direy += DIREY_ATK / hero.sp; //ディレイ算出 int dm_a,dm_b,dm_c,dm; int iryoku; iryoku = 100; dm_a = hero.str * ( iryoku / 100 ); //攻撃値を求める dm_b = ( dm_a * 5 - enemy.def * 2.5) / 2; //基本ダメージ if( dm_b < 0 ){ //基本ダメージがマイナスの場合ダメージを0に dm_b = 0; } dm_c = ( dm_b ) / 15; //ランダム値 dm = dm_b + dm_c; //最終ダメージ enemy.hp -= dm; if( enemy.hp < 0){ //残りHPが0以下になったら0に修正 enemy.hp = 0; } DrawFormatString( 250, 240 - 32, Cr, "敵の残りHP %d", enemy.hp); if( enemy.hp > 0 ){ Turn = JUGHGE; } else { DrawString( 250 , 260 - 32 , "敵を倒した!!!" , Cr ); money += 100; clear++; WaitKey() ; return; } WaitKey() ; // キーの入力待ち(『WaitKey』を使用) break; } if( CheckHitKey (KEY_INPUT_F) == 1 ){ // 画面に描かれているものを一回全部消す ClsDrawScreen(); DrawString( 250 , 220 - 32 , "K:クリムゾンレイ T:ティアラ" , Cr ); WaitKey() ; // キーの入力待ち(『WaitKey』を使用) if( CheckHitKey (KEY_INPUT_K) == 1 ){ DrawString( 250 , 240 - 32 , "アーツ駆動…" , Cr ); hero.direy += 3500 / hero.sp; //ディレイ算出 Turn = JUGHGE; Hero = 1; //アーツ遷移 Ats[0] = 1; } if( CheckHitKey (KEY_INPUT_T) == 1 ){ DrawString( 250 , 240 - 32 , "アーツ駆動…" , Cr ); hero.direy += 1000 / hero.sp; //ディレイ算出 Turn = JUGHGE; Hero = 1; //アーツ遷移 Ats[1] = 1; } WaitKey() ; // キーの入力待ち(『WaitKey』を使用) break; } if( CheckHitKey (KEY_INPUT_D) == 1 ){ // 画面に描かれているものを一回全部消す ClsDrawScreen(); DrawString( 250 , 220 - 32 , "回復アイテム!!" , Cr ); hero.direy += DIREY_ITEM / hero.sp; hero.hp += 500; DrawFormatString( 250, 240 - 32, Cr, "残りHP %d", hero.hp ); Turn = JUGHGE; WaitKey() ; // キーの入力待ち(『WaitKey』を使用) break; } DrawString( 250 , 260 - 32 , "ターン終了" , Cr ); WaitKey() ; // キーの入力待ち(『WaitKey』を使用) break; } else{//アーツ駆動状態の場合 if( Ats[0] == 1){ DrawString( 250 , 220 - 32 , "アーツ発動「クリムゾンレイ」" , Cr ); // 画面に描かれているものを一回全部消す ClsDrawScreen(); hero.direy += 1500 / hero.sp; //ディレイ(硬直時間 int dm_a,dm_b,dm_c,dm; int iryoku; iryoku = 800; dm_a = hero.ats * ( enemy.fad / 100 ) * ( iryoku / 100 );//攻撃値を求める dm_b = ( dm_a * 5 - enemy.atd * 2.5) / 2; //基本ダメージ if( dm_b < 0 ){ //基本ダメージがマイナスの場合ダメージを0に dm_b = 0; } dm_c = ( dm_b ) / 15; //ランダム値 dm = dm_b + dm_c; //最終ダメージ enemy.hp -= dm; if( enemy.hp < 0){ //残りHPが0以下になったら0に修正 enemy.hp = 0; } DrawFormatString( 250, 220 - 32, Cr, "%d のダメージ!!", dm); DrawFormatString( 250, 240 - 32, Cr, "敵の残りHP %d", enemy.hp); if( enemy.hp > 0 ){ Turn = JUGHGE; Hero = 0; Ats[0] = 0; } else { DrawString( 250 , 260 - 32 , "敵を倒した!!!" , Cr ); money += 100; clear++; WaitKey() ; return; } WaitKey() ; // キーの入力待ち(『WaitKey』を使用) break; } if( Ats[1] == 1 ){ DrawString( 250 , 220 - 32 , "アーツ発動「ティアラ」" , Cr ); // 画面に描かれているものを一回全部消す ClsDrawScreen(); hero.direy += 1000 / hero.sp; //ディレイ(硬直時間 hero.hp += 2000; DrawString( 250 , 220 - 32 , "HP回復" , Cr ); DrawFormatString( 250, 240 - 32, Cr, "HP %d", hero.hp); Hero = 0; Ats[1] = 0; WaitKey(); break; } } case ENEMY_TURN: ClsDrawScreen(); // 白色の値を取得 Cr = GetColor( 255 , 255 , 255 ) ; // 文字列の描画 DrawString( 250 , 240 - 32 , "敵のターン!!" , Cr ); ClsDrawScreen(); DrawString( 250 , 220 - 32 , "敵の攻撃!" , Cr ); enemy.direy += DIREY_ATK / enemy.sp; int dm_a,dm_b,dm_c,dm; int iryoku; iryoku = 100; dm_a = hero.str * ( iryoku / 100 ); //攻撃値を求める dm_b = ( dm_a * 5 - hero.def * 2.5) / 2; //基本ダメージ if( dm_b < 0 ){ //基本ダメージがマイナスの場合ダメージを0に dm_b = 0; } dm_c = ( dm_b ) / 15; //ランダム値 dm = dm_b + dm_c; //最終ダメージ hero.hp -= dm; DrawFormatString( 250, 240 - 32, Cr, "自分の残りHP %d", hero.hp ); if( hero.hp > 0){ Turn = JUGHGE; } else { DrawString( 250, 260 - 32 , "力尽きた…" , Cr); money -= 50; miss ++; WaitKey(); return; } DrawString( 250 , 260 - 32 , "ターン終了" , Cr ); WaitKey() ; // キーの入力待ち(『WaitKey』を使用) break; } } // Windows 特有の面倒な処理をDXライブラリにやらせる -1 が返ってきたらループを抜ける if( ProcessMessage() < 0 ) return ; // もしESCキーが押されていたらループから抜ける if( CheckHitKey( KEY_INPUT_ESCAPE ) ) return ; return; } //ここまで このプログラム自体は問題無く動きました(うえの状態だと見た目に難がありますがw) しかし、見ての通り1対1にしか対応できないんです。 私は初心者なので行き詰ってしまいました。どうすればいいのでしょうか?プログラムを全て書き直す羽目になってもかまいません。 複数の敵、複数の味方を戦わせるにはどうすればいいのか、アドバイスだけでも頂けるとありがたいです。 (とくに分からない点は、複数のキャラの戦闘順をどう処理したらいいのか) *一応環境* VisualC++2010 ExpressEdition *システムについて* このゲームの戦闘順ですが念のため説明しときます。念のため。 まず最初は自分も敵もディレイは”0”で、スピードで行動順を決めます。 その後、起こす行動によって”ディレイ値(ディレイ÷スピードで算出)”を加算していきます。(強力な技やアーツはディレイが高く、アイテム使用などはディレイが低い)。 このとき、ディレイ値の低い者から行動します。 (ちなみにこれもコードを見れば分かりますが、アーツは発動するまでにもディレイがあります。  アーツ駆動→主人公アーツ使用状態に遷移→駆動までのディレイ→発動→ダメージ計算等→主人公通常モード遷移→アーツ使用後の硬直時間ディレイ)

Page: 1 |

Re: ターン制ゲームについて ( No.1 )
名前:いっち 日時:2011/08/14 01:39

ここまできたら、ごり押しでもいけそうな気がしますが・・・。 とりあえず、HeroModel と EnemyModel を合成した構造体を作って、 その構造体の配列にすべてのキャラの情報を入れるようにしてみてはどうでしょうか? 例えば以下のような感じで・・・。 struct CharactorStatus { int type;//キャラクタのタイプ(味方?敵?) int hp;//体力 int str;//攻撃力 int ats;//アーツ(魔法攻撃力) int def;//防御力 int atd;//アーツ防御力 int fad;//火耐性 int aad;//水耐性 int ead;//風耐性 int tad;//地耐性 int sp;//スピード int direy;//ディレイ }; CharactorStatus[12] = { //type,hp ,str ,ats ,def ,atd ,fad,aad,ead,tad,sp ,direy { 0,10000,1300,1000,2200,2000, 0, 0, 0, 0,200, 0}, { 1,11000, 300,1000,2100,2000,200,100, 50,500,180, 0}, { 1, 5000, 500, 500,1000,1000, 0, 0, 0, 0, 0, 0}, // 以下続く };
Re: ターン制ゲームに ( No.2 )
名前:獅子 日時:2011/08/14 02:06

なるほど、クラスでは無く構造体ならキャラを増やすのは簡単そうですね。敵と味方の判別も簡単になると…。 すぐに書き換えようと思います、ありがとうございます! ただ、もうひとつ 最初の複数キャラの行動順の判別はソートでなんとかできそうですが、 以降のディレイ式の行動順もソートでどうにか判定できますかね? 私の分かる範疇じゃなくて…ソート以外でもいいので行動順の判定をどう処理したらいいか教えていただけませんか?
Re: ターン制ゲームについて ( No.3 )
名前:いっち 日時:2011/08/14 18:00

> クラスでは無く構造体ならキャラを増やすのは簡単そうですね。敵と味方の判別も簡単になると…。 仰る「クラス」というのが、RPGの職種的なクラスなのか、C++の機能としてのクラスなのか分かりかねるのですが、 C++の機能としてのクラスであれば、クラスと構造体はほぼ同じことなので少し誤解があるかもしれません。 > 最初の複数キャラの行動順の判別はソートでなんとかできそうですが、以降のディレイ式の行動順もソートでどうにか判定できますかね? ソースを詳しく拝見していないので、ディレイがどういったものかとか、行動順の判定方法など分かっていないのですが、 あるキャラが行動をすると、連続して同じキャラが行動したり、別のキャラの行動順に割り込んだりすることがあるということでしたら、 誰かが行動するたびにソートと行動順序の判定をやり直せばうまくいくのではないでしょうか。
Re: ターン制ゲームに ( No.4 )
名前:獅子 日時:2011/08/15 01:11

クラスと構造体がC++ではほぼ同じ意味を持つことは一応知ってはいます。が、初心者ゆえにまだ良く分からない点も多くて… ちなみに、構造体なら簡単に云々は、構造体の配列の初期化がクラス(の私の知っている範疇の使い方)よりも簡単に出来そうだと思ったという意味です わかりにくくてすいません… >誰かが行動する度にソートと行動順序の判定をやり直せば なるほど…やってみます。ありがとうございます!
Re: ターン制ゲームについて ( No.5 )
名前:ゆう 日時:2011/09/01 13:06

基本的には、アクセス権の初期値の違いしかなかったような。 structはpublic、classはprivateがアクセス権の基本設定です。 変更するには、 class Test { private: int a; int b; public: Test(); ~Test(); int c; int d; }; のようにします。 (コンストラクタとデストラクタは「public:」の下に記述してくださいね。) 定義の方法はそんなに難しくなくて、いっちさんと(おおよそ)同じように書くのであれば、以下のように記述します。 class CharactorStatus { int type;//キャラクタのタイプ(味方?敵?) int hp;//体力 int str;//攻撃力 //...(続く) public: // 一つ目のやり方(変数のメモリの確保時の初期値を指定する方法で、こちらの方がほんの少し高速です。) CharactorStatus( int type,//キャラクタのタイプ(味方?敵?) int hp,//体力 int str//攻撃力 //...(続く場合は上にカンマを忘れないように) ): type(type), hp(hp), str(str) //...(続く場合は上にカンマを忘れないように) { // コンストラクタの中身 } // 二つ目のやり方 CharactorStatus( int type,//キャラクタのタイプ(味方?敵?) int hp,//体力 int str//攻撃力 //...(続く場合は上にカンマを忘れないように) ){ // 初期値代入 this.type = type; this.hp = hp; this.str = str; //...(続く) // コンストラクタの中身 } }; CharacterStatus *characterStatus[12]; characterStatus[0] = new CharacterStatus(0,10000,1300);// 増やす場合はカンマ区切りで増やしてください characterStatus[1] = new CharacterStatus(1,11000, 300);// 増やす場合はカンマ区切りで増やしてください characterStatus[2] = new CharacterStatus(1, 5000, 500);// 増やす場合はカンマ区切りで増やしてください ちなみにこの場合、いっちさんの場合と同じく、各データ(メンバ)にアクセスする際は、 「characterStatus[0].type」とドット演算子でも問題ないですが、 配列にしない場合は「characterStatus->type」のようにアロー演算子を用いなくてはならない場合があります。 もしVisualStudioを使っている場合は、入力補助があるので、その都度試しながら覚えてください。 最後になりましたが、上のソースはたったいまテキストで打ち込んだだけなので、誤字があるかもしれませんが、そのときはご容赦ください。
Re: ターン制ゲームに ( No.6 )
名前:獅子 日時:2011/09/02 09:46

なるほど、じゃあクラスでもpublicなら構造体と基本的には変わらないという事ですか 解説ありがとうございます<(_ _)>

Page: 1 |