Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
どこのご家庭にもあるシーンマネージャーの話
Search
いも
March 24, 2021
Programming
8.8k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
どこのご家庭にもあるシーンマネージャーの話
いも
March 24, 2021
More Decks by いも
See All by いも
UnityプログラミングバイブルR6号宣伝&Unity Logging小話
adarapata
0
650
Unityテスト活動のふりかえり
adarapata
1
700
Gather.townはいいぞ その後
adarapata
1
1.7k
Unityでの開発事例
adarapata
3
23k
Gather.townはいいぞ
adarapata
2
2.5k
宴はいいぞ
adarapata
0
2.2k
わかった気になるモブプログラミング
adarapata
1
180
モブワークっぽいのをやっている話/Trying mobwork
adarapata
2
1.3k
Zenjectを導入する前に
adarapata
0
4.1k
Other Decks in Programming
See All in Programming
Streamlitで実現する自然言語データアプリ開発
ayumu_yamaguchi
0
230
Claude Codeを組織的に動かして月400PRを実現した話
happy_ryo
0
270
LoopHub - ローカルで動く GitHub で、AI と共同開発
jugyo
1
540
新卒PdEのリアル
ryu1013
1
490
AWS Step Functions 大規模並列の壁を越える / jaws-sonic-2026-niigata-step-functions
kasacchiful
PRO
1
440
初心者DevRelとして参加者だった私が、DevRel Talks!#2に登壇するまでにしてきたこと
sokohirai
0
370
Jetpack Compose メカニズム
skydoves
0
150
Snowflakeで業務アプリを作ろう。 Snowflakeのアプリ機能解説&実践ガイド
ayumu_yamaguchi
1
270
What We Talk About When We Talk About XP
m_seki
2
580
モバイル交通系ICへのチャージ実例から考える、クロスプラットフォーム開発におけるiOS実機テスト設計とCI運用
yusuga
1
450
Security issues being discussed on Web Platforms
petamoriken
0
840
Vibes Containers 〜AIで変わるコンテナ設計と運用〜
tkikuc
3
530
Featured
See All Featured
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
0
230
Deep Space Network (abreviated)
tonyrice
0
300
Technical Leadership for Architectural Decision Making
baasie
3
560
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.8k
Optimizing for Happiness
mojombo
378
71k
Designing Experiences People Love
moore
143
24k
RailsConf 2023
tenderlove
30
1.5k
Navigating Algorithm Shifts & AI Overviews - #SMXNext
aleyda
1
1.6k
BBQ
matthewcrist
89
10k
Tell your own story through comics
letsgokoyo
1
1.1k
Building AI with AI
inesmontani
PRO
1
1.2k
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.6k
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