GameContext?[C++]

moba
記事: 82
登録日時: 9年前

GameContext?[C++]

投稿記事 by moba » 9年前

 ISLeさんのおっしゃるGameContextについて知りたいです。ピンポイントなので日記側から間接的に質問させていただきました。もしもご存じの方がいらっしゃれば、教えていただけると助かります_(._.)_
 質問掲示板で「GameContext」で検索すると、こちらがヒットします。クラス間でのデータの受け渡しについて
 僕が質問した際のご回答はこちらです。

 これで分かればいいのですが、実装で困りました。そこで、自分のコードで試そうとしました。クラスの上下関係はこんな感じです。

CODE:

GameParent
 - MapManager
   - MapDrawer
   - MapData  etc.
 - MapObjectsManager
   - ActorsManager
     - ActorsList etc.
   - ItemAndTrapManager
 - BGMManager
 - InputManager
 ここで、例えばMapObjectsがMap絡みのオブジェクトについて知りたいときに、GameContextを渡されていれば、下記のように書けるということだと思います。

CODE:

MapData* data = GetGameContext()->GetMapContext()->GetMapData();
data->GetMapSize( &width, &height );
...
■疑問点
 GameParentの下につくオブジェクト(Map, MapObjects, BGM, Input)をどのContextに入れるか。
 例えばMapManagerオブジェクトをGetGameContext()->GetMapManager()として得るか、
 GetGameContext()->GetMapContext()->GetMapManager()と書いて得るようにするか。

■問題点

1.誰がオブジェクトの所有権(deleteする責任の意味)を持つか、
 いつ誰がContextにポインタを持たせるか、
 誰がContextの所有権を持つか

2.Contextから得られるオブジェクトのインタフェイスは、なるべくGet系のみにしたい。


実装例:Contextだけ、GameContextをコンストラクトした時に最下層まで生成する。
Context::Set(オブジェクトへのポインタの引数)で、オブジェクトへのポインタを渡す。
GameParentがGameContextを持つ。

問題点:誰でもポインタをセットしてしまえる
     下層のオブジェクトが多いほど、Setの引数が増えて面倒くさい


ここまで考えました。この案はISLeさんの考えられているGameContextを実装するものとしてふさわしいでしょうか。
最後に編集したユーザー moba on 2016年3月29日(火) 20:33 [ 編集 2 回目 ]

アバター
せんちゃ
記事: 50
登録日時: 14年前

Re: GameContext?[C++]

投稿記事 by せんちゃ » 9年前

自分も似たような設計最近やっているのですが、コードレビューのときに
instance.instance.instanceみたいなアクセスが多いねって突っ込まれてしまいました。
自分の設計に問題があるだけかもしれませんが、入れ子が増えてしまいますね。。。
そこの解決策をどうするのがベターかが最近の悩みどころです。

moba
記事: 82
登録日時: 9年前

Re: GameContext?[C++]

投稿記事 by moba » 9年前

せんちゃさん、書き込みをありがとうございます。上の例はある程度の正しさに辿り着いているようで安心しました。おかげさまで突っ走れます。
引数が常に1つで済む(1つで全てのオブジェクトにアクセスできるようになる)ので便利ですよね。後からどうにでもできるので気が楽です。
ただこれは、クラス図を見て『これをちょうだい』と言うようなものなので、オブジェクト指向としては反則的なのかなと素人ながら思いました。離れていないオブジェクト同士ならば、コンストラクトする時にポインタを渡しています。

アバター
せんちゃ
記事: 50
登録日時: 14年前

Re: GameContext?[C++]

投稿記事 by せんちゃ » 9年前

僕も自分の実装が正しいのかはいつもわからんでやっているので当てになるかはわからないですね。
常に試行錯誤の日々です^^;
とはいえやはりstaticは使わなければ使わないほど、再利用性や汎用性が上がるような感じはします。
ゲーム部分はなかなか汎用的に作るのも難しいのですが、デザイナーがエフェクトを作りたいとか、プランナーがバランス調整したいとか、
同じゲームパートを使いまわしながらもそれぞれ専用のロジックの入ったシーンなんかを作らなきゃいけない場面が割とありました。

