Skip to content

Commit e144bec

Browse files
authored
GameStates converted from enums to structs and classes (#26)
* Changes Made + Persistent Inventory Items Saving + Bag Refactored from SO to Serializable Class + Custom Json Serializer for SOs using Addressable + Small Utils Edits and Bug Fixes * Changes Made + Lighting regenerated for game scene + Small modifications and added burst project settings files * Refactored Functions in to states (just renames) * Updated Unity version to v2022 LTS * checkpoint * checkpoint, refactored StateStatus enum to a bool IsEnabled * added refactored and tested new state transitions * pooling abstraction implemented, moved SerializableVector3.cs to Data package to fix core dependency compile error * implemented spawner to hit effect on weapons * Changes made - Added serialized dictionary as an attribute to Generic Dictionary - More improvements to Spawner * checkpoint * finished #16 * small DeSpawn fix for Spawner.cs * EventBus implemented * EventBus.cs implemented/refactored into Project * namespace and class renames * revert from merge * GameState converted from enums to struct/class
1 parent c8c2879 commit e144bec

File tree

20 files changed

+294
-140
lines changed

20 files changed

+294
-140
lines changed

Packages/com.ekaka.core/Runtime/Common/EventParams.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,15 @@ public struct GameManagerReady : IEventParams
1111
{
1212
}
1313

14+
public struct GameStateEnabled<T> : IEventParams where T : IGameState
15+
{
16+
}
17+
1418
public struct GameStateChanged : IEventParams
1519
{
16-
public GameState State { get; private set; }
17-
18-
public GameStateChanged(GameState state)
20+
public IGameState State { get; private set; }
21+
22+
public GameStateChanged(IGameState state)
1923
{
2024
State = state;
2125
}

Packages/com.ekaka.core/Runtime/Common/Utils.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,18 @@ public static T Cast<T>(object obj)
109109
}
110110
}
111111

