Skip to content

Commit

Permalink
add restarting mechanism with scenes (scuffed)
Browse files Browse the repository at this point in the history
  • Loading branch information
thepigeongenerator committed Dec 4, 2024
1 parent aedad9c commit 2084005
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 22 deletions.
32 changes: 22 additions & 10 deletions Core/Game.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@ namespace Core;

public abstract class Game : Microsoft.Xna.Framework.Game
{
private readonly Type[] scenes = null;
private static Game instance = null;
private Scene scene;
private bool initialized = false;
private bool loadedContent = false;

internal static Game Instance => instance ?? throw new NullReferenceException("Tried to get the game's instance before the game has been made");

internal readonly ObjectRegistry objectRegistry;
internal bool Initialized => initialized;
internal bool LoadedContent => loadedContent;
public Scene Scene => scene;

protected abstract SpriteBatch SpriteBatch { get; set; }

Expand All @@ -25,25 +27,37 @@ public Game()
if (instance != null) throw new InvalidOperationException("there is only allowed to be one game!");
instance = this;

objectRegistry = new();
scenes = GetScenes();
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static IEnumerable<T> GetObjectsOfType<T>() where T : class
{
return Instance.objectRegistry.GetObjectsOfType<T>();
return Instance.scene.objectRegistry.GetObjectsOfType<T>();
}

public void LoadScene(int i, params object[] args)
{
if (scenes[i].IsSubclassOf(typeof(Scene)) == false)
throw new InvalidCastException($"the scene '{i}' is not derrived from '{typeof(Scene).FullName}'!");

scene?.Dispose();
scene = (Scene)Activator.CreateInstance(scenes[i], args);
if (initialized) scene.Initialize();
if (loadedContent) scene.LoadContent(Content);
}

// executes the scheduled actions DO NOT CALL UNLESS YOU KNOW WHAT YOU'RE DOING
protected void ExecuteScheduled()
{
objectRegistry.CreateGameObjects();
objectRegistry.DisposeGameObjects();
scene.objectRegistry.CreateGameObjects();
scene.objectRegistry.DisposeGameObjects();
}

protected override void Initialize()
{
initialized = true;
scene.Initialize();
foreach (IInitialize initialize in GetObjectsOfType<IInitialize>())
initialize.Initialize();

Expand All @@ -55,6 +69,7 @@ protected override void Initialize()
protected override void LoadContent()
{
loadedContent = true;
scene.LoadContent(Content);
foreach (ILoadContent loadContent in GetObjectsOfType<ILoadContent>())
loadContent.LoadContent(Content);

Expand All @@ -65,6 +80,7 @@ protected override void LoadContent()

protected override void Update(GameTime gameTime)
{
scene.Update();
foreach (IUpdate update in GetObjectsOfType<IUpdate>())
update.Update();

Expand All @@ -73,9 +89,5 @@ protected override void Update(GameTime gameTime)
base.Update(gameTime);
}

protected void DrawObjects()
{
foreach (IDraw draw in GetObjectsOfType<IDraw>())
draw.Draw(SpriteBatch);
}
protected abstract Type[] GetScenes();
}
4 changes: 2 additions & 2 deletions Core/GameObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public GameObject()
{
// initialize public variables with their default values
transform = new();
Game.Instance.objectRegistry.AddGameObject(this);
Game.Instance.Scene.objectRegistry.AddGameObject(this);
}

// to get rid of the gameobject
Expand All @@ -23,7 +23,7 @@ public void Dispose()
return;

GC.SuppressFinalize(this);
Game.Instance.objectRegistry.RemoveGameObject(this);
Game.Instance.Scene.objectRegistry.RemoveGameObject(this);
disposed = true;
OnDispose();
}
Expand Down
24 changes: 23 additions & 1 deletion Core/ObjectRegistry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace Core;

internal class ObjectRegistry
internal class ObjectRegistry : IDisposable
{
// using linked lists instead of a List, because it's faster when creating new objects
// removing makes no difference, as it only needs to climb till the correct gameObject. Where in a list it'd need to move all the elements after one forward.
Expand Down Expand Up @@ -119,4 +119,26 @@ public IEnumerable<T> GetObjectsOfType<T>() where T : class
yield return t;
}
}

public void Dispose()
{
GC.SuppressFinalize(this);

// call dispose on all the gameObjects
while (objectRegistry.First != null)
{
objectRegistry.First.Value.Dispose();
objectRegistry.RemoveFirst();
}

// clear other lists
initializes.Clear();
loadContents.Clear();
updates.Clear();
draws.Clear();

// clear queues
createQueue.Clear();
disposeQueue.Clear();
}
}
53 changes: 53 additions & 0 deletions Core/Scene.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace Core;

