何故自分が困る書き方を好むのか

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

何故自分が困る書き方を好むのか

投稿記事 by usao » 3年前

立て続けに2つの質問{ これこれ }を見たけど…

なんか,結構な期間このサイトを見てきた感じ,
  • Scene とかいう謎の基底
  • Task とかいう(同上)
  • XXXManager とかいうクソみてぇな名称の何か
みたいな謎の設計の話を割とよく見かけたような気がする.
何故彼らはこれらを好むのだろうか?
もちろん,それで何かが楽になるのであれば良いのだが,楽になってない方々は何なの?っていう.

意味わかんねぇ謎の実装形態を(どこかから持ってきて)採用したら直後に実装作業に行き詰るであろうことは明白であると思うのだが.
マゾなのか?

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: 何故自分が困る書き方を好むのか

投稿記事 by usao » 3年前

Scene をこのように定義してみました:

CODE:

class Scene
{
public:
	virtual ~Scene(){}
	///<summary>Called when this instance is selected as the current scene.</summary>
	virtual void OnSelectedAsCurrent( IGameContext &Context ) = 0;

	///<returns>Whether a redraw is required. (If returns true, <see cref="Paint"/> will be called.)</returns>
	///<remarks>
	///If this method calls IGameContext::TransToXXXScene() method and returns true,
	///Paint() of other instance correspond to the target scene will be called (rather than of this instance).
	///</remarks>
	virtual bool Update( IGameContext &Context, const Input_b &rInput, RndGenerator &Rnd ) = 0;
	
	//
	virtual void Paint( HDC hdc, const IGameContext &Context ) const = 0;
};
「場面を変えたい」的な要望等をどうやって実現するのか?
シーン毎に個別の処理に必要なデータをどこかから引っ張ってくる必要がある場合,どう実現するのか?

といったことを,「IGameContext なる型をメソッドに突っ込む」としています.
何か必要なことは全部こいつに言え,という.
コンストラクタDIの方がシーン毎に本当に必要な物を必要な形で突っ込むことができる気もしますが,それだと初期化時にしか渡せない(途中変更できない)という制約も生じるので,その辺は作る物次第かな,という気がします.
(グローバルとかシングルトン(笑)とかはここでは選択肢には入れません.)

で,この IGameContext を定めます.

CODE:

enum class DifficultyLV { Normal, Hard };

//Scene側から,ゲームの全体的な状況に対して何かするのに必要な処理手段を提供する
class IGameContext
{
public:
	virtual ~IGameContext(){}
public:
	virtual void TransToTitleScene() = 0;
	virtual void TransToGamePlayScene( DifficultyLV GameLV ) = 0;
public:
	///<returns>
	///Returns the difficulty that selected as argument to <see cref="TransToGamePlayScene"/>
	///</returns>
	virtual DifficultyLV GetCurrentGameLV() const = 0;

	///<returns>
	///This method always returns the same value.
	///(left, top) is (0,0), and (width, height) is paintable range size.
	///</returns>
	virtual const RECT &ViewRect() const = 0;
};
ここでは話をわかりやすくするために,あえて「XXXシーンに遷移しろや」っていうメソッドにしてあります.
また,シーン間で何も情報伝達が無いのも寂しいので「ゲームの難易度」という概念を設けてみました.

※で,今回は安直にこれを GameLogic に継承させて済ませたので,↑の方で Scene::Update() とかに *this が渡されています.

各シーンの具体実装はほぼ変わりません.上位側とのやり取りだけをこの新しい仕様に従う形に修正するだけの話です.
最後に編集したユーザー usao on 2022年8月02日(火) 13:12 [ 編集 1 回目 ]

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: 何故自分が困る書き方を好むのか

投稿記事 by usao » 3年前

で,書いといてなんですが,正直この実装は良くないと思います.

というのは,GameLogic の内側だけで閉じている話をちょっと楽にするためだけに,そのしわ寄せが外側(本来,好き勝手に実装できたはずの TitleScene とか GameScene とか)にまで及ぶ,というのはどうなのか? と.

TitleScene や GameScene を Scene を継承したものとして実装するのではなくて,あくまでもそれらは素朴な実装のままとすべきと思えます.
それらを管理している GameLogic が自身の事情でそいつらを Scene なる型として統一的に扱いたいだけなのであれば,そのためのアダプタでも用意して勝手にそうすれば良いだけの話なんじゃないかな,という感じです.

何だろう,こんなローカルな範囲にしか効かない話じゃなくて,もっと,こう,「 Scene であること」がプログラムの広範囲で意義があって,Scene として受け渡すだとかそういった大規模な(?)話じゃないと,どうにもならんなぁ.

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: 何故自分が困る書き方を好むのか

投稿記事 by usao » 3年前

ところで,「管理している側」が持っている

> TransToTitleScene();

みたいなメソッドを「管理されている側」から呼ぶのって,なんか恐怖感(?)みたいなのを感じるは私だけであろうか?
これの具体実装が

CODE:

void 管理側具体実装::TransToTileScene()
{//「カレントのシーン」を「タイトルシーン」にすげ替える最もシンプルな実装ってこんな感じだよねきっと
  delete m_pCurrentScene;  //おおっと!
  m_pCurrentScene = new TitleScene();
}
みたいな形になっていそうな気がして怖いのだ.
このメソッドから処理が返った時点では,既にこのメソッドを呼び出したオブジェクトは解体されてしまっている,っていう.
(この場合,呼び出し側が以降に自身のメンバ変数にアクセスしたらその時点でアウトって感じかな)

こういうのって,TransToTitleScene() を定義しているインタフェースでこのメソッドの規約として「コレ呼んだらカレントシーンオブジェクトは解体され得るぞ」的な話(あるいは逆に「そのへんは大丈夫だぞ」っていう話)がコメントなりで明言されてないとマジムリ……みたいな.
(もちろん,大前提として,呼ぶ側は自分自身が「カレント」なのだということがわかるのだとして)

一種の恐怖症かもしれんね.

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: 何故自分が困る書き方を好むのか

投稿記事 by usao » 3年前

さらに無意味にぐちゃぐちゃと考えてみる.
【「シーン」の側から「シーンの遷移」を要求する】っていうスタイルでいくのであれば,

> TransToTitleScene();
> TransToGameScene();
> ...

みたくメソッドを必要な分だけ設けずとも,

CODE:

ChangeSceneTo( std::unique_ptr<Scene> &Tgt );  //引数の適切な型がわからんけど
みたいな形でいいじゃんこれ,って当然思うね.うん.(ていうか,こっちが先に思いつくよな)
どうせ各シーンが{他のシーン群の存在を知っているし,遷移の流れも司っている}という枠組みで実装するんだから.

これなら遷移時の シーンA → シーンB の情報伝達とかも勝手にやれるわけだし,もう困ったことは何もないぜ!

---

でもなぁ…なんとも説明できない「なんか違くね…?」感みたいなのが……
「シーン群が互いの実装に依存し合っている」っていうので本当に良いのか?っていう警告が心の奥から来る感じ.
少なくとも

> TransToTitleScene();

のスタイルであれば,
「タイトルのシーンに遷移しろ」とは要求するものの,ここでの「シーン」ってのは概念なのであって,Scene型そのものではない.
例えば「タイトルシーン」という具体型が実際には存在しなくても全くOKなわけだし.
なんつーかそういう所を簡単に手放しちゃいけないんじゃない? 本当によいのですね?(強めの確認メッセージ) みたいな…

「どう割り切るか」なんだろうけど.