C#でpartialを使ってクラスの中身を分割する
こんにちは。
開発が進んでいくと、一つのクラスの中身が膨大な行数になることがあると思います。
その理由は様々あり、解決策もまた様々あると思います。
その中で、今回はpartialを使ってクラスを分割するということを行います。
どのような時にpartialを使うのか
まず、クラスの中身が膨大な行数になっていく場面はいつなのかを考えます。
- クラスの役割を明確に分けられておらず、なんでもできる神クラスになっている
- 役割は明確だが、メソッドなどが抽象化できていないので同じ処理を複数回書いている
- 役割も明確で抽象化もできているが、仕様が多い
1の場合はまずクラスの役割を定めましょう。partialで分けるとさらに可読性が低くなります。
2の場合はまず同じメソッドを呼び出していないか、同じ計算を書いていないかを探して最適化しましょう。DRY原則を守れの一言に尽きます。
3の場合。お待たせしました、partialの出番です。
そもそもpartialってなんぞ
これ(投げやり)
クラスの定義を、複数ファイルにまたいで行うことができます。
例として、ある特定のクラス内で使用するStateの中身をpartialで追加していきます。
gist3c692f67badadfc5e98a8f8abd8480a1
こんな感じです。
これだけだと分かりづらいかもしれませんが、このStateを継承したState1やState2というクラスはこのソースに帰属しているということがわかるので、メンテナンス性や拡張性も向上します。
最後
使用方法を間違えると、スパゲッティになりがちなので要注意です。
適切な場所で使いましょう。
おわり
UnityのStateMachineBehaviourについてのメモ
こっちを読んでください
MonoBehaviourと呼び出される順番
最初の1F
Awake()
Start()
FixedUpdate()
Update()
OnStateEnter()
OnStateMove()
LateUpdate()
それ以降
FixedUpdate()
Update()
OnStateExit()
OnStateUpdate()
OnStateMove()
OnStateIK()
LateUpdate()
各コールバックが呼ばれるタイミング
OnStateEnter()
そのStateに移行した時一番最初に呼ばれる
OnStateUpdate()
OnStateEnter()の次のフレームから最後のExitを除いた毎フレーム呼ばれる
Stateがトランジションしてる時でも呼ばれる
OnStateMove()
Stateが切り替わるまで最初のフレームから最後のフレームまでずっと呼ばれる
Stateがトランジションしてる時でも呼ばれる
OnStateIK()
アニメーションがIKを更新した際だけ呼ばれる
OnStateExit()
Stateの最後の1Fで呼ばれる
UnityのAnimatorでアニメーション遷移するときの自分なりの解
こっちも読んでください
設計の指標なので、なんとなくUnityできる人向けな感じする
AnimatorController
アニメーションアセットを登録してトランジション作ったり、パラメータを色々持てる
Animatorの管理
アニメーションのトランジション制御をパラメータで行うのはトランジション設定を毎回やらないといけないし、矢印が量産されすぎてつらい
矢印量産をめんどくさがって減らすと、一回Exitを経由させてアニメーション遷移させたりしなければいけない
スクリプトでアニメーションの制御を行うと
スクリプト上で保存してるキャラクターの現在のStateと
アニメーションのパラメータがズレる自体が頻出して拡張性が低くなる
スクリプトを使わない(使えない)なら
トランジション制御をぽちぽち頑張って作るしかない
矢印の量産は必要経費として割り切る
スクリプトを使えるなら
AnimatorにStateを作って、State名をScriptableObjectに登録する
(Enumで定義して、Enum名をStateに合わせてもいい)
Animator.CrossFadeInFixedTime(StateName,duration);で制御すると良い
動的にトランジション制御を作成してくれるので、とても楽
ただ、レイヤー内を総当たりで検索してるらしいので、アニメーションの数が膨大になるとパフォーマンス的に厳しくなるのかも
ちなみにCrossFade(StateHash,duration);だとdurationが実時間分の遷移ではないので、意図した動作にならない
CrossfadeInFixedTimeおすすめ
EnumでState名を管理していた場合は
Animator.CrossFadeInFixedTime(Enum.State.ToString(),duration);
で矢印一個分の働きをしてくれる
制御の詰まりポイント
CrossFadeInFixedTimeのdurationが0よりも大きい時(主に3Dで、モーションブレンドさせたい時)
CrossFadeInFixedTimeを呼ぶと、前のStateからCrossFade先のStateに移動するまでにduration分の時間がかかる
CrossFade中は、Animatorから取得できるStateInfoは遷移が完全に終わらないと、遷移先のStateではなく、遷移前のStateのままになる
つまり
if(CurrentStateName == NextStateName) return;
みたいな形で
同じステートの時アニメーションが最初から再生される動作を弾くチェックしようとしても弾けない
他にも、遷移中に同じStateに遷移が行われてしまう要因にもなる
解決方法として、アニメーションの遷移を行った時は、コルーチンなりを使って
yield return new WaitForSeconds(duration);などアニメーション制御を待機させてあげると良いと思う
結果
Animatorぽちぽち地獄から解放されて、設定弄るだけでアニメーション制御の書き換えもできるようになる
今の所問題はないけどあったら追記予定
2016/8/25 追記
こんなものがあった。
併用してアニメーション遷移の汎用コンポーネント作りたい
2017/4月の追記
制御コンポーネントを作成して適用してみた(年明け前くらい)
いい感じだけど、NormalizedTimeが機能しなかったりして自前で実装した
右側のPlayerStateTransitionはStateMachineBehaviour継承したクラスで
・Inputの入力受付時間
・ステートの自動終了時間
・ステートのキャンセル時間
・ステートのキャンセル先と優先度登録
とかできるようになってて、遷移先の切り替えが楽になった
やったね
Unity+VRの開発用DebugConsoleを作った
こんにちは
GearVR向けアプリのビルド後にDebug.Logが確認したかったり、頂点数やFPSを見たかったりしたので作りました
FPSみたいだけならOculusSDKのプラグイン入れた方がいいかも
UnityPackageはここ
使い方
BuildSettingsにDebugシーンを追加
好きなシーンのオブジェクトにAddDebugSystems.csをアタッチ
追記
Jsonをusingでimportしてますが使ってないので記述を消して大丈夫です
見れる機能
ビルドしたUnityのバージョン
OS名
グラフィックス設定
システムメモリサイズ
ビデオメモリサイズ
スクリーンサイズ(width,height)
頂点数(若干不正確な可能性高め)
Console(debug.logとか見れる)
今後追加したいもの
DebugWindowのActive切り替え
ドローコール(できれば)
Menuのアクティブ切り替え
Recenter機能
がべこれ関係(Profilerから取得)
終わり
C#でEventManager作った
作った
そこらじゅうにActionを置くのと、どこからどの機能がコールバック発火して飛んでるのかわからんのが地獄すぎたので作成
GameManagerとかのMono非継承のstaticインスタンスあたりでnewすればUnityでも使えるよ
gistec74e89d9f146dd88d1959f3538fc2de
いい結果
Actionの宣言の大幅な削減に成功(keyに置き換わった)
EventManagerを全て経由するので、コールバックフローがLogで可視化できる
keyとAddEventとRemoveEventをBaseクラスにロジックとして仕込むことでRemove忘れのnull参照回避ができる
それぞれのActionに対して参照を得る必要がなくなった(最高)
悪い結果
keyが多い
引数ないのでカスタマイズ性がない
他の人がこれ使わないでAction追加してキレた
まとめ
総合的に見ると結構使いやすい
オーバーヘッドとオブジェクト志向の関係上大型プロジェクトには向かない
おわり。
C#のプロパティでスタックオーバーフローする話
最近
「プロパティの書き方わからない」
「書いたけどなんかアプリ落ちる」
「理由がわからない」
と、ジェットストリームアタックを受けたので
一人でも悲しみを減らし、僕の時間も増やすためにバッドノウハウを残します
コード
まずはこちらをごらんください
gist67a556915426e4d8e9a9f1a7ba4102be
一番上
もっとも短縮された形です
変数宣言とgetsetを同時に行っているので、適当にアクセス制限かける時に使えます
セッターをアクセス指定してよく使います
真ん中
動きません、アプリが即死します
なんでかというと、「プロパティの中でプロパティを参照する」からです
そのまま無限にプロパティを参照し続けてループします
C#初心者が必ずハマって死ぬのでここを見つけてくれることを祈ります
一番下
真ん中の正常に動くように書き直した形です
変数を宣言し、その変数に対してプロパティを作成しています
セッターにコールバックを仕込みたい!など
ロジックを組み込むときはこの形にしましょう
終わり