投稿記事

2024年 08月の記事 (2)

白神プロジェクト 2024/08/25 21:20

【プログラマー向け】クラス設計のリファクタリング#2

皆さんこんにちは!
ご閲覧いただきありがとうございます。

本日は前回に引き続き、制作者様向けに私が行った
リファクタリング方法を微力ながら解説させていただきます!

開発環境は以下の通りです。
・Unity
・VisualStudio 2022
・c#


何を行ったか

拡張するたびに、EnemyCore内のswitchケースの分岐が増えたり
条件式が冗長になるのは避けたかったのでシンプルに機能の切り分けを行いました。

それぞれのInterfaceに基本機能をつけ、EnemyCore内に以下の
変数を用意します。

このように定義すると、Setup関数内で継承先のクラスを自由に
アタッチすることができるので柔軟な設計になったかと思います。


  • 自滅判定

改修前では自滅タイマーでの判定しか行っていませんでしたが
ここに追加条件が入ると、どの条件によって自滅しているのか
不具合が発生したときにどの条件で問題が発生しているか
分からなくなる設計になっていた。

またドロップ条件などもここに条件があるのはおかしいので
状態遷移の命令と自滅実行時の関数だけ呼ぶように修正

【before】

【after】


  • 死亡時判定

コインや経験値以外にドロップアイテムを増やしていく場合
Listにドロップ予定のアイテムを追加するだけでそれぞれの条件から
ドロップを行うか判断できるように修正

【before】

【after】


  • 移動更新処理

switchケースでそれぞれの処理を書いていたので、行動パターンが
増えるたびに追加しなければいけなかったり、〇〇の行動と△△の行動を
組み合わせた動作をさせたいときに、EnemyBaseを継承して専用の
処理を作る必要がありましたが

_enemyMovementに代入した
クラスの型を変更するだけで任意の挙動に切り替えることができ

特別な動作を作る場合も、IEnemyMovementを継承させた
EnemyMovementBossのようなクラスを作成することでよいので
量産を簡単に行うことができるようになりました。

【before】

【after】


反省点や振り返り

量産や今後の活動に合わせてある程度
ソースの整理は行えたかなと思いましたが、MonoBehaviorを継承
させるかについてはいまだに迷いました。

実際にEnemyMovementクラスは移動座標量を計算して
渡しているだけなので、EnemyCoreから現在の座標やターゲット座標を
与えてもらうまで動かないので制約がきついので

今度挙動を追加する際に手間になってしまう気がします。
(現状でも振る舞いごとに渡すプロパティが違うので)

UnityAPIに頼る部分とそうでない部分の見極めは慎重に
行う必要があると改めて実感できました。


今回は以上となります!
新米プログラマーの書いた記事ですが、少しでも参考になれば幸いです!
最後までご閲覧いただきありがとうございます!

白神プロジェクト 2024/08/11 21:20

【プログラマー向け】クラス設計のリファクタリング#1

皆さんこんにちは!
ご閲覧いただきありがとうございます。

本日はタイトルにもある通り、趣向を変えて制作者様向けに
敵クラスの設計について失敗したな~と思うところがあったので
こちらをリファクタリングしつつ
微力ながら解説を行っていこうかと思います!

開発環境は以下の通りです。
・Unity
・VisualStudio 2022
・c#


現状の実装について

ということで、敵クラスが以下フォルダにまとまっています

・Bullet
・Generator
・ScriptableObject

こちらについては今回リファクタリングを行わないためノータッチで進めます
その他のクラスについて

・EnemyBase
・EnemyEliteBase
・EnemyBossBase
→敵のコアクラス、これがないと動きません

・EnemyManager
→敵本体に別クラスからアクセスを行うためのクラス
 敵のプーリングもこちらで行っています

・EnemyDefine
→列挙型などの定義関連をまとめたクラス


なにがいけないのか

敵コアクラスの構造に改善の余地があり、とりあえず継承させとけばどうにかなるかと考えてた筆者の脳内では以下のようになっていました
・EnemyBase
 └スライム
 └スケルトン

・EnemyEliteBase (EnemyBaseを継承)
 └スライムキング
 └スケルトンキング
 ※いわゆる中ボスたち

・EnemyBassBase (EnemyBaseを継承)
 └サキュバスちゃん

ただし、ヴァンサバライクなゲームなので、敵一体一体にそれほど特徴的な
差はなく、ステータスが多少変わる程度なので、ベースクラスという
骨組みだけが残された状態でそれを各Prefabにくっつけているだけなんですね。

さらに、EnemyBaseクラスで自滅の仕方だったり、行動制御まで行っているためEnemyEliteBaseクラスに関しては死亡処理の中で
宝箱をドロップするだけのスカスカな実装になっていました↓

これだとSOLID原則の単一責任の原則が守れていません
(そもそも場合によって中ボス以外からも宝箱を出したくなる時があるかもしれないのでこういった実装はよろしくない)


どうやって改修を行うか

当ゲームでは敵ごとに特殊な処理が入るわけではないのと、量産型の敵を
バリエーションがあるように見せたいので、機能の取り回しが
簡単に行えるようコンポーネント指向な設計に修正していこうと思います!

とりあえずの構想としてはこちら↓
(見やすいようにすべて外に出してますが、機能のまとまりはフォルダを切りましょう)

EnemyCore
 →EnemyBaseから機能分けして、残った共通部
 →EliteとBossは中身の実装がなかったので機能分けした部分に統合
 →各インターフェースの取り扱いのみを記述します

IEnemyDrop (インターフェース)
 └EnemyDropCoin
 └EnemyDropExp
 └EnemyDropTresureBox
 →ドロップアイテムについてのクラス
 →キャラにとって、ドロップアイテムをたくさん出したい場合があるかもしれないのでCore側ではリスト配列として保持

IEnemySuicide (インターフェース)
 └EnemySuicideTimer
 └EnemySuicideEvent
 →自滅のさせ方を決めるクラス

IEnemyMovement (インターフェース)
 └EnemyMovementBoss
 └EnemyMovementStraight
 └EnemyMovementTrace
→敵の行動制御クラス
→〇〇専用の処理を書きたい場合も使いやすい

といった具合でリファクタリングを行っていこうと思います!


本日はここまでにして次回、ソースレベルでの解説を行っていこうと思います。
閲覧いただきありがとうございました!

月別アーカイブ

記事のタグから探す

限定特典から探す

記事を検索