ページ 11

メインループの考え方でのゲームの設計

Posted: 2012年3月19日(月) 16:46
by L'z
メインループを使わず各関数の中でループする方法だと今のいる関数でゲーム部分やオプション部分とわかるのですが
メインループの考え方では今の場所(ゲーム部分なのかタイトル部分なのかオプション部分なのかなど)を表す変数stateを用意してstateの値に応じて処理をする必要があります。

オプション画面を半透明にし、背景にゲーム画面やタイトル画面があるようにしたいとき、stateだと今の場所しかわからずオプション画面を呼んだときの背景部分が表示させれません。
なので、stateを、stateに入れる値の分の要素数の配列にしてそれぞれに0か1を入れて1の部分だけを順に表示するように考えました。
ゲーム中にオプションを呼べばstatearry[GAME]とstatearry[OPTION]が1でオプションを抜けるとstatearry[OPTION]が0になりstatearry[GAME]だけが1になるということです。
処理部分では1になっているものは1つでいいのに複数あるのでどちらを処理するか選ぶというのも出てくるので、配列だけでなく今のだけを入れるstateも作っています。
表示はこれでできてはいるのですがあまりいい方法とは思えないしstateが増えると複雑でフラグ管理が面倒に思えます。

なにかいい方法って無いですか?
普通はこうするっていうのでなくても複雑にならずわかりやすい、管理しやすいというのであれば教えてください。




もうひとつ聞きたいのですが、メインループだと毎フレーム一番上のループに戻り、現在処理する部分をstateなどのフラグで判別しそこまで関数を入っていくのを繰り返すので無駄な処理が多い気がします。
低スペックPCに向けたゲームやコンシューマゲーム機のゲームでもメインループの考え方でつくられているのですか?

Re: メインループの考え方でのゲームの設計

Posted: 2012年3月19日(月) 17:11
by softya(ソフト屋)
L'z さんが書きました:なにかいい方法って無いですか?
普通はこうするっていうのでなくても複雑にならずわかりやすい、管理しやすいというのであれば教えてください。
stateがOPTIONの時に、オプション処理、ゲーム画面描画、オプション画面描画の順番で関数を呼び出すようにメインループを書けば解決する気がします。
どうにもしっくり来ないなら、メインから呼び出すのはOptionMng()関数とかにして中でオプション処理、ゲーム画面描画、オプション画面描画を呼び出せばよろしいかと。
L'z さんが書きました: もうひとつ聞きたいのですが、メインループだと毎フレーム一番上のループに戻り、現在処理する部分をstateなどのフラグで判別しそこまで関数を入っていくのを繰り返すので無駄な処理が多い気がします。
低スペックPCに向けたゲームやコンシューマゲーム機のゲームでもメインループの考え方でつくられているのですか?
ファミコン時代でも、そういう作り方はされていました。
あるいはシューティング等だとタスク・システムとかですね。まぁメインループに戻る事には変わり無いです。

●参考 「タスクシステム」
http://www5f.biglobe.ne.jp/~kenmo/progr ... /task.html
「タスクステムについて(基本編)」
http://www5f.biglobe.ne.jp/~kenmo/progr ... task2.html


今時のコンシューマやPC程度の性能になればstateからの分岐は負荷にはなりません。
気になるのなら実測して確認して見ることをお勧めします。

Re: メインループの考え方でのゲームの設計

Posted: 2012年3月19日(月) 17:33
by ISLe
L'z さんが書きました:なにかいい方法って無いですか?
普通はこうするっていうのでなくても複雑にならずわかりやすい、管理しやすいというのであれば教えてください。
ゲームでもよく使うウィンドウを重ねていく表示などで使う方法ですけど、stateの配列に積んでいく方法があります。
いわゆるスタックという考え方です。

簡単な実装だと、
const int STATE_NEST_NUM = 8; // ステートのスタック深さ最大数
int state_count = 0; // ステートの深さ
int state[STATE_NEST_NUM]; // ステートのスタック
// ゲーム開始するとき
state[state_count++] = GAME;
// オプションに入るとき
state[state_count++] = OPTION;
// オプションから出るとき
state_count--;
というふうにすると
state[0]~state[state_count-1]までを順番に描画して、state[state_count-1]に対して処理することになります。
L'z さんが書きました:もうひとつ聞きたいのですが、メインループだと毎フレーム一番上のループに戻り、現在処理する部分をstateなどのフラグで判別しそこまで関数を入っていくのを繰り返すので無駄な処理が多い気がします。
低スペックPCに向けたゲームやコンシューマゲーム機のゲームでもメインループの考え方でつくられているのですか?
1フレームに1回しか実行しない単なる分岐なのでまったくと言って良いほど影響ありません。

各部きちんと構造化すればオプション画面の後ろにタイトル画面が透けて見える場合も、後ろのタイトル画面を描くのはタイトル部で、オプション画面を処理するのはオプション部です。
ゲーム中にオプション画面を開いても、後ろのゲーム画面を描くのはゲーム部で、オプション画面を処理するのはオプション部です。

