Unityで今すぐ使えるTips・コツ(Room2)
2020/9/5 13:30~ 学内勉強会
名前:山内龍我
大学:京都産業大学
学年:3年
役職:電子計算機応用部・主幹
趣味:バイク(SR400), Unity
クライアントエンジニア(志望)
自己紹介
@Yamauchi_Ryoga
自己紹介
目次
1. ゲームオブジェクトの参照の取り方(扱い方ゲームオブジェクト)
• Actionの使い方
2. 入出力の取り方
3. MVCのやり方(メイン)
4. シングルトンの使い方
5. オブザーバパターンの使い方
• Rx
• UniTask(時間があれば)
• DI(時間があれば)
お題:タイマーを作る
ゲームオブジェクトの参照の取り方
(正しくはゲームオブジェクト(にアタッチされているスクリプト)の参照の取り方)
みなさんはどうやってゲームオブジェクトの参照を取得していますか?
ゲームオブジェクトの参照の取り方
Cubeを作った時に、どうやってCubeをスクリプトで操りますか?
ゲームオブジェクトの参照の取り方
オブジェクトの子供にオブジェクトがある場合
ゲームオブジェクトの参照の取り方
GameObject.Find()は使っていませんよね
…?
[SerializeField]をつけると
ゲームオブジェクト側かオブジェクトを渡せる
(publicで公開してもいいけど、よくない)
ゲームオブジェクトの参照の取り方
エディタ上からオブジェクトを指定できる
オブジェクトの参照が取れたから
もうGameObject.Find()とかしなくていいじゃん。
ゲームオブジェクトの参照の取り方
タイマーを作る
タイマーを作る
とりあえず、エディタから入力された数値を表示してみる
タイマーを作る
できた🎉
タイマーを作る
Start()に関数を追加します
1秒ずつデクリメントして表示
表示
タイマーを作る
うごいた🎉
タイマーを作る
タイマーは完成しましたが、こんな要求をされました。
すまんが、ボタンから起動できるようにしてくれ!
タイマーを作る
言われると思って先に用意してたわ!よかった!
タイマーを作る
まさか、ボタン一つの機能を追加するのにエディターから指定してませんよね…?
タイマーを作る
こんな関数を作ってOnClick()に指定して起動する デメリット
• 指定したオブジェクトの関数しか指定できない
• いちいちエディタに戻って指定しないといけない
タイマーを作る
onClick.AddListenerを使おう!
クリックされた時の処理を事前に登録している
引数はAction型。
メリット
• OnClickのメソッドをprivateにできる
• エディターに戻って設定しなくてもいい
• 他のオブジェクトの関数を指定したくても、ここで渡せばいい
タイマーを作る
Actionとは、メソッド参照のこと(コールバックとして使うことも多い)
メソッドを変数的な感じで渡せる。
例えば、敵キャラを倒した時ちゃんとアニメーションを終えてからプレイヤーに経験値を入れたいとか
タイマーを作る
例えば、敵キャラを倒した時ちゃんとアニメーションを終えてからプレイヤーに経験値を入れたい時
タイマーを作る
プレイヤーがいるとして、
ダメージを食らったら時間が2秒減る機能が欲しいんや
ボタンから起動できるようになりましたが、こんな要求をされました。
タイマーを作る
そんなん簡単や、ダメージ受けた時に2秒時間が減るようにすればええんや。
タイマーを作る
画面を作って、プログラムを実装します、
タイマーを作る
さっきと同じように、PlayerにTimerViewの参照を持たせてあげればいいねん。
タイマーを作る
できた🎉
タイマーを作る
ここで疑問に思って欲しいこと
• PlayerViewって、Playerを制御するプログラムのはずなのにTimerViewまで持ってる…
• [SerializeField]で取得してきたけど、それができない場合はないの…?
ある。プログラムから自動生成した場合は違う方法で渡さないといけない。
PlayerはTimerの情報を持つべきではない
MVCとは
MVCの概念が登場する
• Playerの概念自体をレイヤーに分ける
• 描画(View)
• 他のコンポーネントとのやり取り(Controller)
• データ(Model)
ModelView
Controller
Controllerで制御することによって、PlayerView自体はTimerの参照を持たなくて良くなる。
Hp:10
At:5
Df:3
MVCとは
MVCにも種類がある
Push MVC Pull MVC
引用:http://super-apparel-engineer.hatenablog.com/entry/2016/10/11/102637
MVCとは
①入力(ダメージ)
ModelView
Controller
Player
ModelView
Controller
Timer
②Timerを2秒減らしたい
③2秒減らす
④Viewに変更を通知
⑤タイマーの秒数を描画
タイマーを作る
Playerのプログラムを作る
1.生成時にControllerも生
成
2.Modelも生成
3.Timerを減らす命
令
MVCとは
Timerのプログラムを作る
Viewが公開しているのはUpdateTimeメソッドだけ
ControllerはViewとModelの仲介役 Modelはビジネスロジックを書いてるだけ
テストが書けるようになるのがメリット
MVCとは
①入力(ダメージ)
ModelView
Controller
Player
ModelView
Controller
Timer
②Timerを2秒減らしたい
③2秒減らす
④Viewに変更を通知
⑤タイマーの秒数を描画
2. Modelが変更された時どうやってControllerに通知するの?
1. どうやってPlayerのControllerからTimerのModelの参照をとってくるの?
MVCとは
どうやってPlayerのControllerからTimerのModelの参照をとってくるの?
ModelView
Controller
ModelView
Controller
Player Timer
GameModel
Modelへの参照を統括するクラス
シングルトンで運用する場合が多い
シングルトンとは
GameModelがそれぞれのインスタンスを持っている
Staticなのでゲームモデル生成時にInstanceも生成 GameModel.Instanceで参照をとってこれる
これで他のゲームオブジェクトのModelをいじれるようになった🎉
MVCとは
①入力(ダメージ)
ModelView
Controller
Player
ModelView
Controller
Timer
②Timerを2秒減らしたい
③2秒減らす
④Viewに変更を通知
⑤タイマーの秒数を描画
2. Modelが変更された時どうやってControllerに通知するの?
IObserverとは
Modelが変更された時どうやってControllerに通知するの?
A.Observerパターンを使う
Subject Observer
①イベントの発行 ②イベントの購読
値が変更されたよ!通知出す その値でViewを変更するように先に処理
登録しとくから実行してね!
IObserverとは
TimerView TimerModelTimerController
↑OnUpdateTime()になってる
↑TimerControllerのコンストラクタで
Subscribe(購読)(処理の登録)をしている
Subject(イベント発行側)を作る→
IobservableでSubscribeを公開している→
Subject.OnNext()で通知を出している→
IObserverとは
これ、いわゆるRx(Reactive Extentions)的な考え方になっていくんですけど
Unityに標準で実装されているものにSubjectとかがない(自前で実装しないといけない)
(eventとかdelegateとかあるしそっちでもできるけどUniRxを推したい)
https://github.com/neuecc/UniRx/releases/download/7.1.0/UniRx.unitypacka
このライブラリは、SubjectからReactiveProperty、MessageBrocker、その他諸々実装されているので、
デザインパターンの勉強をして、正解をこのライブラリで答え合わせするのもいいかも
IObserverとは
このライブラリの作者neueさん
• UniTask
• Magic Onion
• MasterMemory
• ZString
MVCとは
①入力(ダメージ)
ModelView
Controller
Player
ModelView
Controller
Timer
②Timerを2秒減らしたい
③2秒減らす
④Viewに変更を通知
⑤タイマーの秒数を描画
Observer
シングルトン
実装できた🎉
IObserverとは
IObserverとは
まとめ
• 共同開発するためには、アーキテクチャ(MVCなど)が必要な場合がある。
• アーキテクチャを作ったことによって何かができなくなる時は、デザインパターンで解決できるか考える
• オブジェクトの振る舞いを考えてコードを書く
• このオブジェクトがするべきなのは表示。ロジックは持つべきではないとか。
• シングルトンを使ってみる
• 使い方や用途は他にもあるけど、多用は禁止
• オブザーバパターンを使ってみる
• 使い所を考えないとスパゲッティコードになる場合がある
• 使って放置しているとメモリリークする可能性がある
ご清聴ありがとうございました!
UniTask(UniRx.Async)
非同期のライブラリ
• Ienumeratorの代わり
• await asyncで制御できるUniTaskを発行できる
Coroutine
UniTask
クリック待ちをawaitできる WWWをawaitできる Coroutineをawaitできる
UniTask(UniRx.Async)
他にもいろいろとawaitで待つことができる
Stateがtrueの間待つ 値が変化するまで待つ 複数のUniTaskを待つ
キャンセル処理がめんどくさいデメリットもある…
CoroutineだとMonobehaviourからしか起動できないけど、
UniTaskはそうじゃないからキャンセルや止めるタイミングを
管理しなければならない。
効率よくなるけど、メモリリークの可能性も上がる
DI(Dependency Injection)
設計図をコンテナに渡しておく
Container
PlayerView
PlayerController
①PlayerControllerをコンテナに登録!
②PlayerControllerください!
③どうぞ!
DI(Dependency Injection)
↑設計図をコンテナに渡しておく
[Inject]でPlayerControllerを→
受け取る
自分で生成しなくてよくなる
メリット
• テストが書きやすくなる
• インスタンスの管理がしやすくなる
ご清聴ありがとうございました!

