ページ 1 / 1
判定は誰がする?
Posted: 2012年6月03日(日) 23:17
by LisetteLander
簡単な質問ですいません。
今ゲームを製作中で、主に関数ポインタでマネージャークラスを駆使して作っているのですが疑問が生まれたので質問させてもらいます。
例えば
コード:
class MainGameManager(){
private:
CCharacter Character[10];
CWeapon Weapon[10];
public:
func();
};
(大雑把ですが)このようなマネージャークラスを作ると、
武器クラスが、キャラクラスのアドレス貰って武器クラスが当たり判定すべきなのでしょうか?
それとも
武器クラスから判定クラスに武器クラスの位置や角度を渡して判定させるべきでしょうか?
また、後者の場合マネージャークラスが判定クラスを保持しておいて、武器クラスがマネージャークラスを通って判定クラスまでアクセスしたほうがいいのでしょうか?
Re: 判定は誰がする?
Posted: 2012年6月04日(月) 00:39
by Dixq (管理人)
武器はプレイヤーや、敵が持っているのではないでしょうか・・?
プレイヤーや敵が持っている情報を取得しあうようなケースがあれば
関数ポインタを使うのではなく、必要なクラスにインターフェイスを渡してやればいいのではないでしょうか。
例えばキャラクタの特定の情報を取得することのみが出来るインターフェイスクラスを定義しておき、キャラクタはそれを実装し、
情報が欲しいクラスからそれが参照出来るようにすれば安全で、広い範囲から情報が取得できるかと思います。
https://www.google.co.jp/search?sugexp= ... 2B&qscrl=1
一番良い方法かどうかは分かりませんが、参考までに。
Re: 判定は誰がする?
Posted: 2012年6月04日(月) 00:48
by Dixq (管理人)
言葉だけではわかりにくいと思ったのでクラス図を描いてみました。
プレイヤークラスが敵クラスの座標を取得する方法です。
座標の取得が出来るメソッドを備えたPosGettableインターフェイスを定義し、Enemyクラスはそれを実装します。
マネージャークラスがEnemyクラスのPosGettableインターフェイスのインスタンスをPlayerクラスに渡します。
そうすれば、PlayerクラスからEnemyクラスの座標が参照出来ます。
その間マネージャークラスは仕事をしなくて済みます。
参考までに
# ↓「縮小表示中」の文字をクリックすると拡大表示できます
Re: 判定は誰がする?
Posted: 2012年6月05日(火) 01:01
by LisetteLander
C++の知識が乏しいのでよくわからないですが、
PosGettableから継承したEnemyクラスはPosGettableのインスタンスを持っているって事で、
マネージャークラスはEnemyクラスからPosGettableの成分だけポインタだけ取り出せるって事ですか?
継承というのはEnemyクラスのメンバにPosGettableのメンバが追加されるだけ・・って思ってたのですが・・・
Re: 判定は誰がする?
Posted: 2012年6月05日(火) 04:13
by nullptr
横から失礼。
LisetteLander さんが書きました:C++の知識が乏しいのでよくわからないですが、
PosGettableから継承したEnemyクラスはPosGettableのインスタンスを持っているって事で、
マネージャークラスはEnemyクラスからPosGettableの成分だけポインタだけ取り出せるって事ですか?
継承というのはEnemyクラスのメンバにPosGettableのメンバが追加されるだけ・・って思ってたのですが・・・
継承の概念は、AがBを継承している場合、「A is a B」となり、これをis-a関係とか言うことが多いです。
なんぞそれ、っていうと、ようは「AはB」なんです。この場合、
EnemyクラスはPosGettableクラスなんです。
意味分かんないですかね。
>継承というのはEnemyクラスのメンバにPosGettableのメンバが追加されるだけ
というよりは
「継承というのはEnemyクラスをPosGettableクラスとして扱うことができるようになる」
のです。そしてこの理由は
「EnemyクラスはPosGettableクラスだから(is-a)」
です。
継承のイメージは「機能(メンバ)を引き継ぐ」→「つまり継承したクラスは継承されたクラスの機能を持っているのだから、継承元と同様に扱ってもいいよね」
みたいな感じでいいと思います。
具体的にこの必要はあるのか?という点について。
コード:
class A
{
int Hp;
public:
int getHp() const{ return this->Hp; }
};
class B
:public A
{
public:
void Hoge();
};
というコードがあったとして
PosGettableから継承したEnemyクラスはPosGettableのインスタンスを持っているって事で、
マネージャークラスはEnemyクラスからPosGettableの成分だけポインタだけ取り出せるって事ですか?
ではなく、
継承したクラスは継承されたクラスの機能を持っているのだから、継承元と同様に扱ってもいいので、
BのポインタをAのポインタ変数に入れられます。
Aのポインタからは、Aの持つインターフェイス(getHP)しか触れない。つまりAに入れるとHogeは使えない。
コードにするとこんな感じ。
コード:
void Test(){
B instans; // B型のインスタンス
A* pointer; // A型のポインタ
pointer = &instans; // 継承したクラスは継承されたクラスの機能を持っているのだから、継承元と同様に扱ってもいいので、BのポインタをAのポインタ変数に入れられます。
pointer->getHp(); // OK
pointer->Hoge(); // Error!! AからはHogeは使えない
}
これ管理人様のおっしゃっている、
情報が欲しいクラスからそれが参照出来るようにすれば安全で、広い範囲から情報が取得できるかと思います。
を実装するのにピッタリだと思いません?
厳密に言えば
「情報が欲しいクラスからそれ
だけが参照出来るようにすれば安全で、広い範囲から情報が取得できるかと思います。」
つまり、
「情報が欲しいクラスに、EnemyクラスをPosGettableクラス型のポインタに入れて教えてあげれば、座標だけ教えられるよね?他のは触れないもん、だってPosGettableクラス型なんだから」
ってことです。
継承というのはEnemyクラスのメンバにPosGettableのメンバが追加されるだけ
というのは、まぁ完全に間違ってるかって言うとコレも結果的な事実ではありますが、よくない設計のもとになるかと思います。
Re: 判定は誰がする?
Posted: 2012年6月05日(火) 17:21
by LisetteLander
なるほど
それならメソッドやコンストラクタの引数でキャラクターのアドレスを渡すよりも目的がハッキリ区別していて分かりやすそうですね。
でも、話が進んでしまって言い難いのですが、No.1の質問は
武器クラスが判定するか、判定クラスを作って「攻撃」という情報を送って判定させるかどちらのほうがいいのか
というもので、No.1の補足すると
攻撃のアクションが行われたら武器の座標と角度や攻撃方法や、マネージャクラスから貰ったキャラクタのアドレスを使って
武器クラスがその場で判定クラスをインスタンス化してどのキャラクタにあたったかを判定するのか
もしくは
マネージャクラスが判定クラスを保持しておき、
武器クラスがマネージャクラスのアドレスを持つことで、武器->マネージャ->判定->Func()という経路を攻撃要求が来る度に毎回辿らせて
ひとつの判定クラスがどのキャラクタにあたったかを判定するほうがいいのか?
というもので、
階層構造でいうと
・マネージャ/武器[10]/判定 (武器の数分)
とするか、もしくは
・マネージャ/武器[10]
・マネージャ/判定 (一個)
としたほうがいいのか、という意味です。
Re: 判定は誰がする?
Posted: 2012年6月05日(火) 21:27
by Dixq (管理人)
上で
> 武器はプレイヤーや、敵が持っているのではないでしょうか・・?
と言った通りで、私はプレイヤーや敵と同じ階層に武器クラスがある設計がよくわかりません。
武器はキャラクターが持っているのですから、キャラクターの持ち物であるべきではないでしょうか?
従って当たり判定は、判定したい対象を元にプレイヤーが持っている武器クラスが行うべきではないかと思います。
また、物をオブジェクトと捉えるオブジェクト指向設計において、「判定」というクラスは少しおかしいのではないかと思います。
Re: 判定は誰がする?
Posted: 2012年6月06日(水) 01:27
by nullptr
Dixq (管理人) さんが書きました:上で
> 武器はプレイヤーや、敵が持っているのではないでしょうか・・?
と言った通りで、私はプレイヤーや敵と同じ階層に武器クラスがある設計がよくわかりません。
武器はキャラクターが持っているのですから、キャラクターの持ち物であるべきではないでしょうか?
従って当たり判定は、判定したい対象を元にプレイヤーが持っている武器クラスが行うべきではないかと思います。
また、物をオブジェクトと捉えるオブジェクト指向設計において、「判定」というクラスは少しおかしいのではないかと思います。
管理人様はこう仰っていますが、私はそうは思いません。(ただし私より管理人様のほうがはるかに経験者ですから納得イカなかったら気にしないでください)
「判定」も“モノ”だと思います。
判定という言い方をすると、動作のイメージが強いですが、「どう」判定するかという点において、十分クラスになり得るかと。
むしろ、武器が当たり判定を行う方がおかしいのではないでしょうか?位置あい的には武器に任せると楽に見えますが、正しい設計とは思えません。
たとえば当たり判定の仕方を変えたいと思った時、武器クラスが判定を行なっていると武器クラスを書き換える必要が出てきます。
これっておかしいと思います。だって、変更を加えたいのはキャラと武器の当たり判定です。
例えば「当たり判定基底クラス」があるとして、それを派生させて「本格的な当たり判定クラス」や「味方には当たらない判定クラス」などの
様々な「方法」をクラスの階層構造で表現するのは正しいことだと思います。
なので私なら、判定クラスを作り、判定クラスのインターフェイスのポインタをキャラが持つべきだと思います。
判定に必要な武器の情報はキャラが知っているでしょうから(管理人さんも懸念してますがもし№1のように武器がキャラと同階層にあるなら武器はキャラのしたに入れるべきです、その上で)、
キャラクラスが判定クラスに引数なりで渡せば良いと思います。
例えばポインタですから途中で「無敵状態」を作ろうと思った時に中身の判定クラスを差し替えるだけで済みます。
キャラに持たせる判定の仕方を変えようと思っても、書き換えの被害は当然変更したい判定クラスや、キャラクラスもcppファイル内で済みます。
GoFのパターンで言うStrategyパターンです。
これが完全に正しい設計かは知りません。ただ武器が判定するよかいいと思います。
Re: 判定は誰がする?
Posted: 2012年6月06日(水) 02:45
by ISLe
わたしも判定などの実装をクラス化することが多いですね。
というかフレームワークは実装をクラス化したものの塊ですし。
だいたい新月獅子さんと同じ考えですが、持たせるのは判定クラスではなくて汎用判定領域クラスにすると思います。
汎用判定領域クラスはインスタンス同士の重なりを調べるだけの単純なクラスにしてフィードバック先として武器クラスのポインタを保持します。
汎用判定領域クラスはインスタンスが作成されたら判定マネージャクラスが管理するリストに登録します。
判定マネージャクラスはリストから汎用判定領域クラスを検索して重なりを調べて当たっていればフィードバックします。
判定クラスは当たっているかどうかだけをフィードバック、フィードバックされた武器クラスが武器としての効果を相手に与えるというふうに役割を分けるわけです。
2Dシューティングゲームでひとつのキャラに破壊可能部位が複数あるとかの場合にも同じような実装をするのでいけると思いますけど。
Re: 判定は誰がする?
Posted: 2012年6月06日(水) 15:43
by shiro4ao
武器が判定する仕事をするべきである→フェンシングのように武器が判定をブザーで通知する
審判が判定する仕事をするべきである→剣道のように審判の判断で声で判定を通知する
という違いなのでしょうか。
コンピュータにおける実装の場合どちらが便利がいいのかは私にはわかりません。
横槍で混乱させるようで申し訳ありません。
Re: 判定は誰がする?
Posted: 2012年6月06日(水) 16:38
by ISLe
shiro4ao さんが書きました:武器が判定する仕事をするべきである→フェンシングのように武器が判定をブザーで通知する
審判が判定する仕事をするべきである→剣道のように審判の判断で声で判定を通知する
という違いなのでしょうか。
コンピュータにおける実装の場合どちらが便利がいいのかは私にはわかりません。
フェンシングの場合でも、相手の体に触れたらブザーを鳴らす、という『ルール』自体を武器が備えているわけではないですね。
どちらも武器が相手の体に触れたことをきっかけに発生するイベントです。
もし武器自身が変化するギミックを実装するとしても、武器は変化することができるだけで、変化するタイミングは武器が判断するものではないです。
Re: 判定は誰がする?
Posted: 2012年6月06日(水) 17:41
by LisetteLander
「攻撃というイベントがあったらキャラクターにあたったか判定する」
のではなく、
「キャラクターが攻撃に当たっていないか判定しにいく」
という考え方ならば、
キャラクター(判定したいオブジェクト)の数によって処理が肥大化することもないですし、
例えば当たり判定用のマップなどを作って管理すれば、攻撃というイベントがあったらそこに座標と角度その他もろもろを登録するだけで、
キャラクターは自分の座標などを持ってメソッドにアクセスすれば、ひょっとしたら帰ってくるbool値だけで判断もできるということですね
ただし、マップに当たり判定をガンガン追加していく方法は想像もつきませんが・・・
※今まで攻撃イベント発生→総当りで当たり判定→該当したキャラクタにダメージを与えるという流れでした。
当たり判定マップを作るのならば
判定用クラスはキャラクタからアクセスできる必要があるのですが、キャラクタそれぞれが別々のものを持っていても仕方ないですよね?
そう考えるとやはり、当たり判定クラスはゲームマネージャクラスにフィールド(メンバ変数)として持たせて
同じフィールドのキャラクタが当たり判定クラスにアクセスしたほうがいいのでしょうか
Re: 判定は誰がする?
Posted: 2012年6月06日(水) 17:43
by shiro4ao
>ISLeさん
なるほど。そうなっているのですね。難しい。
横槍すみませんでした。m(_ _)m
Re: 判定は誰がする?
Posted: 2012年6月06日(水) 18:20
by ISLe
LisetteLander さんが書きました:例えば当たり判定用のマップなどを作って管理すれば、攻撃というイベントがあったらそこに座標と角度その他もろもろを登録するだけで、
キャラクターは自分の座標などを持ってメソッドにアクセスすれば、ひょっとしたら帰ってくるbool値だけで判断もできるということですね
ただし、マップに当たり判定をガンガン追加していく方法は想像もつきませんが・・・
武器だけじゃなく当たり判定を持つ部位をすべてリストに登録して判定クラスで重なりをフィードバックすれば、ダメージを与えるのも受けるのも同じように処理できます。
武器も人も固定された罠もすべて、当たり判定を持つものとしてそこにあるということです。
相手の属性によって当たったあとの挙動を決定する必要があると思いますが、そのあたりはフィードバックの際に相手情報として渡すようにインターフェースを設計すると良いです。
その辺の情報も抽象化した分だけ汎用性が高くなります。
攻撃と言ってもただ武器を振り回して位置が変わるだけ。
武器の属性として振り回されたパワーを持っている。
という考え方をします。
Re: 判定は誰がする?
Posted: 2012年6月06日(水) 19:10
by Dixq (管理人)
判定クラスについて言及しましたが、私が言いたかったのは、一番大きな枠組が「判定」になっていることで、キャラクタと同列に判定クラスがいることについてです。
仰るように、判定もクラスになるでしょうから、少し語弊がありました。
ただ、一番上のマネージャークラスが判定クラスを持っている構造が私にはすんなり受け入れられませんでした。
私が考えていたのは、その判定クラスをインスタンス化せず、
判定に必要なパラメータだけ持っておいて、判定クラスはそのパラメータを渡せば仕事をしてくれるような作りでいいのではないかと思いました。
ただ、ISLeさんの回答を見ると、確かに当たり判定を計算すべき物を全てリストで持っておけば、ぐるっと回すだけで全て計算出来て楽ですね。
> 新月獅子さん
> ただし私より管理人様のほうがはるかに経験者ですから納得イカなかったら気にしないでください
いえいえ、私はゲームプログラマーではないので、ゲームについては完全に素人です。
ISLeさんやSoftyaさんのように仕事でゲームを作ってる人間ではないですので、ガンガン突っ込んで下さい。
Re: 判定は誰がする?
Posted: 2012年6月06日(水) 22:07
by LisetteLander
ISLe さんが書きました:
武器だけじゃなく当たり判定を持つ部位をすべてリストに登録して判定クラスで重なりをフィードバックすれば、ダメージを与えるのも受けるのも同じように処理できます。
武器も人も固定された罠もすべて、当たり判定を持つものとしてそこにあるということです。
"リストに登録"とはstd::listというものでしょうか?
とすると、具体的な実装方法として、
座標、大きさ、形、存在時間の要素を持ったstruct型をpushしていき、イベントがあれば先頭から一つ一つ判定していく、ということでしょうか?
それとも、”フィードバック”というのがよくわからないですが、とにかくリストに追加していき、
ひと通り、1フレーム内の処理が終わったらJudge.Refresh()とでもしてクラスから各オブジェクトに結果を渡すということですかね・・・
Dixq (管理人) さんが書きました:
私が考えていたのは、その判定クラスをインスタンス化せず、
判定に必要なパラメータだけ持っておいて、判定クラスはそのパラメータを渡せば仕事をしてくれるような作りでいいのではないかと思いました。
インスタンス化していないクラスにパラメータを持たせるとはどういうものなのでしょうか?
別の話になりますが、C#を少し弄った時にnewせずにクラス名からそのままメソッドを使えたことに驚いたので、どういう仕組みなのかと・・・
Re: 判定は誰がする?
Posted: 2012年6月07日(木) 02:11
by ISLe
LisetteLander さんが書きました:"リストに登録"とはstd::listというものでしょうか?
とすると、具体的な実装方法として、
座標、大きさ、形、存在時間の要素を持ったstruct型をpushしていき、イベントがあれば先頭から一つ一つ判定していく、ということでしょうか?
それとも、”フィードバック”というのがよくわからないですが、とにかくリストに追加していき、
ひと通り、1フレーム内の処理が終わったらJudge.Refresh()とでもしてクラスから各オブジェクトに結果を渡すということですかね・・・
std::listを剥き出しで使うと応用が効かないので独自にインターフェースを設計すると良いと思います。
分類とかソートとか効率の良い方法は状況によって違うのであとから内部構造を変更できるように配慮しておくべきです。
1フレームに1回、判定マネージャが登録された当たり判定領域オブジェクトを総当たりで比較して当たっているオブジェクト同士に当たっているよと教えてやります。
判定マネージャから当たっていることが通知されるのがフィードバックでありイベントです。
ゲームプログラムはひとつの世界にひとつのオブジェクトが存在しているパラレルワールドです。
パラレルワールドを合成して見ているわけです。
判定マネージャのフィードバックを止めると目の前にいる敵に向かって武器を振り下ろしても当たらずスカる状態になります。
フィードバックはリアクションを自演するように求めるものです。
もちろん当たり判定処理を集中することで保守性が高くなるメリットもあります。
Re: 判定は誰がする?
Posted: 2012年6月07日(木) 17:25
by LisetteLander
なるほど、欲しい回答が得られました。
ありがとうございます!
あとひとつ、
ISLe さんが書きました:
std::listを剥き出しで使うと応用が効かないので独自にインターフェースを設計すると良いと思います。
分類とかソートとか効率の良い方法は状況によって違うのであとから内部構造を変更できるように配慮しておくべきです。
というのはどうすればいいんでしょうか?
勿論、ゲームにあった実装方法が良い、と仰っているのはわかるのですが、
オブジェクトにあった構造体の配列を予め用意しておき、その要素にフラグをたてて代入したり、
判断クラスのフィールドがもつ構造体ポインタにnewでインスタンス化して配列に追加するぐらいしか方法が思いつきません。
なんでもかんでも質問するのはよくないとは思いますが、「リスト化」というのがいまいちピンとこないので・・
Re: 判定は誰がする?
Posted: 2012年6月08日(金) 00:55
by ISLe
std::listと同じようなものを新たに自作せよというのではなくて、別に中身はstd::listそのままでも構わないのですが、将来中身が変わっても外からは分からないようにガワを作っておくと変更が楽だというだけのことです。
オブジェクト指向プログラミング的に言うと『委譲』というやつです。
Re: 判定は誰がする?
Posted: 2012年6月08日(金) 09:52
by LisetteLander
なるほど、大変勉強になりました。
ISleさんDixqさん新月獅子さんありがとうございました!