H073.TheaterKit 1.0.1

Prefix Reserved
dotnet add package H073.TheaterKit --version 1.0.1                
NuGet\Install-Package H073.TheaterKit -Version 1.0.1                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="H073.TheaterKit" Version="1.0.1" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add H073.TheaterKit --version 1.0.1                
#r "nuget: H073.TheaterKit, 1.0.1"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install H073.TheaterKit as a Cake Addin
#addin nuget:?package=H073.TheaterKit&version=1.0.1

// Install H073.TheaterKit as a Cake Tool
#tool nuget:?package=H073.TheaterKit&version=1.0.1                

TheaterKit

TheaterKit is a .NET library designed for advanced scene management in MonoGame projects. This package provides a structured approach to managing, loading, and transitioning between game scenes seamlessly, including support for loading screens and asynchronous scene transitions.

Installation

To install TheaterKit, you can add it to your project as a NuGet package:

dotnet add package TheaterKit

Components

Scene

Scene is an abstract base class that represents individual game scenes. To create a scene, inherit from Scene and override its methods to define the specific behavior, content, and rendering for that scene.

Each Scene provides:

  • Lifecycle Methods:
    • Initialize: Sets up the scene’s initial state.
    • LoadContent: Loads assets like textures, sounds, etc., necessary for the scene.
    • Update: Contains the logic for each frame’s updates.
    • Draw2D and Draw3D: Allows separation between 2D and 3D rendering.
    • UnloadContent: Frees up resources once a scene is no longer in use.

Example of a custom Scene implementation:

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

public class MainMenuScene : Scene
{
    public MainMenuScene(Game game) : base("MainMenu", game) { }

    public override void Initialize()
    {
        // Set up scene-specific variables here
    }

    public override void LoadContent()
    {
        // Load textures, fonts, or other assets needed for the main menu
    }

    protected override void Draw2D(SpriteBatch spriteBatch, GameTime gameTime)
    {
        // Render 2D elements like buttons or backgrounds
    }

    protected override void Draw3D(GameTime gameTime)
    {
        // Optional 3D rendering, if needed
    }

    public override void Update(GameTime gameTime)
    {
        // Update menu-specific logic, such as navigation and animations
    }
}

SceneManager

SceneManager is a singleton class responsible for handling scene transitions, managing scene lifecycles, and providing an optional loading screen between scenes.

Key methods and properties:

  • Add(Scene, bool): Adds a scene to the manager. Optionally overwrites existing scenes with the same name.
  • Stage(string): Stages a scene for activation, loading its content in the background.
  • StageAsync(string, int, int): Asynchronously stages a scene, with pre and post delays to customize the transition duration.
  • Grab(): Activates the staged scene, managing deactivation and unloading of the previous scene.
  • OnLoadComplete: An event triggered when a staged scene completes loading.

Loading Scenes and Transitions

The SceneManager supports using a LoadingScene to provide visual feedback during scene loading. This can be helpful for complex scenes with many assets.

  • Setting a Loading Scene: Assign a custom loading screen to LoadingScene property on the SceneManager. This screen will be shown while new scenes load asynchronously.
  • OnLoadComplete Event: Subscribe to this event to handle actions once the loading of a staged scene finishes.

Example:

// Define and add scenes
var mainMenu = new MainMenuScene(game);
var gameplayScene = new GameplayScene(game);
var loadingScene = new LoadingScene(game); // Custom scene for showing loading visuals

SceneManager.Instance.Add(mainMenu);
SceneManager.Instance.Add(gameplayScene);
SceneManager.Instance.LoadingScene = loadingScene; // Assign loading screen

// Stage and transition to the gameplay scene with a loading screen
await SceneManager.Instance.StageAsync("GameplayScene", pre: 500, post: 500);
SceneManager.Instance.Grab(); // Activates the loaded scene

Full Example with LoadingScene and Camera2D

This example demonstrates how to create a LoadingScene that uses a Camera2D to manage camera position, zoom, and rotation, and animate a loading sprite.

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using TheaterKit;

