A flexible context management system for Unity that provides a structured way to handle application state and data flow through context stacks.
- Stack-based Context Management: Push and pop contexts to manage different application states
- Data Sharing: Share data between contexts through
IContextDatainterfaces - Context Lifecycle: Built-in lifecycle methods (
Start,Update,Dispose) - Observable Updates: Integrates with R3 for reactive update loops
- Type-safe Data Access: Generic methods for retrieving context data with compile-time safety
Add this package to your Unity project using the Package Manager with Git URL:
- Open Window > Package Manager
- Click the + button and select "Add package from git URL..."
- Enter the following URL:
https://github.com/lourenco-pedro/UnityContext.git - Click "Add" and Unity will download and install the package
Create data classes that implement IContextData to share information between contexts:
using ContextSystem;
public class PlayerData : IContextData
{
public int Health { get; set; }
public string PlayerName { get; set; }
}
public class GameSettings : IContextData
{
public float Volume { get; set; }
public bool FullScreen { get; set; }
}Extend BaseContext to create your own contexts:
using ContextSystem;
using UnityEngine;
public class GameplayContext : BaseContext
{
public override void Start(ContextArgs args)
{
Debug.Log("Gameplay context started");
// Access shared data from parent contexts
args.UseContextData<GameSettings>(settings =>
{
Debug.Log($"Volume: {settings.Volume}");
});
}
public override void Update(ContextArgs args)
{
// Called every frame
args.UseContextData<PlayerData>(player =>
{
// Update player logic
});
}
public override void Dispose()
{
Debug.Log("Gameplay context disposed");
// Clean up resources
}
}Initialize the context manager at application startup:
using ContextSystem;
using UnityEngine;
public class GameBootstrap : MonoBehaviour
{
void Start()
{
ContextManager.Tick();
// Push the initial context
var playerData = new PlayerData
{
Health = 100,
PlayerName = "Player1"
};
ContextManager.PushContext<GameplayContext>(playerData);
}
void OnDestroy()
{
ContextManager.Terminate();
}
}Add a new context to the stack:
ContextManager.PushContext<MenuContext>();Push with initial data:
var data = new PlayerData { Health = 100 };
ContextManager.PushContext<GameplayContext>(data);Remove the current context from the stack:
ContextManager.PopContext();Replace the current context with a new one:
ContextManager.SwitchContext<GameOverContext>();Use ContextArgs to access data in your context methods:
public override void Update(ContextArgs args)
{
// Access single data type
args.UseContextData<PlayerData>(player =>
{
Debug.Log($"Player health: {player.Health}");
});
// Access multiple data types
args.UseContextData<PlayerData, GameSettings>((player, settings) =>
{
Debug.Log($"{player.PlayerName} playing at volume {settings.Volume}");
});
}You can register additional data after context creation:
public override void Start(ContextArgs args)
{
var enemyData = new EnemyData();
RegisterContexData(enemyData);
}Static manager class that controls the context stack.
Tick()- Initializes the update loopTerminate()- Stops the update loopPushContext<T>(IContextData data = null)- Adds a new context to the stackPopContext()- Removes the top context from the stackSwitchContext<T>(IContextData data = null)- Replaces the current contextCurrentContext- Returns the name of the current context (read-only)Initialized- Returns whether the manager is initialized (read-only)
Abstract base class for all contexts.
Start(ContextArgs args)- Called when the context is pushed onto the stackUpdate(ContextArgs args)- Called every frameDispose()- Called when the context is removed from the stackRegisterContexData(params IContextData[] data)- Register data to be shared with child contextsGetContextDatas()- Returns all registered context data
Structure passed to context lifecycle methods containing shared data.
UseContextData<T>(Action<T> onFound)- Execute an action if the data type is foundUseContextData<T1, T2>(Action<T1, T2> onFound)- Execute an action if both data types are foundCount- Returns the number of available context data objects
public class MainMenuContext : BaseContext
{
public override void Start(ContextArgs args)
{
Debug.Log("Main Menu opened");
}
public override void Update(ContextArgs args)
{
if (Input.GetKeyDown(KeyCode.Return))
{
// Switch to gameplay
ContextManager.SwitchContext<GameplayContext>(new PlayerData());
}
}
public override void Dispose()
{
Debug.Log("Main Menu closed");
}
}- Unity 2021.3 or later
MIT License