ステージそのものやゲーム部分を汎用的に作れないとそういうニーズに対応するのもなかなか難しいのかもな、と思います。
シングルトン的なものでまとめてればまだ良いのですが、それでもstaticは情報が残っちゃうので。
残った値が他の場面で悪さしてる、なんてバグはstaticを減らすほど少なくなった感があります。

moba
記事: 82
登録日時: 9年前

Re: GameContext?[C++]

投稿記事 by moba » 9年前

ご経験を聞かせてくださってありがとうございます。
充分には想像が及んでいないのですが、例えばチュートリアルを入れるのは大変そうだと思いました。いつかおっしゃることが分かればいいなと思います。
GameContextを使うことは、半ば全てのオブジェクトをグローバル変数にするようなものに見えて、『良い』組み方なのか判断しかねます。オブジェクト指向とはどういうものか、なぜオブジェクト指向で組むのか、オブジェクト指向で組むべきなのか、オブジェクト指向でない考え方とは…。僕がウディタで組んでいたときにはオブジェクト指向の考え方は無かったと思います。C++に移ると、処理やデータではなくて、綺麗に分かれた概念で組みやすくなったと思いました。例えば、ウディタではスコープの概念すらもほぼありませんでしたし。それ以上の差には気付いていないので、もしも何か違いがあるならば自覚的になりたいです。
今度オブジェクト指向に関する本が届くので考えたいと思います。お話を聞かせていただいてありがとうございました_(._.)_

ISLe
記事: 2650
登録日時: 14年前

Re: GameContext?[C++]

投稿記事 by ISLe » 9年前

#久しぶりのアクセスでかなり遅い返信になってしまいました。

掲示板の質疑応答では深い説明はほとんどできないので
グローバル変数とかマネージャークラスにアクセスする方法のような紹介をしてますけど
context(文脈)は、実装へのアクセスではなく、
いわゆる構造化プログラミング的な抽象化が本来の目的なんですよね。

例えば、マップ(フィールド)におけるイベント演出をする場合、
いちいちマップコンテキストからマップマネージャーを参照するとかでなく
マップコンテキストに用意したイベント発生メソッドを使う、という形でコードを書くのです。

イベントでは、マップ(フィールド)の変化やサウンドの再生やアニメーションなどいろいろ絡むわけで
それらはコンテキストの向こう側へ追いやって
あくまで、「マップでイベントが起きる」という文脈のコードで表現できるようにするわけです。

で、コンテキストの実装のほうに、各種マネージャーオブジェクトに指示を出すコードを書きます。

そうすることで、アプリケーションレベルとコンテキストレベルで実装を切り離すことができます。

アプリケーションレベルでは、文脈を表す記述になるので、いわゆるリーダブルなコードになります。
最後に編集したユーザー ISLe on 2016年4月10日(日) 18:13 [ 編集 1 回目 ]

アバター
せんちゃ
記事: 50
登録日時: 14年前

Re: GameContext?[C++]

投稿記事 by せんちゃ » 9年前

ISLeさん
横からの質問になってしまい恐縮なのですが、この辺の話、自分もとても気になっています。
ISLeさんの仰るcontextはちょうどandroidアプリケーションなどでも使用されているcontextクラスのような役割(というか構造?)
という感じなのでしょうかね?

>例えば、マップ(フィールド)におけるイベント演出をする場合、
>いちいちマップコンテキストからマップマネージャーを参照するとかでなく
>マップコンテキストに用意したイベント発生メソッドを使う、という形でコードを書くのです。
先ほどandroidを例に挙げましたが、これはandroidで言うところのActivityやBroadcastReceiverやASyncTaskのような類で
システム側に登録することでイベントが必要に応じて投げられる、けどどのようなロジックになってるかは各contextクラスが握っているよ、
そしてそれは見せないよって感じでしょうかね?