112+
public static bool FindIndex<T>(this T[] array, Predicate<T> predicate, out int index)
113+
{
114+
index = Array.FindIndex(array, predicate);
115+
116+
return index != - 1;
117+
}
118+
119+
public static string TypeName(this object obj)
120+
{
121+
return obj?.GetType().Name;
122+
}
123+
112124
public static float NormalizeValue(float value, float lowerLimit, float upperLimit)
113125
{
114126
float cachedValue = value;
@@ -240,7 +252,7 @@ public static bool IsNullOrEmpty(this Array array)
240252

241253
public static bool IsType(this object obj, object compareObj)
242254
{
243-
return obj.GetType() == compareObj.GetType();
255+
return obj != null ? obj.GetType() == compareObj.GetType() : compareObj == null;
244256
}
245257

246258
public static string[] GetAllSceneNamesInBuildSettings()
Lines changed: 90 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,9 @@
11
using System;
2-
using System.Collections;
3-
using System.Collections.Generic;
4-
using System.Linq;
52
using Core.Common;
6-
#if UNITY_EDITOR
7-
using UnityEditor;
8-
#endif
93
using UnityEngine;
104

115
namespace Core.Game
126
{
13-
public enum GameState
14-
{
15-
//happens only once when game is first loaded on start
16-
//used to load assets and initialize GameManager
17-
Initializing,
18-
//when loading between scenes or game states
19-
//from landing to play from game scene to menu...
20-
Loading,
21-
//first landing scene (main menu)
22-
Landing,
23-
//in game scene/playing game
24-
Play,
25-
//when game is paused - still in game scene
26-
Pause,
27-
//when game is over (Player is dead) - still in game scene
28-
GameOver,
29-
//onApplicationQuit (maybe use for dispose/garbage collection)
30-
Quitting
31-
}
32-
337
//run before everything else
348
[DefaultExecutionOrder(- 1)]
359
public class GameManager : Singleton<GameManager>
@@ -54,13 +28,25 @@ private void InvokeReady()
5428
IsReady = true;
5529
}
5630

31+
// Add new GameStates here.
32+
private IGameState[] AllStates => new IGameState[]{
33+
new Loading(),
34+
new Landing(),
35+
new Play(),
36+
new Pause(),
37+
new GameOver(),
38+
new Quitting()
39+
};
40+
41+
private int _currentStateIndex = - 1;
42+
5743
[field: SceneList] [field: SerializeField] public int LandingScene { get; private set; }
5844

5945
[field: SceneList] [field: SerializeField] public int GameScene { get; private set; }
6046

61-
public GameState State { get; private set; } = GameState.Initializing;
47+
public IGameState CurrentState => _currentStateIndex < 0 ? null : AllStates[_currentStateIndex];
6248

63-
public bool InGame => State == GameState.Play || State == GameState.Pause || State == GameState.GameOver;
49+
public bool InGame => CurrentState is IInGameState;
6450

6551
private void Start()
6652
{
@@ -71,175 +57,167 @@ private void Initialize()
7157
{
7258
//all other managers are already initialized OnEnable
7359
InvokeReady();
60+
61+
// use for loop since states are mostly structs.
62+
for (int i = 0; i < AllStates.Length; i++)
63+
{
64+
AllStates[i].Initialize();
65+
}
7466

7567
//now it has finished initializing change state to loading - loading landing scene
76-
ChangeGameState(GameState.Loading);
68+
ChangeGameState<Loading>();
7769

7870
//load first/landing scene
79-
Common.Utils.LoadScene(LandingScene, delegate { ChangeGameState(GameState.Landing); });
71+
Utils.LoadScene(LandingScene, ChangeGameState<Landing>);
8072
}
8173

82-
private void ChangeGameState(GameState newState)
74+
private void ChangeGameState<T>() where T : IGameState
8375
{
84-
if (newState == State)
76+
if (!AllStates.FindIndex( s => s is T, out int index))
77+
{
78+
Debug.LogError($"{nameof(IGameState)} of type {typeof(T).Name} not found.");
79+
80+
return;
81+
}
82+
83+
if (_currentStateIndex == index)
84+
{
85+
Debug.LogWarning($"{nameof(IGameState)} already {CurrentState}.");
86+
87+
return;
88+
}
89+
90+
IGameState newState = AllStates[index];
91+
92+
if (!newState.IsReady)
8593
{
86-
Debug.LogWarning($"{nameof(GameState)} already {State}");
94+
Debug.LogWarning($"{typeof(T).Name} {nameof(IGameState)} is not ready.");
8795

8896
return;
8997
}
9098

91-
Debug.Log($"{nameof(GameState)} changed from {State} to {newState}");
99+
// Disable previous state.
100+
if (_currentStateIndex != - 1)
101+
{
102+
AllStates[_currentStateIndex].Disable();
103+
}
104+
105+
Debug.Log($"{nameof(IGameState)} changed from {CurrentState.TypeName()} to {newState.TypeName()}.");
106+
107+
_currentStateIndex = index;
108+
109+
newState.Enable();
110+
111+
// Update current state reference since states can be structs.
112+
AllStates[_currentStateIndex] = newState;
92113

93-
State = newState;
114+
EventBus<GameStateEnabled<T>>.Invoke();
94115

95-
EventBus<GameStateChanged>.Invoke(new GameStateChanged(State));
116+
EventBus<GameStateChanged>.Invoke(new GameStateChanged(CurrentState));
96117
}
97118

98119
public void StartGame(bool continued)
99120
{
100121
if (continued)
101122
{
102-
ContinueGame();
123+
LoadSavedGame();
103124
}
104125

105126
else
106127
{
107-
StartNewGame();
128+
LoadNewGame();
108129
}
109130
}
110131

111132
//load persistent data first
112-
private void ContinueGame(bool reload = false)
133+
private void LoadSavedGame(bool tryAgain = false)
113134
{
114135
//change to loading until scene loads async
115-
ChangeGameState(GameState.Loading);
136+
ChangeGameState<Loading>();
116137

117-
Debug.Log("Loading Game...");
138+
Debug.Log("Loading Saved Game...");
118139

119140
//load game scene and call onSceneLoaded
120-
Common.Utils.LoadScene(GameScene, NewGameStarted, reload);
141+
Utils.LoadScene(GameScene, GameStarted, tryAgain);
121142
}
122143

123-
private void StartNewGame()
144+
private void LoadNewGame()
124145
{
125146
//change to loading until scene loads async
126-
ChangeGameState(GameState.Loading);
147+
ChangeGameState<Loading>();
127148

128149
Debug.Log("Loading New Game...");
129150

130151
//load game scene and call onSceneLoaded
131-
Common.Utils.LoadScene(GameScene, NewGameStarted);
152+
Utils.LoadScene(GameScene, GameStarted);
132153
}
133154

134155
//when game scene finished loading
135-
void NewGameStarted()
156+
void GameStarted()
136157
{
137-
ChangeGameState(GameState.Play);
158+
ChangeGameState<Play>();
138159

139160
Debug.Log("Loaded New Game");
140161
}
141162

142163
public void ExitGame()
143164
{
144-
#if UNITY_EDITOR
145-
EditorApplication.isPlaying = false;
146-
#else
147-
Application.Quit();
148-
#endif
165+
ChangeGameState<Quitting>();
149166
}
150167

151168
//leave/unload game scene and load to Landing scene
152169
public void ExitToMainMenu()
153-
{
154-
if (InGame)
155-
{
156-
//change to loading until scene loads async
157-
ChangeGameState(GameState.Loading);
158-
159-
Debug.Log($"exiting {nameof(GameScene)}...");
160-
161-
//load landing scene and call onSceneLoaded
162-
Common.Utils.LoadScene(LandingScene, GameExited);
163-
}
164-
165-
else
166-
{
167-
Debug.LogError($"can't exit {nameof(GameScene)} when {nameof(GameState)} is not an {nameof(InGame)} {State}");
168-
}
169-
}
170-
171-
public void TryAgain()
172170
{
173171
if (!InGame)
174172
{
175-
Debug.LogError("Can't Not in Game.");
173+
Debug.LogError($"can't exit when {nameof(CurrentState)} is not an {nameof(IInGameState)}.");
176174

177175
return;
178176
}
179177

180-
GameExited();
178+
//change to loading until scene loads async
179+
ChangeGameState<Loading>();
181180

182-
ContinueGame(true);
181+
Debug.Log($"exiting {nameof(GameScene)}...");
182+
183+
//load landing scene and call onSceneLoaded
184+
Utils.LoadScene(LandingScene, GameExited);
185+
}
186+
187+
public void TryAgain()
188+
{
189+
LoadSavedGame(true);
183190
}
184191

185192
//called once landing scene is loaded
186193
private void GameExited()
187194
{
188-
Debug.Log($"Exited {nameof(GameScene)}");
195+
Debug.Log($"Exited {nameof(GameScene)}.");
189196

190-
ChangeGameState(GameState.Landing);
191-
192-
//reset timeScale in case it was exited in pause
193-
Time.timeScale = 1f;
197+
ChangeGameState<Landing>();
194198
}
195199

196200
public void PauseGame()
197201
{
198-
//pause only from GameState.Play
199-
if (State != GameState.Play)
200-
{
201-
Debug.LogWarning($"can't {nameof(PauseGame)} when {nameof(GameState)} is {State}");
202-
203-
return;
204-
}
205-
206-
Time.timeScale = 0f;
207-
208-
ChangeGameState(GameState.Pause);
202+
ChangeGameState<Pause>();
209203
}
210204

211205
public void GameOver()
212206
{
213-
if (!InGame)
214-
{
215-
Debug.LogWarning($"can't {nameof(GameOver)} when {nameof(GameState)} is {State}");
216-
217-
return;
218-
}
219-
220-
Time.timeScale = 0f;
221-
222-
ChangeGameState(GameState.GameOver);
207+
ChangeGameState<GameOver>();
223208
}
224209

225210
public void ResumeGame()
226211
{
227-
//resume only from GameState.Pause
228-
if (State != GameState.Pause)
229-
{
230-
Debug.LogWarning($"can't {nameof(ResumeGame)} when {nameof(GameState)} is {State}");
231-
232-
return;
233-
}
234-
235-
Time.timeScale = 1f;
236-
237-
ChangeGameState(GameState.Play);
212+
ChangeGameState<Play>();
238213
}
239214

240215
private void OnApplicationQuit()
241216
{
242-
ChangeGameState(GameState.Quitting);
217+
if (!(CurrentState is Quitting))
218+
{
219+
ChangeGameState<Quitting>();
220+
}
243221
}
244222
}
245223
}

Packages/com.ekaka.core/Runtime/Game/GameState.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)