This repository was archived by the owner on Feb 12, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathSequenceManager.cs
More file actions
250 lines (218 loc) · 9.7 KB
/
SequenceManager.cs
File metadata and controls
250 lines (218 loc) · 9.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
using System;
using System.Collections;
using System.Collections.Generic;
using HyperCasual.Core;
using HyperCasual.Runner;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace HyperCasual.Gameplay
{
/// <summary>
/// This singleton determines the state of the game based on observed game events.
/// </summary>
[Serializable]
public class SequenceManager : AbstractSingleton<SequenceManager>
{
[SerializeField]
GameObject[] m_PreloadedAssets;
[SerializeField]
AbstractLevelData[] m_Levels;
[SerializeField]
GameObject[] m_LevelManagers;
public AbstractLevelData[] Levels => m_Levels;
[Header("Events")]
[SerializeField]
AbstractGameEvent m_ContinueEvent;
[SerializeField]
AbstractGameEvent m_BackEvent;
[SerializeField]
AbstractGameEvent m_WinEvent;
[SerializeField]
AbstractGameEvent m_LoseEvent;
[SerializeField]
AbstractGameEvent m_PauseEvent;
[SerializeField]
AbstractGameEvent m_SetupWalletEvent;
[SerializeField]
AbstractGameEvent m_MintEvent;
[SerializeField]
AbstractGameEvent m_UnlockedSkinEvent;
[SerializeField]
AbstractGameEvent m_CollectEvent;
[Header("Other")]
[SerializeField]
float m_SplashDelay = 2f;
readonly StateMachine m_StateMachine = new();
IState m_SplashScreenState;
IState m_MainMenuState;
IState m_LevelSelectState;
readonly List<IState> m_LevelStates = new();
public IState m_CurrentLevel;
SceneController m_SceneController;
/// <summary>
/// Initializes the SequenceManager
/// </summary>
public void Initialize()
{
m_SceneController = new SceneController(SceneManager.GetActiveScene());
InstantiatePreloadedAssets();
m_SplashScreenState = new State(ShowUI<SplashScreen>);
m_StateMachine.Run(m_SplashScreenState);
CreateMenuNavigationSequence();
CreateLevelSequences();
SetStartingLevel(0);
}
void InstantiatePreloadedAssets()
{
foreach (var asset in m_PreloadedAssets)
{
Instantiate(asset);
}
}
void CreateMenuNavigationSequence()
{
// Create states
var splashDelay = new DelayState(m_SplashDelay);
m_MainMenuState = new State(OnMainMenuDisplayed);
m_LevelSelectState = new State(OnLevelSelectionDisplayed);
//Connect the states
m_SplashScreenState.AddLink(new Link(splashDelay));
splashDelay.AddLink(new Link(m_MainMenuState));
m_MainMenuState.AddLink(new EventLink(m_ContinueEvent, m_LevelSelectState));
m_LevelSelectState.AddLink(new EventLink(m_BackEvent, m_MainMenuState));
}
void CreateLevelSequences()
{
m_LevelStates.Clear();
//Create and connect all level states
IState lastState = null;
foreach (var level in m_Levels)
{
IState state = null;
if (level is SceneRef sceneLevel)
{
state = CreateLevelState(sceneLevel.m_ScenePath);
}
else
{
state = CreateLevelState(level);
}
lastState = AddLevelPeripheralStates(state, m_LevelSelectState, lastState);
}
//Closing the loop: connect the last level to the level-selection state
var unloadLastScene = new UnloadLastSceneState(m_SceneController);
lastState?.AddLink(new EventLink(m_ContinueEvent, unloadLastScene));
unloadLastScene.AddLink(new Link(m_LevelSelectState));
var setupWalletState = new PauseState(ShowUI<SetupWalletScreen>);
var mintState = new PauseState(ShowUI<MintScreen>);
var unlockedSkinState = new PauseState(ShowUI<UnlockedSkinScreen>);
var collectedSkinState = new PauseState(ShowUI<CollectedSkinScreen>);
lastState?.AddLink(new EventLink(m_SetupWalletEvent, setupWalletState
));
lastState?.AddLink(new EventLink(m_UnlockedSkinEvent, unlockedSkinState));
setupWalletState.AddLink(new EventLink(m_MintEvent, mintState));
setupWalletState.AddLink(new EventLink(m_ContinueEvent, unloadLastScene));
mintState.AddLink(new EventLink(m_ContinueEvent, unloadLastScene));
unlockedSkinState.AddLink(new EventLink(m_ContinueEvent, unloadLastScene));
unlockedSkinState.AddLink(new EventLink(m_CollectEvent, collectedSkinState));
collectedSkinState.AddLink(new EventLink(m_ContinueEvent, unloadLastScene));
}
/// <summary>
/// Creates a level state from a scene
/// </summary>
/// <param name="scenePath"></param>
/// <returns></returns>
IState CreateLevelState(string scenePath)
{
return new LoadSceneState(m_SceneController, scenePath);
}
/// <summary>
/// Creates a level state from a level data
/// </summary>
/// <param name="levelData"></param>
/// <returns></returns>
IState CreateLevelState(AbstractLevelData levelData)
{
return new LoadLevelFromDef(m_SceneController, levelData, m_LevelManagers);
}
IState AddLevelPeripheralStates(IState loadLevelState, IState quitState, IState lastState)
{
//Create states
m_LevelStates.Add(loadLevelState);
var gameplayState = new State(() => OnGamePlayStarted(loadLevelState));
var winState = new PauseState(() => OnWinScreenDisplayed(loadLevelState));
var loseState = new PauseState(ShowUI<GameoverScreen>);
var pauseState = new PauseState(ShowUI<PauseMenu>);
var unloadLose = new UnloadLastSceneState(m_SceneController);
var unloadPause = new UnloadLastSceneState(m_SceneController);
var setupWalletState = new PauseState(ShowUI<SetupWalletScreen>);
var mintState = new PauseState(ShowUI<MintScreen>);
var unlockedSkinState = new PauseState(ShowUI<UnlockedSkinScreen>);
var collectedSkinState = new PauseState(ShowUI<CollectedSkinScreen>);
//Connect the states
lastState?.AddLink(new EventLink(m_ContinueEvent, loadLevelState));
lastState?.AddLink(new EventLink(m_SetupWalletEvent, setupWalletState
));
lastState?.AddLink(new EventLink(m_UnlockedSkinEvent, unlockedSkinState));
loadLevelState.AddLink(new Link(gameplayState));
gameplayState.AddLink(new EventLink(m_WinEvent, winState));
gameplayState.AddLink(new EventLink(m_LoseEvent, loseState));
gameplayState.AddLink(new EventLink(m_PauseEvent, pauseState));
loseState.AddLink(new EventLink(m_ContinueEvent, loadLevelState));
loseState.AddLink(new EventLink(m_BackEvent, unloadLose));
unloadLose.AddLink(new Link(quitState));
pauseState.AddLink(new EventLink(m_ContinueEvent, gameplayState));
pauseState.AddLink(new EventLink(m_BackEvent, unloadPause));
unloadPause.AddLink(new Link(m_MainMenuState));
setupWalletState.AddLink(new EventLink(m_MintEvent, mintState));
setupWalletState.AddLink(new EventLink(m_ContinueEvent, loadLevelState));
mintState.AddLink(new EventLink(m_ContinueEvent, loadLevelState));
unlockedSkinState.AddLink(new EventLink(m_ContinueEvent, loadLevelState));
unlockedSkinState.AddLink(new EventLink(m_CollectEvent, collectedSkinState));
collectedSkinState.AddLink(new EventLink(m_ContinueEvent, loadLevelState));
return winState;
}
/// <summary>
/// Changes the starting gameplay level in the sequence of levels by making a slight change to its links
/// </summary>
/// <param name="index">Index of the level to set as starting level</param>
public void SetStartingLevel(int index)
{
m_LevelSelectState.RemoveAllLinks();
m_LevelSelectState.AddLink(new EventLink(m_ContinueEvent, m_LevelStates[index]));
m_LevelSelectState.AddLink(new EventLink(m_BackEvent, m_MainMenuState));
m_LevelSelectState.EnableLinks();
}
void ShowUI<T>() where T : View
{
UIManager.Instance.Show<T>();
}
void OnMainMenuDisplayed()
{
ShowUI<MainMenu>();
AudioManager.Instance.PlayMusic(SoundID.MenuMusic);
}
void OnWinScreenDisplayed(IState currentLevel)
{
UIManager.Instance.Show<LevelCompleteScreen>();
var currentLevelIndex = m_LevelStates.IndexOf(currentLevel);
if (currentLevelIndex == -1)
throw new Exception($"{nameof(currentLevel)} is invalid!");
var levelProgress = SaveManager.Instance.LevelProgress;
if (currentLevelIndex == levelProgress && currentLevelIndex < m_LevelStates.Count - 1)
SaveManager.Instance.LevelProgress = levelProgress + 1;
}
void OnLevelSelectionDisplayed()
{
ShowUI<LevelSelectionScreen>();
AudioManager.Instance.PlayMusic(SoundID.MenuMusic);
}
void OnGamePlayStarted(IState current)
{
m_CurrentLevel = current;
ShowUI<Hud>();
AudioManager.Instance.StopMusic();
MemoryCache.CurrentLevel = m_LevelStates.IndexOf(current) + 1;
}
}
}