つまりいつ開かれる可能性があるとしてもオプション部はオプション部として独立してただひとつあれば良い(他の各部も同様)わけで、分業化など開発効率の向上に繋がります。

Re: メインループの考え方でのゲームの設計

Posted: 2012年3月19日(月) 17:49
by L'z
softya(ソフト屋) さんが書きました:
L'z さんが書きました:なにかいい方法って無いですか?
普通はこうするっていうのでなくても複雑にならずわかりやすい、管理しやすいというのであれば教えてください。
stateがOPTIONの時に、オプション処理、ゲーム画面描画、オプション画面描画の順番で関数を呼び出すようにメインループを書けば解決する気がします。
どうにもしっくり来ないなら、メインから呼び出すのはOptionMng()関数とかにして中でオプション処理、ゲーム画面描画、オプション画面描画を呼び出せばよろしいかと。
すみません。情報が不足していました。
オプション画面はゲーム部分、タイトル部分など複数の場所から呼び出せます。
なのでstateだけだと背景をゲーム画面とタイトル画面のどちらを表示すればよいかがわからず困っているんです。
また、オプションからサブオプションを呼び出すことができ、サブオプションはショートカットでオプションを飛ばして表示することも可能にしようかと思っています。この場合stateがサブオプションのときオプションを表示させるかどうかもフラグで管理する必要ができます。

softya(ソフト屋) さんが書きました: ファミコン時代でも、そういう作り方はされていました。
あるいはシューティング等だとタスク・システムとかですね。まぁメインループに戻る事には変わり無いです。
そんな昔から使われている方法だったのですか。
使われていてもPS2くらいからかなと思っていたので驚きました。
参考ページ読んで見ることにします。
softya(ソフト屋) さんが書きました:今時のコンシューマやPC程度の性能になればstateからの分岐は負荷にはなりません。
気になるのなら実測して確認して見ることをお勧めします。
PS3やPSVitaなどはスペックが高いですがPSPやDSとかはstateの分岐の処理も削らないと3D(飛び出さない方)とか処理が重いゲームを快適にするのは厳しいのかと思ってたのですがそんなことはないんですね。
気になるのはどちらかというとコンシューマの方なんですがさすがに自作ソフトを作るのはめんどうなので(つくれるのもPSPくらい?)実測はやめておきます。

Re: メインループの考え方でのゲームの設計

Posted: 2012年3月19日(月) 18:00
by softya(ソフト屋)
L'z さんが書きました:すみません。情報が不足していました。
オプション画面はゲーム部分、タイトル部分など複数の場所から呼び出せます。
なのでstateだけだと背景をゲーム画面とタイトル画面のどちらを表示すればよいかがわからず困っているんです。
また、オプションからサブオプションを呼び出すことができ、サブオプションはショートカットでオプションを飛ばして表示することも可能にしようかと思っています。この場合stateがサブオプションのときオプションを表示させるかどうかもフラグで管理する必要ができます。
Optionが何時呼び出されるかもわからないなら常に呼び出しておいて、Option処理内部において独自に有効・無効のステータス管理をすればよろしいかと思います。
Option処理モジュールにおいて、オプション・サブオプションの切り替えを独自管理するだけですのでスッキリすると思いますし、外部からオプション状態にあるか知ることの出来る関数とか現状の画面状態で使えるオプションとか設定する関数を用意すれば色々と都合よく処理できるのでは?

Re: メインループの考え方でのゲームの設計

Posted: 2012年3月19日(月) 18:17
by L'z
ISLe さんが書きました: ゲームでもよく使うウィンドウを重ねていく表示などで使う方法ですけど、stateの配列に積んでいく方法があります。
いわゆるスタックという考え方です。

簡単な実装だと、
const int STATE_NEST_NUM = 8; // ステートのスタック深さ最大数
int state_count = 0; // ステートの深さ
int state[STATE_NEST_NUM]; // ステートのスタック
// ゲーム開始するとき
state[state_count++] = GAME;
// オプションに入るとき
state[state_count++] = OPTION;
// オプションから出るとき
state_count--;
というふうにすると
state[0]~state[state_count-1]までを順番に描画して、state[state_count-1]に対して処理することになります。
スタックを使えばいいんですね。
ゲームでよく使う方法だけあって便利そうです。
ウィンドウを重ねる方法なのでオプションからタイトルへ戻るを選択したとすると
 state[0] GAME
 state[1] OPTION
 state[2] TOTITLE_CONFIRM
この状態で、確認でyesを選択するとウィンドウはタイトルだけなのでstate[0]だけで
 state[0] TITLE
となるようすればいいですよね?

ISLe さんが書きました: 1フレームに1回しか実行しない単なる分岐なのでまったくと言って良いほど影響ありません。
大きいゲームになるとstateがとても多くなるのである程度のstateで括ってstate、substate、subsubstateと何度も分岐するので処理が重くなると思ってました。1回だけの分岐ということはstateだけでいいんですね。
ISLe さんが書きました: 各部きちんと構造化すればオプション画面の後ろにタイトル画面が透けて見える場合も、後ろのタイトル画面を描くのはタイトル部で、オプション画面を処理するのはオプション部です。
ゲーム中にオプション画面を開いても、後ろのゲーム画面を描くのはゲーム部で、オプション画面を処理するのはオプション部です。

