C#でpartialを使ってクラスの中身を分割する

 

こんにちは。

 

開発が進んでいくと、一つのクラスの中身が膨大な行数になることがあると思います。

その理由は様々あり、解決策もまた様々あると思います。

 

その中で、今回はpartialを使ってクラスを分割するということを行います。

 

どのような時にpartialを使うのか

まず、クラスの中身が膨大な行数になっていく場面はいつなのかを考えます。

  1. クラスの役割を明確に分けられておらず、なんでもできる神クラスになっている
  2. 役割は明確だが、メソッドなどが抽象化できていないので同じ処理を複数回書いている
  3. 役割も明確で抽象化もできているが、仕様が多い

 

1の場合はまずクラスの役割を定めましょう。partialで分けるとさらに可読性が低くなります。

2の場合はまず同じメソッドを呼び出していないか、同じ計算を書いていないかを探して最適化しましょう。DRY原則を守れの一言に尽きます。

3の場合。お待たせしました、partialの出番です。

 

そもそもpartialってなんぞ

partial (型) (C# リファレンス)

これ(投げやり)

 

クラスの定義を、複数ファイルにまたいで行うことができます。

例として、ある特定のクラス内で使用するStateの中身をpartialで追加していきます。

 

gist3c692f67badadfc5e98a8f8abd8480a1

 

こんな感じです。

これだけだと分かりづらいかもしれませんが、このStateを継承したState1やState2というクラスはこのソースに帰属しているということがわかるので、メンテナンス性や拡張性も向上します。

 

 最後

使用方法を間違えると、スパゲッティになりがちなので要注意です。

適切な場所で使いましょう。

 

おわり

デジゲー博とコミケに申し込んだ話

 

タイトルの通り申し込みました

オープンワールド(に頑張ればなってる)3DのARPGを開発してます

 

サークル名は申し込み時に適当に決めたので今後変わるかもしれません

今は「PhantomIsland」です、マボロシ島です、レアな木の実はなってません(わかる人いるのかな)

 

デジゲー博

f:id:yutakaseda3216:20160830095148p:plain

こんなサークルカットで出てると思います

多分展示だけです

 

コミケ

f:id:yutakaseda3216:20160830095339p:plain

 

受かればこれが出てると思います

完成版を頒布予定です

 

ゲームの中身

本気で作ってるのでお楽しみに

 

終わり

 

うちのプランナー兼デザイナーの渾身の作品

f:id:yutakaseda3216:20160830095951p:plain

 

宜しくお願いします。

 

UnityのStateMachineBehaviourについてのメモ

 

 こっちを読んでください

 

yutakaseda3216.hatenablog.com

 

 

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でアニメーション遷移するときの自分なりの解

こっちも読んでください

 

yutakaseda3216.hatenablog.com

 

 
設計の指標なので、なんとなく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 追記

qiita.com

 

こんなものがあった。

併用してアニメーション遷移の汎用コンポーネント作りたい

 

2017/4月の追記

制御コンポーネントを作成して適用してみた(年明け前くらい)

いい感じだけど、NormalizedTimeが機能しなかったりして自前で実装した

 

f:id:yutakaseda3216:20170404113601p:plain

 

右側のPlayerStateTransitionはStateMachineBehaviour継承したクラスで

・Inputの入力受付時間

・ステートの自動終了時間

・ステートのキャンセル時間

・ステートのキャンセル先と優先度登録

 

とかできるようになってて、遷移先の切り替えが楽になった

やったね

Unity+VRの開発用DebugConsoleを作った

 

こんにちは

 

GearVR向けアプリのビルド後にDebug.Logが確認したかったり、頂点数やFPSを見たかったりしたので作りました

FPSみたいだけならOculusSDKのプラグイン入れた方がいいかも

 

UnityPackageはここ

www.dropbox.com

 

使い方

BuildSettingsにDebugシーンを追加

好きなシーンのオブジェクトにAddDebugSystems.csをアタッチ

追記
Jsonをusingでimportしてますが使ってないので記述を消して大丈夫です

 

見れる機能

ビルドしたUnityのバージョン

OS名

グラフィックス設定

システムメモリサイズ

ビデオメモリサイズ

スクリーンサイズ(width,height)

頂点数(若干不正確な可能性高め)

FPS

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#初心者が必ずハマって死ぬのでここを見つけてくれることを祈ります

 

一番下

真ん中の正常に動くように書き直した形です

変数を宣言し、その変数に対してプロパティを作成しています

セッターにコールバックを仕込みたい!など

ロジックを組み込むときはこの形にしましょう

 

終わり