質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.54%

  • C#

    8811questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • オブジェクト指向

    321questions

    オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

キャラクターと移動の振る舞いに対する設計

解決済

回答 1

投稿

  • 評価
  • クリップ 2
  • VIEW 1,317

tmt

score 3

前提・実現したいこと

質問させていただいた意図としては、
オブジェクト指向として適切な設計というのを理解したいという背景がございます。
タイトルはうまくまとめることができなかったので、例題としての内容を記載させていただきました。
下記の問題に沿ってご回答がいただけますと幸いです。

発生している問題

Unity/C#でゲームの製作するにあたって、ゲーム内のキャラクター用のクラスを実装しています。
キャラクターは、移動をはじめとした様々なアクションを行うことを想定しています。
が、これをキャラクターのクラス内でガシガシ書いていくと、
将来的なことを考えるとぶくぶくと肥えていきそうな懸念があります。
そのうえ、単一責任の原則から見るとあまり好ましくなさそうなので、
アクションごとに切り分けることにしました。移動も例外なく切り分けます。

移動はキャラクターによってまちまちなので、移動用のインタフェース(MoveInterface)を作り、
その上に歩行(Walk)、ワープ(Warp)と移動方法毎のクラスを用意しました。

このような形で各々のアクションについても実装することで役割がはっきりするとおもうのですが、
最終的にこのキャラクターをプレイヤーが動かせるようになった場合に、
結局インタフェース上に存在するMoveTo()やStop()をCharacterクラスの外から呼び出す必要が出てくるため、
自分のやっていることがラッパクラスを作っているに過ぎないのではという疑念が浮かび、
しっくりきていません。
疑念が晴れず、以下のコードのような設計がオブジェクト指向として適切なのか、
悩みが尽きません。

本来はどのような実装が適切なのか、ご指摘を賜れればと考えております。
よろしくお願いいたします。

※Unityならコンポーネント指向だからそもそもオブジェクト指向を使う意味が分からない、
という話は今回はご容赦いただけますと幸いです。

該当のソースコード

public interface MoveInterface
{
    void MoveTo(Vector3 destination);
    void Stop();
}
public class Walk : MoveInterface
{
    // 中身は割愛
}
public class Warp : MoveInteface
{
    // 中身は割愛
}

class Character
{
  private MoveInterface _moveLogic = new Walk();

    public void MoveTo(Vector3 destination)
    {
        if (null != _moveLogic)
        {
            _moveLogic.MoveTo(destination);
        }
    }
    public void Stop()
    {
        if (null != _moveLogic)
        {
            _moveLogic.Stop();
        }
    }
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

私はゲームプログラミングをしませんが、この手の質問は色々な意見があった方が良いと思うので回答してみます。


Strategyパターンとしては正しい切り分けをしていると思います。表層的なクラス(今回はキャラクター)は各種状態とアルゴリズムを纏めることが要求されているので、細かい動作の変更によってこのクラスを修正するのはおかしいですよね。

ゲームの進行上キャラクターをある地点に移動させたい

  1.   ゲームエンジンがCharacterにアクセス
    CharacterがMoveInterfaceにアクセス ⇒ 〇

  2.   ゲームエンジンがCharacterのMoveInterfaceにアクセス ⇒ ×

というように私は考えるので、上記コード自体には違和感はありませんでした。
複雑なオブジェクトを構成する場合、一次的に中身がスカスカのクラスができてしまうことはあります。
ただし、MoveInterfaceは移動方法と言いつつ、座標等も管理していそうなのでもしも移動している座標を管理しているならそれはちょっと違うだろう、と思いました。移動方法は進行状況を管理するべきではありません。座標情報自体はキャラクターと紐づくべきですから、そうなるとキャラクターのインターフェースと移動アルゴリズムのインターフェースは変わってくるはずです。

他の考え方としては…

キャラクターが状態だけを持っていればいいのでは?ということを気にされていると思います。
ようは、MoveKindだけキャラクターは持てばいいんじゃないのか、ということです。

3Dのゲーム等ではシーン切り替えで1人のキャラクターが複数の座標位置と紐づいたりする場合があります。
そうなると、シーン毎に座標等の状態は管理しなくてはいけなくなります。

こうなると、キャラクター自体をもっと抽象的な状態に保つために
・キャラクターに移動方法という状態を持たせる
・ゲームエンジン側で移動方法とアルゴリズムのマッチングを行い、表示したモデルを移動させる
・ゲームエンジン側がモデルとキャラクターの紐づきを把握している
という切り分けが行われているんじゃないか、と思っています。
キャラクターが保持する情報に直接的なアルゴリズムが含まれていないと、簡単なフラグの切り替えだけで移動方法が変更できる等の利点もあります。

ただこれはシーン切り替えが無ければ抽象化レイヤを追加して複雑にしただけと言えますから、作るゲームの規模で考えれば良いんじゃないかと思います。

あとは強いて気になった点を挙げるならMoveInterfaceという名前でしょうか、これはC#的な名前ではないですね。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/28 11:32

    ご回答ありがとうございます。

    ご指摘の通り、この構造だと目的地の座標を持っていなければならないので、その点では適切な設計ではないと考えています。
    実際は毎フレーム目的地に対して移動するための更新処理も必要になります。
    Characterに目的地を管理するメンバを追加して、MoveInterfaceは更新時にCharacterを引数にとって座標の更新をする…といったところでしょうか。

    抽象化を進めることで仕様の改変に対応できる幅は広がり変更コストがある程度抑えられるけど、複雑さと実装コストがかかってくるかと思うのでそこはトレードオフですね。

    もともとC++でコードを書いていた時期があってMoveInterfaceという名前になっています…
    C#的なネーミングだとIMoveという形が適切でしょうか…?

    キャンセル

  • 2017/01/29 21:44

    広く回答をいただきたいところではあったのですが、
    今一つ質問をうまく伝えられていないところもあって、これ以上は回答がつかないだろうと判断しました。

    haru666様のご回答をベストアンサーとさせていただきます。
    >複雑なオブジェクトを構成する場合、一次的に中身がスカスカのクラスができてしまうことはあります。
    少なくとも設計として大きな誤りをしているわけではないことが理解できましたので、
    少し自信をもってコーディングに努めていこうと思います。

    ご回答いただきありがとうございました。

    キャンセル

  • 2017/01/31 11:18

    そうですね、皆さん発言に責任持ちたいと思うので、気軽には答えづらいかもしれません。

    IMoveだと自身が動くようなイメージになってしまうので、(といっても今回は状態を保持している関係上それで間違っていませんが)ファンクタに近い性質を表すために私だとIMoveActionとかにすると思います。
    一方でIMoveという名前で常にCharacterクラスが同じ各キャラクターやエネミークラスもIMoveを継承するのであれば違和感はないです。

    キャラクターと各アクションの関係は複雑なので、これを扱いやすくするためにFacadeパターンを適用していると考えれますしね。

    キャンセル

同じタグがついた質問を見る

  • C#

    8811questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • オブジェクト指向

    321questions

    オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。