public abstract class Scene : IDisposable, IInitialize, ILoadContent, IUpdate, IDraw
{
private bool disposed = false;
internal readonly ObjectRegistry objectRegistry;

public Scene()
{
objectRegistry = new();
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public IEnumerable<T> GetObjectsOfType<T>() where T : class
{
return objectRegistry.GetObjectsOfType<T>();
}

public void DrawObjects(SpriteBatch spriteBatch)
{
Draw(spriteBatch);
foreach (IDraw draw in GetObjectsOfType<IDraw>())
draw.Draw(spriteBatch);
}

public void Dispose()
{
// ignore extra dispose calls; we've already disposed.
if (disposed)
return;

GC.SuppressFinalize(this);

// dispose of the object registry
objectRegistry.Dispose();

disposed = true;
OnDispose();
}

public virtual void OnDispose() { }

public abstract void Draw(SpriteBatch spriteBatch);
public abstract void Update();
public abstract void LoadContent(ContentManager content);
public abstract void Initialize();
}
30 changes: 22 additions & 8 deletions SpaceShooter2/SpaceShooter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Microsoft.Xna.Framework.Input;
using SpaceShooter2.Src;
using SpaceShooter2.Src.Data;
using SpaceShooter2.Src.Scenes;
using System;
using System.Collections.Generic;
using System.Diagnostics;
Expand Down Expand Up @@ -86,6 +87,12 @@ private void DebugKeybinds()
glob.player.Damage(glob.player.Health);
}

protected override void Initialize()
{
LoadScene(0, glob);
base.Initialize();
}

// loads all the assets we will use for the game
// aditionally, it initializes the objects used in the game
protected override void LoadContent()
Expand All @@ -104,11 +111,8 @@ protected override void LoadContent()
glob.assets.destroyAsteroid = Content.Load<SoundEffect>(Const.SFX_DESTROY_ASTEROID);
glob.assets.lose = Content.Load<SoundEffect>(Const.SFX_LOSE);

// init game objects (some aren't stored in globalstate, because theglob.spawnery're automatically added to the game object registry)
glob.player = new Player(glob);
glob.pcl = new(GraphicsDevice);
_ = new Spawner(glob);
_ = new UI(glob);

base.LoadContent();
}

Expand All @@ -122,9 +126,12 @@ protected override void Update(GameTime gameTime)
// excute the debug keybinds to perform debug actions
DebugKeybinds();

// if the game has been lost, check if the enter key has been pressed, exit if so
if (glob.lose == true && glob.keyboard.IsKeyDown(Keys.Enter))
Exit();
// if the game has been lost, check if the enter key has been pressed, restart if so
if (glob.lose && glob.keyboard.IsKeyDown(Keys.Enter))
{
glob.lose = false;
LoadScene(0, glob);
}

base.Update(gameTime);
}
Expand All @@ -138,7 +145,7 @@ protected override void Draw(GameTime gameTime)
// draw everything
SpriteBatch.Begin(samplerState: SamplerState.PointClamp, sortMode: SpriteSortMode.FrontToBack);
glob.pcl.Draw(SpriteBatch); // draw the pixel control layer
DrawObjects(); // draw all the gameObjects with IDraw implemented
Scene.DrawObjects(SpriteBatch); // draw all the gameObjects with IDraw implemented
SpriteBatch.End();

// clear pcl's internal buffer *after* drawing, otherwise it won't know what to draw
Expand All @@ -158,4 +165,11 @@ protected override void OnExiting(object sender, EventArgs args)

base.OnExiting(sender, args);
}

protected override Type[] GetScenes()
{
return new Type[] {
typeof(GameScene),
};
}
}
30 changes: 30 additions & 0 deletions SpaceShooter2/Src/Scenes/GameScene.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Core;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using SpaceShooter2.Src.Data;

namespace SpaceShooter2.Src.Scenes;

internal class GameScene : Scene
{
private readonly GlobalState glob;

public GameScene(GlobalState glob)
{
this.glob = glob;
}

public override void Initialize()
{
_ = new Spawner(glob);
_ = new UI(glob);
}

public override void LoadContent(ContentManager content)
{
glob.player = new Player(glob);

}
public override void Update() { }
public override void Draw(SpriteBatch spriteBatch) { }
}
2 changes: 1 addition & 1 deletion SpaceShooter2/Src/UI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.DrawString(glob.assets.font, "YOU LOST", new Vector2(Const.SCREEN_CENTRE_X, Const.SCREEN_CENTRE_Y), Color.Red, centre, 1.0F, 1.0F);
spriteBatch.DrawString(glob.assets.font, $"Score: {score}\nHigh Score: {highscore}", new Vector2(Const.SCREEN_CENTRE_X, 10), Color.White, topCentre, 0.5F, 1.0F);
spriteBatch.DrawString(glob.assets.font, "press [enter] to exit", new Vector2(Const.SCREEN_CENTRE_X, Const.SCREEN_CENTRE_Y + 40), Color.Red, centre, 0.5F, 1.0F);
spriteBatch.DrawString(glob.assets.font, "press [enter] to restart", new Vector2(Const.SCREEN_CENTRE_X, Const.SCREEN_CENTRE_Y + 40), Color.Red, centre, 0.5F, 1.0F);
return;
}

Expand Down

0 comments on commit 2084005

Please sign in to comment.