KC3_Room2_9_6

Editor's Notes

  • #7 それぞれのゲームオブジェクトに違うスクリプトをアタッチすると思います。すごく正しいです。 ここで、CubeのオブジェクトからImageのオブジェクトを操りたい時はどうしますか?
  • #8 GameObject.Find()で名前から検索はしてないですよね…? これ文字列からゲームオブジェクトを探してくるので、Updateとかで使うととっても重い処理になりますし、シーン上は同一nameのオブジェクトが存在できるので、例えば敵を生成した時に名前が一緒だとどっちを取得してくるかわからないです。
  • #13 ここから中身を作っていきます
  • #15 ここから中身を作っていきます
  • #16 ここから中身を作っていきます
  • #17 ここから中身を作っていきます
  • #18 ここから中身を作っていきます
  • #19 OnClickがpublicで公開されてしまう。 エディターに戻って毎回設定し直されないといけない。 ここで指定したい関数が他のオブジェクトの関数だったりするかもしれない
  • #20 ここから中身を作っていきます
  • #21 ここから中身を作っていきます
  • #22 ここから中身を作っていきます
  • #23 ここから中身を作っていきます
  • #24 ここから中身を作っていきます
  • #25 ここから中身を作っていきます
  • #26 ここから中身を作っていきます
  • #27 ここから中身を作っていきます
  • #28 ここから中身を作っていきます
  • #29 ここから中身を作っていきます
  • #30 ここから中身を作っていきます
  • #31 ここから中身を作っていきます
  • #32 ここから中身を作っていきます
  • #33 ここから中身を作っていきます
  • #34 ここから中身を作っていきます
  • #35 ここから中身を作っていきます
  • #36 ここから中身を作っていきます
  • #37 ここから中身を作っていきます
  • #38 Pub subとはちょっと違う。。。
  • #39 ここから中身を作っていきます
  • #40 Pub subとはちょっと違う。。。
  • #41 Pub subとはちょっと違う。。。
  • #42 ここから中身を作っていきます
  • #43 Pub subとはちょっと違う。。。
  • #44 Pub subとはちょっと違う。。。
  • #46 Pub subとはちょっと違う。。。
  • #47 Pub subとはちょっと違う。。。
  • #48 Pub subとはちょっと違う。。。
  • #49 Pub subとはちょっと違う。。。