つまりいつ開かれる可能性があるとしてもオプション部はオプション部として独立してただひとつあれば良い(他の各部も同様)わけで、分業化など開発効率の向上に繋がります。
わかってはいるんですがそれをうまく実装する実力がないのが現状です……
まずオブジェクト指向になれないとですね。

softya(ソフト屋) さんが書きました: Optionが何時呼び出されるかもわからないなら常に呼び出しておいて、Option処理内部において独自に有効・無効のステータス管理をすればよろしいかと思います。
Option処理モジュールにおいて、オプション・サブオプションの切り替えを独自管理するだけですのでスッキリすると思いますし、外部からオプション状態にあるか知ることの出来る関数とか現状の画面状態で使えるオプションとか設定する関数を用意すれば色々と都合よく処理できるのでは?
常に呼び出すというのは考えませんでした。
こんな方法もあるんですね。

Re: メインループの考え方でのゲームの設計

Posted: 2012年3月19日(月) 23:38
by Dixq (管理人)
if文で考えると0か1かというデジタルな考え方しかできず「中間」が表現できないので、
0.5もありえるような構造にすると良いかと思います。
ゲームやメニュー、オプションなどのシーンをリスト化して
for( シーンリスト ){
  要素のシーン();
}
のようにし、フェードアウトするシーン、フェードインするシーンはタイマーで次第にブレンドするようにすれば良いと思います。
時間になれば完全に切り替わり、シーンリストの要素は1つになるという感じで実装してはどうでしょう。

Re: メインループの考え方でのゲームの設計

Posted: 2012年3月20日(火) 00:45
by ISLe
L'z さんが書きました:ウィンドウを重ねる方法なのでオプションからタイトルへ戻るを選択したとすると
 state[0] GAME
 state[1] OPTION
 state[2] TOTITLE_CONFIRM
この状態で、確認でyesを選択するとウィンドウはタイトルだけなのでstate[0]だけで
 state[0] TITLE
となるようすればいいですよね?
TOTITLE_CONFIRMがステートスタックを一気に積み直してしまうのではなく、あくまでも各部はひとつ進む・ひとつ戻るだけとして、OPTIONやGAMEが自発的に終了する仕組みにすると他の部分への依存を減らせます。
L'z さんが書きました:大きいゲームになるとstateがとても多くなるのである程度のstateで括ってstate、substate、subsubstateと何度も分岐するので処理が重くなると思ってました。1回だけの分岐ということはstateだけでいいんですね。
そういう意味では無いです。
ステートのネストが10個あっても1フレームに1回しか呼び出されない分岐が影響する量は少ないということです。
ネストが千とか万とかの単位になれば問題ですけど、そんなことより分かりやすいコードを書くことを心掛けましょう。

必要になってから考えれば良いことですが、気にするなら分岐ではなく、各部内部のループ処理を気にしてください。

Re: メインループの考え方でのゲームの設計

Posted: 2012年3月20日(火) 01:57
by L'z
Dixq (管理人) さんが書きました:if文で考えると0か1かというデジタルな考え方しかできず「中間」が表現できないので、
0.5もありえるような構造にすると良いかと思います。
ゲームやメニュー、オプションなどのシーンをリスト化して
for( シーンリスト ){
  要素のシーン();
}
のようにし、フェードアウトするシーン、フェードインするシーンはタイマーで次第にブレンドするようにすれば良いと思います。
時間になれば完全に切り替わり、シーンリストの要素は1つになるという感じで実装してはどうでしょう。
これは私のstatearryを使う方法のままで小数も扱えるようすればいいんですよね。
シーン切り替え時に中間の値を使ってでフェードもできるし、ウィンドウの重ねるときの透過度の設定もしやすくなるし、シーンの分だけ0,1のフラグのために配列確保する無駄も減るのでいいですね。
自分の方法のままで良くなる方法はないと思ってたのでISLeさんの方法に変えてしまったのでこの方法は次に何か作るとき使ってみたいと思います。

ISLe さんが書きました:TOTITLE_CONFIRMがステートスタックを一気に積み直してしまうのではなく、あくまでも各部はひとつ進む・ひとつ戻るだけとして、OPTIONやGAMEが自発的に終了する仕組みにすると他の部分への依存を減らせます。
プッシュとポップだけを使うようすればいいんですね。
わかりました、そのようにすることにします。

ISLe さんが書きました:そういう意味では無いです。
ステートのネストが10個あっても1フレームに1回しか呼び出されない分岐が影響する量は少ないということです。
ネストが千とか万とかの単位になれば問題ですけど、そんなことより分かりやすいコードを書くことを心掛けましょう。

必要になってから考えれば良いことですが、気にするなら分岐ではなく、各部内部のループ処理を気にしてください。
わかりました。ありがとうございます。

Re: メインループの考え方でのゲームの設計

Posted: 2012年3月20日(火) 01:59
by L'z
softya(ソフト屋)さん ISLeさん Dixqさん ありがとうございました。