Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up for free
どこのご家庭にもあるシーンマネージャーの話
いも
March 24, 2021
Programming
1
2k
どこのご家庭にもあるシーンマネージャーの話
いも
March 24, 2021
Tweet
Share
More Decks by いも
See All by いも
Unityテスト活動のふりかえり
adarapata
1
260
Gather.townはいいぞ その後
adarapata
1
740
Unityでの開発事例
adarapata
4
17k
Gather.townはいいぞ
adarapata
2
1.9k
宴はいいぞ
adarapata
0
820
わかった気になるモブプログラミング
adarapata
1
25
モブワークっぽいのをやっている話/Trying mobwork
adarapata
2
970
Zenjectを導入する前に
adarapata
0
3.2k
Zenject Example SubContainer
adarapata
1
8.6k
Other Decks in Programming
See All in Programming
Beyond Micro Frontends: Frontend Moduliths for the Enterprise @enterjs2022
manfredsteyer
PRO
0
110
シェーダー氷山発掘記
logilabo
0
140
GDG Seoul IO Extended 2022 - Android Compose
taehwandev
0
280
はじめてのプルリク - BLEA 編
watany
0
140
Android Tools & Performance
takahirom
1
420
Keeping your team in top shape with the Gradle Enterprise API
runningcode
3
120
Improving Developer Experience Through Tools and Techniques 2022
krzysztofzablocki
0
400
Reactアプリケーションのテスト戦略
0906koki
10
4.6k
開発速度を5倍早くするVSCodeの拡張機能を作った
purp1eeeee
2
140
JSのウェブフレームワークで高速なルーターを実装する方法
usualoma
1
1.6k
Power Automateドリブンのチームマネジメント
hanaseleb
0
180
Make the most of Django - PyCon Italia 2022
pauloxnet
0
110
Featured
See All Featured
Gamification - CAS2011
davidbonilla
75
3.9k
Intergalactic Javascript Robots from Outer Space
tanoku
261
25k
Bash Introduction
62gerente
597
210k
The MySQL Ecosystem @ GitHub 2015
samlambert
238
11k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
37
3.2k
Pencils Down: Stop Designing & Start Developing
hursman
112
9.8k
Stop Working from a Prison Cell
hatefulcrawdad
261
17k
The World Runs on Bad Software
bkeepers
PRO
57
5.3k
Statistics for Hackers
jakevdp
781
210k
Debugging Ruby Performance
tmm1
65
10k
A Tale of Four Properties
chriscoyier
149
21k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_i
23
15k
Transcript
━━━ どのご家庭にもある シーンマネージャーの話 いも ━━━ 2021/03/24 Gotanda.unity #17 1
いもです twitter @adarapata Unity触ったりしています Godot Engineも好きです 2021/03/24 Gotanda.unity #17 2
モチベーション 画⾯遷移の管理の仕組みを毎回作っている気がする みんな各⾃で似たようなもの作ってる気がする しかしあまり公開されてる気がしない 話すからみんなも教えて下さい 2021/03/24 Gotanda.unity #17 3
シーンマネージャー is Unityでの「画⾯をいい感じに管理してくれる」君 画⾯の単位を定義して管理する 1Sceneとか1Prefabとか 画⾯をスタックできる 前の画⾯に戻ったりとか 画⾯遷移にデータを渡せる 前の画⾯で選択した設定でクエストに挑むとか 2021/03/24
Gotanda.unity #17 4
Unityデフォルトでの画⾯管理 Sceneファイルの切り替え・追加は可能 Prefabはデフォルトではない 画⾯の名称の管理が必要 遷移先の⽂字列 or Indexをどう持つか。増えたらどうするか パラメータを渡す⼿段がデフォルトではない スタックする機能はない ⼀個前の画⾯の状態を保持させるなど
この辺を解決するために画⾯管理クラスを作ったりする 2021/03/24 Gotanda.unity #17 5
解決したいこと 画⾯をスタックできること パラメータを渡せること 名称の管理が楽なこと 2021/03/24 Gotanda.unity #17 6
⾃作の⼀例 : PageManager 画⾯のことを「Page」と呼ぶ SceneはUnityの呼称とかぶるのでPageにした 1Page = 1Prefab Page Prefabを動的にロードして追加する
Pageをスタックしており、前のPageに戻れる 遷移先Pageを型で呼ぶ パラメータを型で渡せる 依存関係の解決にVContainerを使⽤ 2021/03/24 Gotanda.unity #17 7
呼び⽅ var parameter = new FooPage.CreateParameter { Bar = "bar"
}; _pageManager.Push(new FooPage.Transition { Parameter = parameter }); // 追加 _pageManager.Pop(); // ⼀つ前に戻る _pageManager.Replace(new FooPage.Transition { Parameter = parameter }); // 現在のページを破棄して追加する // スタックしたページをすべて破棄して追加する _pageManager.ReplaceAll(new FooPage.Transition { Parameter = parameter }); await _pageManager.PushAsync(new FooPage.Transition { Parameter = parameter }); // ⾮同期で追加 2021/03/24 Gotanda.unity #17 8
Page定義側 [PageAsset("BarPage.prefab")] public class BarPage : BasePage { public class
Transition : BasePageTransition<BarPage>{} } 2021/03/24 Gotanda.unity #17 9
登場⼈物 PageManager : ページのスタック・ライフサイクル管理者 IPageTransition : ページ遷移者 BasePage : ページ本体
2021/03/24 Gotanda.unity #17 10
クラス図 2021/03/24 Gotanda.unity #17 11
PageManager Pageのスタックを管理する リストで保持してる 読み込まれたPageに対して初期化・停⽌というライフサイクルイベ ントを呼んであげるのが役割 具体的にどうやってPageが読み込まれるのかは知らない public async UniTask PushAsync(IPageTransition
transition) { var page = await transition.LoadPage(); await page.Initialize(); _pages.Add(page); // ページリストの管理 } 2021/03/24 Gotanda.unity #17 12
処理の流れ 2021/03/24 Gotanda.unity #17 13
ライフサイクル Unityのライフサイクルに合わせるとハンドリングしにくい StartはPageManager側から⾒て初期化済みか保証できない Destroyで破棄はできるが⼀時停⽌とか再開がない なのでざっくりと4つのライフサイクルイベントを⽤意 Initialize Suspend Resume Discard 2021/03/24
Gotanda.unity #17 14
Pushすると、現在のPageのSupend、新しいPageのInitializeが呼ばれ る Popすると、現在のPageのSuspend->Discard、⼀つ前のPageの Resumeが呼ばれる 2021/03/24 Gotanda.unity #17 15
BasePage 画⾯⾃体を司るクラス ライフサイクルを実装しており、初期化とか停⽌とかできる PageManagerとか外の世界とのやり取りを⾏う際の受け⼝ なので内部はMVCとかMVPとか好きに分割してる 2021/03/24 Gotanda.unity #17 16
public abstract class BasePage { public virtual UniTask Initialize(); public
virtual UniTask Suspend(); public virtual UniTask Resume(); public virtual UniTask Discard(); } public abstract class BasePage<TParam> : BasePage { protected TParam Parameter { get; } } 2021/03/24 Gotanda.unity #17 17
IPageTransition Pageの呼び出し⽅を知っているやつ PageManagerが直接Pageの呼び出しを⾏うのではなく IPageTransitionに具体的な呼び出しをお任せする public class PageTransitionBase<TPage> : IPageTransition where
TPage : BasePage { public virtual async UniTask<PageBase> LoadPage() { var pageInstance = await DoPrefabLoad(pageAssetName); var pageLifetimeScope = pageInstance.GetComponent<LifetimeScope>(); InitializePageParameter(pageLifetimeScope); pageLifetimeScope.Build(); // Page側の依存関係解決 var page = pageLifetimeScope.Container.Resolve<TPage>(); return page; } } 2021/03/24 Gotanda.unity #17 18
リソースとクラスのマッピング どのアセットを引っ張ってくるのかパスを渡したい 毎回⼿打ちで渡したくはない クラス定義とPageアセットは原則1:1と考えて良い // pageAssetNameをどう渡すか var pageInstance = await
DoPrefabLoad(pageAssetName); カスタムアトリビュートで直接紐付けてしまう 2021/03/24 Gotanda.unity #17 19
[AttributeUsage(AttributeTargets.Class, Inherited = false)] public class PageAssetAttribute : Attribute {
public string PrefabName { get; } public PageAssetAttribute(string prefabName) { this.PrefabName = prefabName; } } [PageAsset("BarPage.prefab")] public class BarPage : BasePage { public class Transition : BasePageTransition<BarPage>{} } // PageAssetAttributeを取り出す var pageNameAttr = Attribute.GetCustomAttribute(typeof(TPage), typeof(PageAssetAttribute)) as PageAssetAttribute; var pageInstance = await DoPrefabLoad(pageNameAttr.PrefabName); 2021/03/24 Gotanda.unity #17 20
パラメータ渡し [PageAsset("FooPage.prefab")] public class FooPage : BasePage<FooPage.CreateParameter> { public class
CreateParameter { public string Bar; } public class Transition : BasePageTransition<FooPage, CreateParameter> { } } ジェネリクスで定義できるようにする 2021/03/24 Gotanda.unity #17 21
そもそも外部パラメータをどう扱っているのか public class LifetimeScopeWithParameter<TParam> : LifetimeScope { public TParam Param;
protected override void Configure(IContainerBuilder builder) { builder.RegisterInstance(Param); } } 外からパラメータを設定できるようなLifetimeScopeを⽤意 2021/03/24 Gotanda.unity #17 22
パラメータを設定した上でBuildする public class BasePageTransition<TPage> : IPageTransition where TPage : BasePage
{ public virtual async UniTask<PageBase> LoadPage() { var pageInstance = await DoPrefabLoad(pageAssetName); var pageLifetimeScope = pageInstance.GetComponent<LifetimeScope>(); InitializePageParameter(pageLifetimeScope); pageLifetimeScope.Build(); // Page側の依存関係解決 var page = pageLifetimeScope.Container.Resolve<TPage>(); return page; } protected virtual void InitializePageParameter(LifetimeScope container) { } } public class BasePageTransition<TPage, TParam> : PageTransitionBase<TPage> where TPage : BasePage<TParam> { public TParam Parameter { get; set; } protected override void InitializePageParameter(LifetimeScope scope) { if (scope is LifetimeScopeWithParameter<TParam> s) { s.Parameter = Parameter; } } } 2021/03/24 Gotanda.unity #17 23
PageのアセットにLifetimeScopeをアタッチする public class FooLifetimeScope : LifetimeScopeWithParameter<FooPage.CreateParameter> { [SerializeField] private FooView
_fooView; protected override void Configure(IContainerBuilder builder) { base.Configure(builder); builder.Register<FooPage>(Lifetime.Scoped); builder.Register<FooPresenter>(Lifetime.Scoped); builder.Register<FooModel>(Lifetime.Scoped); builder.RegisterComponent(_fooView); } } これでPageのオブジェクトに外部データをInjectionできる 2021/03/24 Gotanda.unity #17 24
好きなところ 型ベースで画⾯遷移を⾏える 定数を管理しなくていい 渡すべきパラメータも型で管理できるので楽 コード⾒ればリソースがわかる 1:1の関係なら密接でもいいんじゃない派 2021/03/24 Gotanda.unity #17 25
PageManagerまとめ 遷移先をクラス名で指定できる パラメータも型で定義して渡せる Managerから詳細な遷移処理を切り出している Pageは独⾃にライフサイクルを持たせている クラスとアセットをカスタムアトリビュートで紐付けしている 2021/03/24 Gotanda.unity #17 26
みなさんの 画⾯遷移マネージャーの話を お待ちしています 2021/03/24 Gotanda.unity #17 27