前提・実現したいこと
プログラミング初学者のため用語がたどたどしくて申し訳ございません。
現在RPGゲームをjavaで作成しているのですが、敵キャラや味方キャラのデータの保持の仕方についてどの記述がより良いか悩んでいます。
以下の例がダメな理由(下記以外)やより良い保持の仕方を指摘してもらえると助かります。
具体例
例えば、ゴブリンというキャラを実装する場合
(1) Unitクラス(敵キャラ、味方キャラ、主人公キャラ、非戦闘キャラが継承するクラス) //名前等を保持する (2) BattleUnitクラス (Unitクラスを継承: 戦闘を行うキャラ全てが継承するクラス) //攻撃力等を保持する (3) BattleNpcUnitクラス (BattleUnitクラスを継承: 戦闘を行う全てのNPCが継承するクラス) //行動パターンなどを保持する (4) Goblinクラス (BattleNpcUnitクラスを継承: 戦闘NPCであるゴブリンの情報を保持するクラス) //固有のスキルや特性などを保持する
と現在記述しています。
###このようなコードが良いと思う理由
(1) オブジェクト指向っぽい感じがする (2) 戦闘キャラ全般の仕様変更等があった場合(例えば名前の後にレベルをつけるようにするとか)一括でできる。 (3) どの情報がどこに存在するかが明確。 (4) 複雑になると予想される?システム部分の記述量を減らせる。 (5) オブジェクトの使い回しが容易(拡張性が高い?)
###疑問を覚えた理由
この記述に疑問を覚える理由は以下のようにアドバイスされたからです。
(1) わざわざクラスを用意してデータを保持せずとも、システムを管理するクラスに組み込むべきだ。 (2) これは普通のコードではない。 (3) 現状ほとんどのメソッドがget/setならばクラスは必要ない。必要になったらそのようにすればいい。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