public class Camera2D
{
    public Vector2 Position;
    public float Zoom;
    public float Rotation;
    private Viewport _viewport;

    public Camera2D(Viewport viewport)
    {
        _viewport = viewport;
        Zoom = 1.0f;
        Rotation = 0.0f;
        Position = Vector2.Zero;
    }

    public Matrix GetViewMatrix()
    {
        return Matrix.CreateTranslation(new Vector3(-Position.X, -Position.Y, 0)) *
               Matrix.CreateRotationZ(Rotation) *
               Matrix.CreateScale(new Vector3(Zoom, Zoom, 1)) *
               Matrix.CreateTranslation(new Vector3(_viewport.Width * 0.5f, _viewport.Height * 0.5f, 0));
    }

    public void CenterOn(Vector2 target)
    {
        Position = target;
    }
}

public class LoadingScene : TheaterKit.Scene
{
    private Camera2D _camera;
    private Texture2D _spriteSheet;
    private int _currentFrame;
    private int _totalFrames;
    private readonly float _frameTime = 0.1f;
    private float _timer = 0f;
    private const int FrameWidth = 128;
    private const int FrameHeight = 128;

    public LoadingScene(Game game, string contentDirectory = "Content") 
        : base("Loading", game, contentDirectory) { }

    public override void Initialize()
    {
        _camera = new Camera2D(GraphicsDevice.Viewport) { Zoom = 5f };
        _currentFrame = 0;
        TheaterKit.SceneManager.Instance.OnLoadComplete += TheaterKit.SceneManager.Instance.Grab;
    }

    public override void LoadContent()
    {
        _spriteSheet = Content.Load<Texture2D>("loader");
        _totalFrames = _spriteSheet.Width / FrameWidth;
    }

    public override void Update(GameTime gameTime)
    {
        _timer += (float)gameTime.ElapsedGameTime.TotalSeconds;

        // Switch frame after each interval
        if (_timer >= _frameTime)
        {
            _currentFrame = (_currentFrame + 1) % _totalFrames;
            _timer = 0f;
        }
    }

    protected override void Draw2D(SpriteBatch spriteBatch, GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.Black);
        var sourceRectangle = new Rectangle(_currentFrame * FrameWidth, 0, FrameWidth, FrameHeight);

        spriteBatch.Begin(transformMatrix: _camera.GetViewMatrix(), samplerState: SamplerState.PointWrap);
        spriteBatch.Draw(_spriteSheet, Vector2.Zero, sourceRectangle, Color.White, 0f, 
                         new Vector2(FrameWidth / 2, FrameHeight / 2), 1f, SpriteEffects.None, 0f);
        spriteBatch.End();
    }
}

Full Game Example

In a typical MonoGame setup, the Game class might handle scene transitions like so:

protected override void Initialize()
{
    var mainMenu = new MainMenuScene(this);
    var gameplayScene = new GameplayScene(this);
    var loadingScene = new LoadingScene(this);

    SceneManager.Instance.Add(mainMenu);
    SceneManager.Instance.Add(gameplayScene);
    SceneManager.Instance.LoadingScene = loadingScene;

    SceneManager.Instance.Stage("MainMenu");
    SceneManager.Instance.Grab(); 

    base.Initialize();
}

protected override void Update(GameTime gameTime)
{
    SceneManager.Instance.Update(gameTime);
    base.Update(gameTime);
}

protected override void Draw(GameTime gameTime)
{
    GraphicsDevice.Clear(Color.CornflowerBlue);
    SceneManager.Instance.Draw(spriteBatch, gameTime);
    base.Draw(gameTime);
}

// Transition to GameplayScene with loading
private async void StartGame()
{
    await SceneManager.Instance.StageAsync("GameplayScene", pre: 1000, post: 1000);
    SceneManager.Instance.Grab();
}

Contributing

Contributions are welcome! Submit issues or pull requests to improve the library.

License

This project is licensed under the MIT License.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.1 77 11/8/2024
1.0.0 80 11/5/2024