>イベントでは、マップ(フィールド)の変化やサウンドの再生やアニメーションなどいろいろ絡むわけで
>それらはコンテキストの向こう側へ追いやって
>あくまで、「マップでイベントが起きる」という文脈のコードで表現できるようにするわけです。
これは例えばMapContextに対して、「マップを切り替えろ」という命令を誰かが行い、その後のサウンド切り替えや何がしかのトランジションなどの複雑なロジック部分は全てMapContextにやってもらいそれらがすべて終了したときに「終わったよ」、という通知(仮にOnMapChangeCompletedみたいな名前のイベント関数だったとする)だけが呼ばれる、みたいな感じでしょうかね?

ISLe
記事: 2650
登録日時: 14年前

Re: GameContext?[C++]

投稿記事 by ISLe » 9年前

感じとしてはせんちゃさんのおっしゃるとおりですね。

Androidは(他のプラットフォームでも)
コンテキストはプラットフォームの実装に大きく依存した形のものが多いですけど
わたしのは、かなりアプリケーション寄りの抽象化を念頭に置いてます。
せっかく自分で作るのだから向こうの都合より自分の使いやすいものを目指すべき。

コンテキストは入れ子にできるので、
サウンドとかアニメーションとかはサブシステムとして各々抽象化しつつ実装して
汎用性を高めていくことができます。
Androidなどのコンテキストも一部として含めてしまうことで
アプリケーションから見たらマルチプラットフォームなコンテキストになります。

どういうふうにすると良いかというのは一概に言えないので
けっきょく試行錯誤は避けられないのですけど
やればやるだけ確実に経験を積めて見極める力が付き、開発効率の向上につながります。

コンテキストを作り込んでいけば最終的にはプラットフォームになります。
なので既存のプラットフォームの仕様は大いに参考になりますよ。
最後に編集したユーザー ISLe on 2016年4月11日(月) 18:28 [ 編集 3 回目 ]

moba
記事: 82
登録日時: 9年前

Re: GameContext?[C++]

投稿記事 by moba » 9年前

気付くのが遅れてすみません。ISLeさん、直々のご回答をありがとうございました。
また、せんちゃさんの質問のおかげで僕も手がかりをいただけました。助かりました!

contextが「アレらしい」ことを知るには、contextが「アレでない」「コレでもない」
ことを知る必要があり、まだまだ試行錯誤が必要そうです。
考えたことがあるのですが、間違っていても今の僕には修正できないので、
よろしかったら助言をいただけないでしょうか。
太字にしたところが、間違っていないかという疑問点です。


何でもかんでもContextに詰め込もうと考えると、
今の段階で次の2つの層?が出てきました。


1.マップ遷移やマップファイルの読み込み機能を提供する階層

 → マップの中でイベントが起こるという文脈になる

context(というマシン)によってインタフェイスが整えられて便利だと思いました。
(MapLoader, MapTransitionerという(それぞれの責務? を実際に担当するオブジェクト)が見えるよりも)


2.このMapManagerが集約しているオブジェクトの機能を提供する階層
使いたい機能は、例えばmapData->GetMapSize(&width, &height)です。

 → MapContextが、マップの文脈の中でイベントを起こすものというよりも
 → 仮想的な"マシン"になってしまう?


画像

以下ではcontextをマシンとして使う前提です。
追記:以下の疑問点はcontextのあり方そのものとは関係ありませんでした。

こちら(2.)の場合は、contextのインタフェイスは、contextの使い手が直接オブジェクトを見た場合とほぼ変わりません。
( 例:MapContext->MapDataContext->GetMapSize() )

ここでは同じものを書き直しているように見えて、
contextの書き手(ユーザではなく)の視点からだと違和感を覚えました。
ポインタを渡すのでいいのではないかと。

