RPGの戦闘について
RPGの戦闘について
現在、ターン制の戦闘のRPGを作っているんですが、
2対1や2対2などの戦闘になったときの順番に攻撃するプログラムの作り方がわかりません。
どうすればいいのでしょうか?○対○のすべてのパターンについて分けて考えなければいけないのでしょうか?
2対1や2対2などの戦闘になったときの順番に攻撃するプログラムの作り方がわかりません。
どうすればいいのでしょうか?○対○のすべてのパターンについて分けて考えなければいけないのでしょうか?
Re: RPGの戦闘について
敵や味方のキャラクタの情報をどのように管理しているかや、
攻撃をどのように実装しているかによると思います。
つまり、それだけの情報では答えられません。
攻撃をどのように実装しているかによると思います。
つまり、それだけの情報では答えられません。
Re: RPGの戦闘について
すいません、情報が少なすぎました・・・。
まず、主人公のデータは構造体、敵のデータは構造体配列で管理しています。
画面の切り替えはWinMain関数の中のswitchの変数によってマップ画面や、戦闘画面の関数を呼び出しています。
そして、マップ画面でGetRandを使い何分の一の確率でswitchの変数に戦闘画面の関数を呼び出す値を代入しています。また、その際、さらにGetRandを使いその値を戦闘画面の関数の引数で渡し、その引数と同じ配列番号の敵を出現させるようにしています。
戦闘画面の関数では、まず、敵のデータを初期化し、whileループの中でswitchを使いコマンド入力→(素早さが早い順に)戦闘エフェクトとダメージ計算→コマンド入力というような感じにしたいと思っています。
ここでわからないのが(素早さが早い順に)戦闘エフェクトとダメージ計算という部分です。敵によって素早さが違うし、敵の出現数もばらばらにしたいので、いろいろなパターンが出てきてしまうのでどうすればいいのかと・・・。
まず、主人公のデータは構造体、敵のデータは構造体配列で管理しています。
画面の切り替えはWinMain関数の中のswitchの変数によってマップ画面や、戦闘画面の関数を呼び出しています。
そして、マップ画面でGetRandを使い何分の一の確率でswitchの変数に戦闘画面の関数を呼び出す値を代入しています。また、その際、さらにGetRandを使いその値を戦闘画面の関数の引数で渡し、その引数と同じ配列番号の敵を出現させるようにしています。
戦闘画面の関数では、まず、敵のデータを初期化し、whileループの中でswitchを使いコマンド入力→(素早さが早い順に)戦闘エフェクトとダメージ計算→コマンド入力というような感じにしたいと思っています。
ここでわからないのが(素早さが早い順に)戦闘エフェクトとダメージ計算という部分です。敵によって素早さが違うし、敵の出現数もばらばらにしたいので、いろいろなパターンが出てきてしまうのでどうすればいいのかと・・・。
Re: RPGの戦闘について
データ構造が良くわからないのですが、こういった感じでしょうか?(ツクール風)
このような構造であれば、
戦闘関数内で敵のデータが入った配列を(この例だとtroop.list)
素早さで降順でソートして、先頭から順に戦闘をさせるという方法があります。
struct player{ //プレイヤーの単体データ
// HP,MP,etc..
};
struct enemy{ //敵の単体データ
// HP,MP,etc..
};
struct enemy_troop{ //敵グループのデータ
struct enemy list[10];
};
//戦闘関数内
struct player player_list[10]; //プレイヤーの配列
struct enemy_troop troop; //エンカウントした敵グループ
このような構造であれば、
戦闘関数内で敵のデータが入った配列を(この例だとtroop.list)
素早さで降順でソートして、先頭から順に戦闘をさせるという方法があります。
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 14年前
- 住所: 東海地方
- 連絡を取る:
Re: RPGの戦闘について
>ここでわからないのが(素早さが早い順に)戦闘エフェクトとダメージ計算という部分です。敵によって素早さが違うし、敵の出現数もばらばらにしたいので、いろいろなパターンが出てきてしまうのでどうすればいいのかと・・・。
ここだけの部分を取り上げるとソート方法が分からないと言う印象を受けますが違うのでしょうか?
ここだけの部分を取り上げるとソート方法が分からないと言う印象を受けますが違うのでしょうか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: RPGの戦闘について
もちろん、使えますよ。red さんが書きました: しかし、そのような方法は、敵の出現数が変化した場合も使えるんですか?
よほど特殊なデータ管理の方法をしていなければ。
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 14年前
- 住所: 東海地方
- 連絡を取る:
Re: RPGの戦闘について
ソートとは、ある値(この場合素早さ)の順番に並べ替えることです。
可変個数のソートはもちろん可能ですよ。
ゲームや様々なプログラムを組む場合は、アルゴリズムを知っていると楽が出来たのに!って事がたくさん出てきます。
参考
「アルゴリズムとデータ構造編 トップページ」
http://www.geocities.jp/ky_webid/algorithm/index.html
今回の場合、素早さをソートキーにして味方と敵の区分・味方と敵の番号を構造体にまとめて、その構造体配列をソートすれば行動順番を決めるテーブルが出来ますよ。
参考にテーブルの構造と宣言。ソートは自分で考えてみてください。
可変個数のソートはもちろん可能ですよ。
ゲームや様々なプログラムを組む場合は、アルゴリズムを知っていると楽が出来たのに!って事がたくさん出てきます。
参考
「アルゴリズムとデータ構造編 トップページ」
http://www.geocities.jp/ky_webid/algorithm/index.html
今回の場合、素早さをソートキーにして味方と敵の区分・味方と敵の番号を構造体にまとめて、その構造体配列をソートすれば行動順番を決めるテーブルが出来ますよ。
参考にテーブルの構造と宣言。ソートは自分で考えてみてください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
- MoNoQLoREATOR
- 記事: 284
- 登録日時: 14年前
- 住所: 東京
Re: RPGの戦闘について
まず方針として、
①各キャラクターにゲージを持たせ、ゲージの値を各々のすばやさで初期化しておきます。
②ゲージを1ずつ増やしていき、ゲージが一定数(今回の例なら100)を超えたら攻撃するようにします。
③全員が攻撃したら初期化します。
というようにします。
※同時の場合インデックス番号が早いほうが先になります。また、今回の例なら味方より敵の方が先になります。
~以下詳しい説明&重要な部分のソースコード~
敵の最大出現数を TEKI_MAX
とします。
それと、
struct KOUZOUTAI{
int being; //生きている場合1を、そうでない場合0を代入することとする
int subayasa; //すばやさを代入することとする
int gauge; //ゲージ(ゲージが一定数を超えると攻撃)
}party[PARTY_MAX], teki[TEKI_MAX];//変数宣言
を宣言しておきます。
あらかじめ
int party_kazu = パーティーの現在の人数;
for(int i=0;i<party_kazu;i++){
party.being = 1;
party.gauge = party.subayasa;
}
int teki_kazu = GetRand(TEKI_MAX-1)+1 //敵の数を決める
for(int i=0;i<teki_kazu;i++){
teki.being = 1;
teki.gauge = party.subayasa;
}
としておきます。
.attackの値の意味・・・ 0→未攻撃 1→攻撃中 2→攻撃済み
これを無限ループすればできるはずです。
なお、攻撃関数を呼んだとき、仲間や敵が死んだらそのbeingを0にしてください。
実際にプログラムを実行したりとかはしていません。コンパイルもしていません。
だからコンパイルエラーが出るかもしれません。その場合は御自分で直してください。
また、正しく動かないかもしれません。その場合は臨機応変にがんばってみてください。
応援してます。
①各キャラクターにゲージを持たせ、ゲージの値を各々のすばやさで初期化しておきます。
②ゲージを1ずつ増やしていき、ゲージが一定数(今回の例なら100)を超えたら攻撃するようにします。
③全員が攻撃したら初期化します。
というようにします。
※同時の場合インデックス番号が早いほうが先になります。また、今回の例なら味方より敵の方が先になります。
~以下詳しい説明&重要な部分のソースコード~
敵の最大出現数を TEKI_MAX
とします。
それと、
struct KOUZOUTAI{
int being; //生きている場合1を、そうでない場合0を代入することとする
int subayasa; //すばやさを代入することとする
int gauge; //ゲージ(ゲージが一定数を超えると攻撃)
}party[PARTY_MAX], teki[TEKI_MAX];//変数宣言
を宣言しておきます。
あらかじめ
int party_kazu = パーティーの現在の人数;
for(int i=0;i<party_kazu;i++){
party.being = 1;
party.gauge = party.subayasa;
}
int teki_kazu = GetRand(TEKI_MAX-1)+1 //敵の数を決める
for(int i=0;i<teki_kazu;i++){
teki.being = 1;
teki.gauge = party.subayasa;
}
としておきます。
.attackの値の意味・・・ 0→未攻撃 1→攻撃中 2→攻撃済み
//自動変数宣言 ※グローバルじゃないです
int hantei = 1; // 1・・・全員攻撃済み 0・・・少なくとも一体は未攻撃
int trigger = 0; //ゲージが溜まるのが同時の際に他のキャラに攻撃させないため
//最低1体が攻撃態勢になるまでゲージの処理をする
while(flagg==0){
for(int i=0;i<teki_kazu;i++){
//敵が生きている&ゲージが溜まる&敵が攻撃済みでない ならば
if(teki[i].being==1 && teki[i].gauge+=1 >= 100 && teki[i].attack != 2){
teki[i].attack = 1; //敵の状態を攻撃態勢にする
flagg = 1; //whileループから脱出するようにする
}
}
for(int i=0;i<party_kazu;i++){
//味方が生きている&ゲージが溜まる&味方が攻撃済みでない ならば
if(party[i].being==1 && party[i].gauge+=1 >= 100 && party[i].attack != 2){
party[i].attack = 1; //味方の状態を攻撃態勢にする
flagg = 1; //whileループから脱出するようにする
}
}
}
for(int i=0;i<teki_kazu;i++){
if(teki[i].attack==1 && teki[i].being==1){
TekiAttack();//味方の攻撃関数を呼び出す
//処理が完了したら flagg = 0; としてwhileループに入るようにしてください
//また、attack = 2; として、状態を攻撃済みにしてください
trigger = 1;//トリガーを作動させる(同時の際に他に攻撃させないため)
break; //forループから脱出
}
}
if(trigger==0){
for(int i=0;i<party_kazu;i++){
if(party[i].attack==1 && party[i].being==1){
PartyAttack();//味方の攻撃関数を呼び出す
//処理が完了したら flagg = 0; としてwhileループに入るようにしてください
//また、attack = 2; として、状態を攻撃済みにしてください
break; //forループから脱出
}
}
}
//↓全員攻撃し終わったらゲージをリセットする↓
for(int i=0;i<teki_kazu;i++){
//敵の中に、生きていて攻撃していない者がいる ならば
if(teki[i].attack!=1 && teki[i].being==1) hantei = 0;//リセットしない
}
for(int i=0;i<party_kazu;i++){
//味方の中に、生きていて攻撃していない者がいる ならば
if(party[i].attack!=1 && party[i].being==1) hantei = 0;//リセットしない
}
if(hantei==1) ResetTheGauge(); //ゲージをリセットする関数を呼ぶ(書くのめんどくさい)
//↑全員攻撃し終わったらゲージをリセットする↑
なお、攻撃関数を呼んだとき、仲間や敵が死んだらそのbeingを0にしてください。
実際にプログラムを実行したりとかはしていません。コンパイルもしていません。
だからコンパイルエラーが出るかもしれません。その場合は御自分で直してください。
また、正しく動かないかもしれません。その場合は臨機応変にがんばってみてください。
応援してます。
最後に編集したユーザー MoNoQLoREATOR on 2011年2月15日(火) 00:54 [ 編集 2 回目 ]
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 14年前
- 住所: 東海地方
- 連絡を取る:
Re: RPGの戦闘について
>>MoNoQLoREATORさん。
少しテクニックに走っているので初心者さんには分かりづらいかも。
・beingを生きているフラグと加算値で兼用している点。
・attackフラグの数値の意味が不明確。2の値の意味は?
・party.attackの変化が1の代入しかコードにない。
あと、フラグを1にする部分と「TekiAttack(); //敵の攻撃関数を呼び出す」を分ける必要が無いのでは?
[追記]
念の為に書いておきますが、MoNoQLoREATORさんの回答が唯一の方法ではありません。
ソートもひとつの方法ですし、最大値を探して最大のものから一つづつ処理す方法もあります。
ツリー構造にして、ツリー構造を作るときに自動的に順番を決定することも出来ます。
アルゴリズムの組み合わせで色々方法があるとご理解下さい。
少しテクニックに走っているので初心者さんには分かりづらいかも。
・beingを生きているフラグと加算値で兼用している点。
・attackフラグの数値の意味が不明確。2の値の意味は?
・party.attackの変化が1の代入しかコードにない。
あと、フラグを1にする部分と「TekiAttack(); //敵の攻撃関数を呼び出す」を分ける必要が無いのでは?
[追記]
念の為に書いておきますが、MoNoQLoREATORさんの回答が唯一の方法ではありません。
ソートもひとつの方法ですし、最大値を探して最大のものから一つづつ処理す方法もあります。
ツリー構造にして、ツリー構造を作るときに自動的に順番を決定することも出来ます。
アルゴリズムの組み合わせで色々方法があるとご理解下さい。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
- MoNoQLoREATOR
- 記事: 284
- 登録日時: 14年前
- 住所: 東京
Re: RPGの戦闘について
修正しました。
>>・party.attackの変化が1の代入しかコードにない。
ほんとうですね。書き忘れました。
フラグと攻撃関数呼び出しを分ける必要はないですね。
attackの値の2は「攻撃済み」を意味していました。
フラグと攻撃関数の呼び出しを分けないようにしたので、現在は1が「攻撃済み」を意味します。
>>・party.attackの変化が1の代入しかコードにない。
ほんとうですね。書き忘れました。
フラグと攻撃関数呼び出しを分ける必要はないですね。
attackの値の2は「攻撃済み」を意味していました。
フラグと攻撃関数の呼び出しを分けないようにしたので、現在は1が「攻撃済み」を意味します。
- MoNoQLoREATOR
- 記事: 284
- 登録日時: 14年前
- 住所: 東京
Re: RPGの戦闘について
欠陥をみつけてしまったのでこっそり修正してきました。
攻撃エフェクトをアニメーションさせたいときは何度も攻撃関数を呼んだほうが良いのでそのやり方に対応させました。
攻撃エフェクトをアニメーションさせたいときは何度も攻撃関数を呼んだほうが良いのでそのやり方に対応させました。