[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
ども、こんばんわ~
さっき最後まで記事を書いたのに、ブラウザが落ちて記事が消えてしまったZAKIです
涙をこらえながら書き直そうと思います。
さてええぇぇぇぇ今回のおおおおぉぉぉぉテーーーーーーマはああああぁぁぁぁあぁぁぁぁ
シーン制御です。
すんません。マジで悔しいんですorz
さて、シーンとは何でしょうか。
シーンとは、タイトル、キャラセレクト、ゲーム、ゲームオーバー、などなど、ゲームの場面を指します。
皆さんはどんな感じで管理していますか?
while(1) {
if(sceneNo == 0) {
Title();
} else if(sceneNo == 1) {
CharaSelect();
} else if(sceneNo == 2) {
Game();
} else {
break;
}
}
こんな感じですか?
出来てるといえば出来ていますが、Game()関数を実行するとき毎回3回if判定が起こりますね
メインループだけに無駄な処理は避けたいところです
それを防ぐにはいろいろと使い回しの効く憎い奴を使います
そう、ポインタです。
しかも、関数ポインタです。
ああ引かないで待ってがんばるから僕がんばって説明するからぁ
続けて読んでもらえる人。ありがとう。
読んでくれない人、コノヤロウ。
関数ポインタとは関数のアドレスを入れるポインタ変数のことです。
関数ポインタの定義はサンプルではmain.hの38行目でやっていますね。
typedef void *(*LPSCENE)();
この行がそうです
typedefとは新しい型の定義を行います。
この場合はLPSCENEという自作の型を作っています。
説明すると結構長くなるので、詳しくは教科書、ネットで見てみてください。
あ、C言語の教科書あれは必携ですよ
みんな邪険にしますが、あれ見ればほっとんどのことが書いてあるので、実習中は持ってくことをオススメしますよ
あ、すいません。話を戻しますね
残りの部分が関数ポインタの宣言です
この場合は「void *型を返す引数なし」の関数のポインタです。
(*LPSCENE)が型の名前です
typedefが無ければこの部分は、変数名になります
()内の*はポインタであることをさします。
詳しくは教科書およびネットで(ry
関数ポインタ変数の宣言はmain.cppの18,19行目で行っています。
これをシーンの制御に使うので、これをシーン変数と呼びましょう
それじゃ、シーン制御の全体の流れを説明します
COMMENT
古い記事にコメしてみる
突然ですが俺の使ってるシーン変更を見てください
1.scene_baseというクラスつくる
2.それを継承してtitle_scene,game_sceneなどを作る
3.scene_base型のポインタ配列をつくる(*scene[])
4.そのポインタ配列に2で作ったクラスのオブジェクトのアドレスを入れる
5.メインループ内でscene->act(int)回して戻り値で切り替える
自分としてはこの方法が大好きです
戻り値がintになるのでゲームシーンからタイトルシーンなどが簡単にできるのが長所だと思います
この方法をどう思いますか?厳しい評価をして欲しいです。
No Title
生成したインスタンスは終了時にまとめて解放するんだと思うけど、それだとメモリの使い方に無駄ができてしまうなぁ・・・
PCならまだいいとしても、家庭用ゲーム機だと使えるメモリは限られてくるから無駄はなくしたい
だからこの記事に書かれてるような方法にも慣れておくといいと思う
ちなみにシーンマネージャってのを作るともっと楽にできるよ
No Title
コメントありがとうございます。
継承を利用したシーンの制御ですね。
私も知ったときは感動を覚えました。
予めnewで確保したシーンをポインタ配列に入れているのは、タイトルのシーンの間に各シーンを確保していて少し違和感がある。
一年生において継承を利用してのシーン制御している時点で
かなりのアドバンテージです。
もしラボ(北野館3階ゲームラボ1)に良かったら来られませんか?
是非ソースなどを見たいです!
yana#p様
シーンに使っていたインスタンスを終了時にまとめて開放するのは、
普通ではないでしょうか?
それとも、溜め込んで再利用して使うのでしょうか?
そのへんの詳しいコメントもあったら嬉しかったです。
No Title
そうかなぁ・・・
俺はマネージャの中で
Update()←シーン更新関数
の戻り値を次のシーンのインスタンスへのポインタ(シーン遷移がない場合はthis)にして、返ってきたポインタが現在のシーンのポインタと一致しない場合は現在のシーンの解放処理とインスタンス解放を行った後でその戻り値を次のシーンとしてポインタ変数に代入してるけど・・・
もしかして生成したインスタンス=各シーンで使われている画像とかの変数って解釈させちゃったかな?
そうなら申し訳ない
時折俺「何言ってんだ?」って事言い出すからなぁ・・・w
後で考えて「おかしいぞw」ってのはよくある話
直さないとww
さすが先輩パネー
問題点からして、各シーンのインスタンス生成をするタイミングを変えたらいいんでしょうか?
ポインタ配列をポインタ変数に変更して、最初に使うシーンをインスタンス化して回す
戻り値を見て、例えば999以外だったらシーン変更で、前のシーンを解放し戻り値に対応したシーンのインスタンス生成して上書きみたいな?
解放とかにわか知識なんですいません
>リーダ和田
人にみせるのは恥ずかしいので、もう少し勉強してからにします。
>Yana#P
シーンマネージャってのを勉強してみます。
いまだにゲームメインループのFPSを一定にする方法がどれがいいのか分かりません。ググっても古い記事ばかりでガッカリです。先輩たちの方法が知りたいです
No Title
FPS制御は大西先生の2Dの教科書の最後らへん
に乗っていた気がします。
シーンマネージャはシングルトンパターンを利用したクラスです。
一つ以上のインスタンスを管理するクラスをマネージャといいます(多分)
はい、またお願いいたします。
No Title
そういう感じ
ついでに俺は更新関数の戻り値の型をscene_baseにして、シーンが変化しない場合はthisを、変化する場合は次のシーンのインスタンスをnewして返すようにしてる。
たくさん質問する子ほど優秀やねん
グローバルは使ったらかっこわるいですよね
親クラスであるscene_baseに前もって場所を確保してそれを子クラスである各シーンから参照したりすればいいのでしょうか?
No Title
別のシーンから参照したい値とそのアクセサをstaticで作っておいて、参照したいときに参照すればいいと思う
例えばgame_sceneの中でスコアの加算などを行って、result_sceneでその値を参照する場合、
(result_scene.cpp内)
//スコア取得
unsigned int Score = game_scene::GetScore();
って感じで
No Title
(game_scene.h内)
class game_scene : public base_scene {
public:
/* 色々省略 */
static unsigned int GetScore(){ return m_Score; } //スコア取得
private:
/* 色々省略 */
static unsigned int m_Score; //スコア
};
(game_scene.cpp内)
unsigned int game_scene::m_Score = 0;
(何故DWORD使わないの?って人がいるかも知れないけど、一年ボーイ君がDWORDを知ってるかどうかが分からないから一応こっちにしておいた)
No Title
確かにその方法で解決しますがスマートでない気がします。
私、個人の意見ですが、
子クラスから子クラスにアクセスするのに違和感がある。それと、
static による解決だと、渡したいデータが増えてしまった場合、
staticの変数・アクセサが増えるデメリットがあります。
次のシーンにデータを送るためだけのクラスを作り、
シーンの管理クラスに持たせるほうが自然かと思います。
struct SceneData
{
int score;
int hit;
int life;
};
これでも解決しますが、
次のシーンへのデータの種類が増える度にこういう構造体が増えて
管理クラスで保持していといけないため、
各シーンクラスで次のシーンに必要な情報を構造体でまとめておいて
管理クラスにこういうのを作って
boost::any m_NextData;
に突っ込めば
ひとつにまとめれると思うのですがどうでしょう?
boost::anyのURLです。http://www.kmonos.net/alang/boost/classes/any.html
No Title
なるほど。
boostはまだ勉強してないなぁ・・・
僕は夜行性
いろいろ方法があってややこしや
管理クラスってこの場合はscene_baseですかね
親クラスでboost::anyを使って変数を宣言しておく。前のシーンで次のシーンで使う情報を構造体でそこに記憶する。子クラスである各シーンでそれを参照する。こういうことですかね?