回答5件
0
一応気になった点だけ書いておきます。
オブジェクト指向を考えているのであれば、静的な構造からだけでなく、動的な視点も必要です。
どんなデータを持ち回る可能性が高く、そのときにどんなI/Fを持つと汎用的になる、のような視点です。
設計段階で悩む場合は、図にするとイメージがわくこともあるので、UMLを使って何か書くのも手ですよ。
静的/動的両方の観点から現状の仕様の大枠を満たせるか、などを考えつつ簡単に箱と属性を書いていくといいとイメージが湧きやすいです。
なお、派生(や実装)は、構造としての制約が強いので、初期設計段階では確実な関係以外は曖昧にしておいた方がいいと思います。継承構造を厳密にしすぎると、実装を継承するような構造が多くなり、保守性が低下してしまいます。何を言いたいかというと、継承構造は実装目処が立たないうちに何段にもしない方がいいということです。
設計は基本的に今見えている範囲のことが、忘れずに表現できていれば良く、後は同様に検討した他の部分との整合が綺麗に取れていて、歪なところがないかを調整すればいいだけです。動きそうな目処が立ったら、パフォーマンスの観点で厳しそうなところを洗い出し、そこから全体を調整して、初回のモデルとして構造を決めてしまえばいいかと思います。
拡張性は気にするだけ無駄です。変更の入る部分は通常予想できません。今ある機能をより簡潔に描けるモデルを考えるべきです。ようは拡張できるようにあれもこれもと機能を詰めすぎるよりは、こんなのでいいの?みたいなシンプルなモデルの方が良い場合が多いということです。
あと、強いていうとしたら、オブジェクト指向の説明ではオブジェクトが属性とメソッドが合わさってクラスみたいな感じに言われると思いますが、実際にはそれを意識すると、小さなクラスに機能を持たせすぎる形になってしまいます。あまりオブジェクト指向だからと言って、データと機能を小さなクラスに詰め込まず、クラスごとの役割を明確にし、このクラスはデータメイン(モデル)、このクラスは機能メイン(コントローラ)、このクラスはプレゼンテーションメイン(ビュー)みたいな役割を重視する形にメリハリを付けてクラスを分けると、全体としての見通しがよくなります。
投稿2019/02/28 05:41
総合スコア343
0
ベストアンサー
最初に
敵キャラや味方キャラのデータの保持の仕方についてどの記述がより良い
オブジェクト指向を学ばれている他の人にそのクラス設計を見せて、どれだけ何となく(抽象的に)理解しやすいかが1つあると思います。あとはそのクラス設計で実際にプログラミングしやすいか否か。
2点を満たしているとprimさんが判断するのであれば、自信を持ってその設計でやってみると良いと思います。
少し気になる点
より良い保持の仕方
クラス設計には日々悩んでるまだまだオブジェクト指向のアマチュアですが、2点。
1点目、Unit
とNpcUnit
とBattleNpcUnit
は抽象クラスであったほうが良いと思います。
2点目、Npcクラスは、独自の行動で戦闘ができるNPCとして振舞えるということなので、次のようにCAN-DO関係で表現できます。
- Goblin can be NPC
- Goblin can do fight automatically
継承はIS-A関係なので、文章にすると「Goblin is a NPC」になります。
つまり「ゴブリンは絶対にNPC」という確固たる性質を持ってしまうわけなので、個人的に違和感があります。
上の関係で違和感がないのはCAN-DOの方なので、NPCの「行動パターンを持つ」という概念はクラスではなくインタフェースで表現したほうが適切な気がします。
ただ、あくまで「個人的に違和感を感じている」だけなので「ゴブリンは絶対NPC」という思想の元でクラス設計をされているのであれば、次に紹介する「気になった点を解決する」欄はスルーしても構いません。
気になった点を解決する
インタフェースにしたらどのような実装になるのか?を一つ考えてみました。
以下のようなクラス設計になるでしょうか。
(1) Unitクラス(敵キャラ、味方キャラ、主人公キャラ、非戦闘キャラが継承する抽象クラス) (2) BattleUnitクラス (Unitクラスを継承: 戦闘を行うキャラ全てが継承する抽象クラス) (3) Goblinクラス (BattleUnitクラスを継承し、IAutoFightableを実装: ゴブリンの情報を保持し、NPCとして振舞える具象クラス)
ゴブリンを表現するなら次のようになります
Java
1interface IAutoFightable{ 2 void AutoFight(); 3} 4 5public class Goblin extends BattleUnit implements IAutoFightable{ 6 public void AutoFight(){ 7 //敵ゴブリンの戦闘パターンを定義 8 } 9}
上記コードのようにモンスター毎に別々で定義するのではなく、「NPCとして共通の振る舞いを定義したい」という話であれば、そこでBattleNpcUnitクラスの登場になるかなと思います。
Java
1public class BattleNpcUnit extends BattleUnit implements IAutoFightable{ 2 public void AutoFight(){ 3 //敵のデフォルト戦闘パターンを定義 4 } 5}
Interfaceをつけておくと何が良いかというと、抽象的なクラスやインタフェースに対して振る舞いを要求できます。例えばプレイヤーと敵を戦わせる際は次のようなメソッドを作れます。
Java
1public Fight(Player player, BattleNpcUnit enemy){ 2 player.Attack(); //プレイヤーが攻撃 3 enemy.AutoFight(); //NPCが自動的に戦う 4}
Goblin
にBattleNpcUnit
を継承させた場合は、上記のFight
メソッドの引数に渡すことができます。
Goblin
クラスでAutoFight
メソッドをオーバーライドした場合は、Gobrin
独自の戦闘が行えます。(パーティー戦ならあるプレイヤーだけ一人狙いするとかがあるかもしれません)
そうするとFight
メソッドでenemyに保持されているインスタンスの型を知らないで実装を作ることができるので作りやすくなります。
このように抽象クラスやインタフェースに対してプログラミングすることを「ポリモーフィズム」と言います。
もっとオブジェクト指向チックに設計したいのであれば、継承することだけにこだわらず抽象に対してプログラミングするという考え方があると良いと思います。
所感
(1) オブジェクト指向っぽい感じがする
(2) 戦闘キャラ全般の仕様変更等があった場合(例えば名前の後にレベルをつけるようにするとか)一括でできる。
(3) どの情報がどこに存在するかが明確。
(4) 複雑になると予想される?システム部分の記述量を減らせる。
(5) オブジェクトの使い回しが容易(拡張性が高い?)
これ等5点を見て思うのは、オブジェクト指向っぽいというよりかは継承という機能のメリットを説明しているように見えます。なので、継承がオブジェクト指向の全てではないことは認識しておくと良いかもしれません。
(1) わざわざクラスを用意してデータを保持せずとも、システムを管理するクラスに組み込むべきだ。
(2) これは普通のコードではない。
(3) 現状ほとんどのメソッドがget/setならばクラスは必要ない。必要になったらそのようにすればいい。
全体的に同意できかねます。
データを保持する方法は人によって様々ですが、HPや攻撃力のステータスはシステムで静的に持つのではなく各々のオブジェクトに保持しておくのが良いと思います。
システムを管理させるデータというのはステータスなどの具体的な値ではなく、どちらかというとUnit
オブジェクトだとか、何かしらのオブジェクトではないでしょうか。
2はよくわかりません。関数チックに定義しろということでしょうか。
3もよくわかりません。データを保持するためのクラスというものもあるくらいですから合っても良いと思います。むしろ、そのクラスを用意しなければ各々のステータスをどのように管理すれば良いのでしょうか。是非そのアドバイスをされた人からより良い方法を伺いたいです。
投稿2019/02/28 02:41
編集2019/02/28 03:00総合スコア2663
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
検索したらこんなのが出てきました。参考にどうぞ。
【Breed】RPGのモンスターなどのキャラクターを作成するときに使うデザインパターン - Qiita
おそらく参考資料として挙げられている「Game Programming Patterns ソフトウェア開発の問題解決メニュー impress top gearシリーズ」が役に立ちそう。
投稿2019/02/28 02:18
編集2019/02/28 02:19総合スコア30939
0
敵キャラや味方キャラのデータの保持に関しては、
色々とやり方がありますが、下手にクラスを継承しなくても構いません。
疑問を覚えた理由欄の2番目以降は誰でも抱く疑問なので気にしなくていいと思いますよ。
投稿2019/02/28 01:12
総合スコア3307
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
提示されたクラス設計ですが、クラスの多さよりも多重継承「継承されたクラスをさらに継承」が使われていることの方が気になります。
多重継承のデメリットとして、
- クラス構造が複雑になり、全体を把握しにくい。(どの情報がどこに存在するかが分かりにくい)
- クラス設計が変更しにくいため、拡張性が低い。
- たくさんのクラスを用意する必要があり、全体の記述量が増え、メンテナンスコストが増える。
などがあり、オブジェクト指向の考え方と矛盾します。
あと素朴な疑問なのですが、モンスターは全部で何体いるんでしょうか?
極端な例かもしれませんが、ポケモン最新作「Let’s Go!ピカチュウ/イーブイ」では 809 種類のポケモンが登場しますが、この設計ですと 809 個のクラスが必要になります。
現実的にメンテナンス不可能な気がします。
「全体の記述量が増え、メンテナンスコストが増える」の理由を、以下の挙げさせていただきます。
- 単純にクラスが増えれば増えるほどが全体の記述量が多くなり、開発者が把握しなければならない範囲が広くなる。
- クラスが増えることにより、コンパイル時間が長くなる。(使用するプログラミング言語やコンパイラの性能にもよりますが)
- クラス継承により、他のクラスとの関係性が複雑になる。
最後の「クラス継承により、他のクラスとの関係性が複雑になる」は、少し理解しづらいと思いますので、一つだけ例を挙げます。
Bird(鳥)クラスを継承する子クラスとして、Owl(フクロウ)クラスと Pigeon(ハト)クラスがあり、そこに Penguin(ペンギン)クラスを追加したいのですが、一つ問題があります。
Bird(鳥)クラスは Fly メソッドを持っていますが、ペンギンは空を飛ぶことができません。
さて、この場合はクラス設計をどう変更すべきでしょうか?
本題ではないので、解説はリンク先の記事に譲りますが、クラス継承にはこのような問題がたくさん出てきます。
この例では、全部で 4 つしかクラスが出てきませんでしたが、これがもしポケモンのように数百個のクラスが必要になった場合、果たしてうまくクラス設計することができるでしょうか?
投稿2019/02/27 22:20
編集2019/02/28 15:57総合スコア6500
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/02/28 00:58
2019/02/28 01:07 編集
2019/02/28 01:16 編集
2019/02/28 02:16
2019/02/28 02:25

あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/02/28 09:07