けれども、contextの使い手の視点からマシンとしてのcontextを考えると、
インタフェイスが全てcontextの中で完結している方がいい

だからcontextに関数を置く、ということで合っているでしょうか。
最後に編集したユーザー moba on 2016年4月21日(木) 20:53 [ 編集 1 回目 ]

ISLe
記事: 2650
登録日時: 14年前

Re: GameContext?[C++]

投稿記事 by ISLe » 9年前

言葉としての「コンテキスト(文脈)」というのは概念的なもので、
アプリケーションのコンテンツとしての実装も、内部実装も、
それぞれにコンテキストが存在するわけです。

(マップを)ロードする、とか、切り替える、というのは
アプリケーションのコンテンツとしてのものです。
例えば、マップのモジュールが
マップA・マップBの2つマップがある、という前提で作られていたら
それしか扱えなくなります。

抽象マップ、と、具体マップ、はコンテキストが異なります。
抽象マップ、を独立させることで汎用性が生まれるわけです。

抽象マップの、
「マップはいまどうなっているんだい?」
という問いに対して
アプリケーション側が
「マップはいまこうなってますよ」
と応答することでマップが出力されるなら
アプリケーション側が違うマップの情報を返せば
その時点でマップが切り替わるわけです。
いつマップのデータがロードされたか、いつ切り替わったか、を
抽象マップが知る必要はなく
アプリケーション側が自由にできるというわけです。

ということをタイルマップのクラス設計の質問スレで説明した気がするんですけども。

mobaさん質問掲示板でMVCの話題やってましたよね。
実はコンテキストにもMVCの考え方が重要なんですよ。

あと、いわゆるライブラリ的な、抽象化したままで完成っていう形に慣れてないように思います。

例えば、マップサイズの場合、
コンテキスト側にマップサイズを問い合わせると
アプリケーション側にマップサイズを問い合わせるコールバックがあって
そこで返したサイズが最初にマップサイズを問い合わせた元へ返るという形になったりします。
#サイズを記録しておいて返す方法もありますが
インターフェースしか持たないコンテキストの実装もあります。

moba さんが書きました:けれども、contextの使い手の視点からマシンとしてのcontextを考えると、
インタフェイスが全てcontextの中で完結している方がいい

だからcontextに関数を置く、ということで合っているでしょうか。
表現としては合っているんですけど
たぶんmobaさんの中ではMVC的な考え方はしてないと思うんですよ。
なので、mobaさんにとっての、contextにある関数、というものは
わたしの考えているものとだいぶ違ってほんの一部でしかないのではないでしょうかね。
最後に編集したユーザー ISLe on 2016年4月22日(金) 18:35 [ 編集 2 回目 ]

moba
記事: 82
登録日時: 9年前

Re: GameContext?[C++]

投稿記事 by moba » 9年前

ISLeさん返信をありがとうございます。
きっと、返信できるようにこまめに覗きに来てくださっていたのですよね。ありがとうございます。

またも、説明していただくのはかなりの手間になってしまいます…。
これを見ればコンテクストについて理解できる、という紹介だけでもよければお願いします。例えばフレームワークについて知れば分かるのかなと。

> 抽象マップと具体マップの違い

すみません、前に説明していただいたのに、何も分かっていないようです…。
抽象マップと具体マップの区別がつきません。

マップ関連のオブジェクトの上下関係と、
tilemapのDIのお話は覚えています。
あれで言えば抽象マップがtilemapで、TileIndexer等が具体マップですか。
それとも、もしかしてtilemapが抽象マップのコンテクストですか。
もしや全部関係無いですか。

> 抽象化したままの完成

 例えばきっとリスナ登録式ですね!

> コンテクストとMVC

 僕ではMVCの考え方を適用できませんでした。

マップ上でイベントを起こす
 → コンテクストのMakeMapEventがsubjectで、listener=イベント実行者に通知する? MVC??

マップ上で1マスの大きさを測る
 → コールバックするだけで、MVCは関係無いように見えました