Getting Started with LoL Engine¶
A complete guide to setting up LoL Engine for your Unity game.
Target Audience: Developers new to LoL Engine who want to integrate it into their game project.
Unity: 6000.0+ — for the current engine version see package.json or CHANGELOG.md
In a hurry? The 5-minute Quickstart gets you from install to a working sound. This guide is the full walkthrough.
Table of Contents¶
- What is LoL Engine?
- Prerequisites
- Installation
- Minimum Required Setup
- Your First Scene
- Using Services in Code
- Optional Services Setup
- Core Concepts
- Verification Checklist
- Troubleshooting
- Next Steps
1. What is LoL Engine?¶
LoL Engine provides production-ready game systems so you don't have to build them from scratch:
| What You Get | Description |
|---|---|
| Audio System | Music, SFX, spatial audio, fading, tracks, playlists |
| Save System | Save/load with optional encryption & compression |
| Event System | Type-safe decoupled communication |
| Object Pooling | High-performance spawning |
| Localization | Multi-language support with LocString |
| Resource Management | Addressables + Resources fallback |
| Time Management | Pause, slow-motion, timers |
| Deterministic RNG | Named streams with snapshot save/load |
Key Features: - Production-ready with thread-safe implementations - Modular design — use only what you need - ScriptableObject-based configuration - Comprehensive samples and documentation - Unit test coverage
Architecture: Service Locator Pattern (not singletons) for testability and modularity.
2. Prerequisites¶
Required¶
| Requirement | Details |
|---|---|
| Unity Version | 6000.0+ (Unity 6) |
| Addressables | Declared dependency — resolved automatically via Package Manager |
| Newtonsoft JSON | Declared dependency — resolved automatically via Package Manager |
Recommended (Optional)¶
| Package | When to Install |
|---|---|
| Input System | For game input (used in game code — see Input.md) |
| TextMeshPro | Sample UI prefers TMP labels |
3. Installation¶
Option A: Unity Asset Store (Recommended)¶
- Open the Unity Asset Store in your browser or via Window > Asset Store in Unity.
- Purchase/download LoL Engine – Labour of Love Game Framework.
- In Unity, open Window > Package Manager, switch to My Assets, find LoL Engine, and click Import.
- Unity will import the package into your project automatically.
Verification¶
After installation, check: - No console errors - Folder structure exists:
Assets/LoLEngine/
├── Runtime/
├── Editor/
├── Samples~/
└── Documentation~/
4. Minimum Required Setup¶
This is the bare minimum to get LoL Engine running.
Step 4.1: Create Required Folders¶
Create this folder structure in your project:
Assets/
├── Resources/
│ └── Configs/ <-- Required for engine configs
└── Scenes/ <-- Your game scenes
Step 4.2: Create Service Configuration¶
This is the master switch that controls which services are enabled.
- Right-click in
Assets/Resources/Configs/ - Select: Create > LoLEngine > Service Configuration
- Name it:
ServiceConfiguration
Tip: the Setup Wizard (Tools > LoL Engine > Setup Wizard) can generate these configuration assets, wire up a scene initializer, and validate the result for you.
Step 4.3: Configure Core Services¶
Select your ServiceConfiguration asset and enable these in the Inspector:
MINIMUM REQUIRED (check these boxes):
[x] Enable Event Manager Service - Required for all communication
[x] Enable Resource Service - Required for asset loading
Step 4.4: Create Resource Path Config (Optional but Recommended)¶
This tells the engine where to find configuration files.
- Right-click in
Assets/Resources/Configs/ - Select: Create > LoLEngine > Resource Path Config
- Name it:
ResourcePathConfig - Configure paths in Inspector:
Engine Resource Root: "" <-- Empty for game projects
Configs Path: "Configs/" <-- Where your configs live
Step 4.5: Create Your Entry Scene¶
This is the first scene that loads when your game starts. You can name it anything (Boot, Init, Main, etc.).
- File > New Scene (Empty scene)
- Save as:
Assets/Scenes/Boot.unity(or any name you prefer) - Create empty GameObject named
EngineInitializer - Add component: LoLEngine > Core > ImprovedGameInitializer
- In Inspector, assign:
- Service Configuration: Your
ServiceConfigurationasset - Resource Path Config: Your
ResourcePathConfigasset (optional)
Note: If you want a loading screen, splash screen, or any boot sequence - build it yourself. The engine initializes services; what you show the user during that time is up to you.
Step 4.6: Configure Build Settings¶
- File > Build Settings
- Add your entry scene as Scene 0 (first scene)
- Add your other scenes below it
5. Your First Scene¶
The "Boot" scene is simply your game's entry point - the first scene that loads. There's nothing special about it from the engine's perspective. It's where you place the ImprovedGameInitializer to start the engine.
Scene Hierarchy¶
Your entry scene should look like this:
Your Entry Scene (e.g., "Boot", "Init", "Main")
├── EngineInitializer [ImprovedGameInitializer component]
├── Main Camera [AudioListener component]
└── EventSystem [For UI - optional]
Note: You can design your own loading/splash screen however you want. The engine doesn't provide or require any specific boot screen implementation.
ImprovedGameInitializer Settings¶
| Setting | Value | Notes |
|---|---|---|
| Service Configuration | Your asset | Required |
| Resource Path Config | Your asset | Optional |
| Dont Destroy On Load | Checked | Keeps engine alive |
| Initialize In Awake | Checked | Starts immediately |
6. Using Services in Code¶
Basic Pattern¶
Always wait for services to initialize before using them:
using UnityEngine;
using LoLEngine.Core.Events.Interfaces;
using LoLEngine.Core.ServiceManagement.Service;
using LoLEngine.Runtime;
public class MyGameManager : MonoBehaviour
{
private IEventManager _eventManager;
private bool _isInitialized = false;
void Start()
{
// Wait for services to be ready
if (ServiceAwaiter.AreServicesReady())
OnServicesReady();
else
ServiceAwaiter.WaitForServices(this, OnServicesReady, OnServicesTimeout);
}
private void OnServicesReady()
{
// Now safe to get services
_eventManager = ServiceLocator.Instance.Get<IEventManager>();
_isInitialized = true;
Debug.Log("Game ready!");
}
private void OnServicesTimeout()
{
Debug.LogError("Services failed to initialize!");
}
void Update()
{
// Guard against using services before they're ready
if (!_isInitialized) return;
// Your game logic here
}
}
Getting Services¶
// Get any registered service
var eventManager = ServiceLocator.Instance.Get<IEventManager>();
var audioService = ServiceLocator.Instance.Get<IAudioService>();
var saveSystem = ServiceLocator.Instance.Get<ISaveSystem>();
// etc.
MonoBehaviour Extensions (Shortcuts)¶
LoL Engine provides extension methods for common operations:
// Audio (requires AudioService enabled)
this.PlaySound("Audio/Click");
this.PlaySoundAtPosition("Audio/Explosion", transform.position);
// Object Pooling (requires ObjectPoolService enabled)
GameObject enemy = this.Spawn(enemyPrefab, position, rotation);
this.Despawn(enemy);
// Events
this.EventStartListening<MyEvent>();
this.EventStopListening<MyEvent>();
// Delayed calls
this.DelayedCall(() => Debug.Log("After 2 seconds"), 2.0f);
7. Optional Services Setup¶
Enable these in ServiceConfiguration based on what your game needs.
Audio System¶
Enable in ServiceConfiguration:
[x] Enable Audio Service
Create Audio Config:
1. Right-click > Create > LoLEngine > Audio > Audio Config
2. Name it: DefaultAudioConfig (or configure the name in ResourcePathConfig)
3. Place in: Assets/Resources/Configs/
Audio Config Settings:
Tracks:
├── Track: "Music" | Volume: 1.0 | Mute: false
├── Track: "SFX" | Volume: 1.0 | Mute: false
└── Track: "UI" | Volume: 1.0 | Mute: false
└── Track: "Voice" | Volume: 1.0 | Mute: false
└── Track: "Ambient" | Volume: 1.0 | Mute: false
Pool Settings:
├── Use Object Pooling: true
├── Initial Pool Size: 10
└── Max Pool Size: 50
Usage:
var audioService = ServiceLocator.Instance.Get<IAudioService>();
audioService.PlaySound("Audio/MySound");
// Or use extension
this.PlaySound("Audio/MySound");
Save System¶
Enable in ServiceConfiguration:
[x] Enable Data Persistence Service
[x] Enable Serialization Service <-- Required dependency
[ ] Enable Compression Service <-- Optional
[ ] Enable Encryption Service <-- Optional
Create Save Config:
1. Right-click > Create > LoLEngine > Data Persistence > Save Configuration
2. Name it: DefaultSaveConfig
3. Place in: Assets/Resources/Configs/
Save Config Settings:
Save Settings (SaveConfig):
├── Default Save Slot: "save1"
├── Quick Save Slot: "quicksave"
├── Auto Save Slot: "autosave"
├── Max Save Slots: 10
└── Auto Save Interval: 300
Note: save directory and file extensions are configured on LoLEngineConfig, not SaveConfig.
Create Your Save Data:
using LoLEngine.Core.DataPersistence.Data;
[Serializable]
public class PlayerSaveData : PersistableData
{
public override string DataId => "player";
public int level = 1;
public float health = 100f;
public Vector3 position;
}
Usage:
var saveSystem = ServiceLocator.Instance.Get<ISaveSystem>();
// Get or create save data
var playerData = saveSystem.GetData<PlayerSaveData>();
playerData.level = 5;
playerData.position = transform.position;
// Save
saveSystem.SaveGame("slot1");
// Load
if (saveSystem.HasSaveFile("slot1"))
{
saveSystem.LoadGame("slot1");
var loadedData = saveSystem.GetData<PlayerSaveData>();
transform.position = loadedData.position;
}
Input System¶
ServiceConfiguration note:
There is currently no Input Service toggle in ServiceConfiguration.
Use Unity's Input System package directly for input actions.
Setup Input Actions:
1. Create InputActions asset: Create > Input Actions
2. Define your action maps (Player, UI, etc.)
3. Define actions (Move, Jump, Attack, etc.)
4. Save it with your game assets, or duplicate the bundled starter:
Assets/LoLEngine/Runtime/Resources/Input/DefaultInputSystem_Actions.inputactions
5. Assign it to a PlayerInput component or serialize an InputActionAsset reference in your MonoBehaviour.
Usage:
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerController : MonoBehaviour
{
[SerializeField] private InputActionAsset actions;
private InputAction _move;
void OnEnable()
{
var player = actions.FindActionMap("Player", throwIfNotFound: true);
_move = player.FindAction("Move", throwIfNotFound: true);
player.Enable();
}
void Update()
{
Vector2 moveInput = _move.ReadValue<Vector2>();
}
}
Object Pooling¶
Enable in ServiceConfiguration:
[x] Enable Object Pool Service
No additional config needed!
Usage:
// Spawn from pool
GameObject bullet = this.Spawn(bulletPrefab, position, rotation);
// Return to pool (don't use Destroy!)
this.Despawn(bullet);
// Pre-warm pool
this.PreloadPool(bulletPrefab, 20);
Localization¶
Enable in ServiceConfiguration:
[x] Enable Localization Service
Create Localization Config:
1. Right-click > Create > LoLEngine > Localization > Config
2. Name it: DefaultLocalizationConfig
3. Place in: Assets/Resources/Configs/
Create Translation Table (CSV):
Key,Context,English,French,German
UI_PLAY,Main Menu,Play,Jouer,Spielen
UI_SETTINGS,Main Menu,Settings,Paramètres,Einstellungen
Place at: Assets/Resources/Localization/Tables/StringTable.csv
Optional: Font Localization (for CJK/Arabic/Cyrillic) 1. Right-click > Create > LoLEngine > Localization > Font Config 2. Add per-language font entries (e.g., Korean with NotoSansKR, sizeScale 1.2) 3. Assign to LocalizationConfig's "Font Config" field
Usage:
using LoLEngine.Core.Localization.LocString;
var locService = ServiceLocator.Instance.Get<ILocalizationService>();
// Canonical pattern: build a LocString (table + key) and Format it.
string text = locService.Format(new LocString(LocTable.UI, "UI_PLAY"));
locService.SetLanguage(SystemLanguage.French);
// Plurals: "5 items" (English), "5 objets" (French)
string plural = locService.GetPluralText("ITEM_COUNT", 5);
// RTL detection
bool isRTL = locService.IsCurrentLanguageRTL;
Components (add to GameObjects in Inspector):
- LocalizedText — auto-updates text, font, and RTL on language change
- LocalizedImage — auto-updates sprite on language change
- LocalizedAudio — auto-updates AudioClip on language change
- LocalizedLayoutGroup — flips layout direction for RTL languages
See Localization.md for full documentation.
Time Management¶
Enable in ServiceConfiguration:
[x] Enable Time Service
No additional config needed:
When Time Service is enabled, the initializer auto-creates a TimeManager
tick driver at runtime so timers/scheduler update automatically.
Usage:
var timeService = ServiceLocator.Instance.Get<ITimeService>();
// Pause game
timeService.PauseGlobal();
timeService.ResumeGlobal();
// Slow motion
timeService.SetTimeScale(0.5f);
// Timers
timeService.CreateTimer(5f, () => Debug.Log("Timer done!")).Start();
// Delayed call extension
this.DelayedCall(() => Debug.Log("Delayed!"), 2f);
Game State Manager¶
Enable in ServiceConfiguration:
[x] Enable Game State Manager Service
Usage:
using LoLEngine.Core.GameState.Enums;
using LoLEngine.Core.GameState.Interfaces;
using LoLEngine.Core.ServiceManagement.Service;
// Define game state IDs in YOUR project (engine reserves 0–99)
public static class MyGameStateType
{
public const GameStateType MainMenu = (GameStateType)100;
public const GameStateType Gameplay = (GameStateType)101;
public const GameStateType Paused = (GameStateType)102;
}
var gameStateManager = ServiceLocator.Instance.Get<IGameStateManagerService>();
// Register states at bootstrap, then transition
gameStateManager.RegisterState(new MainMenuState());
gameStateManager.RegisterState(new GameplayState());
gameStateManager.RegisterState(new PausedState());
gameStateManager.ChangeState(MyGameStateType.Gameplay);
gameStateManager.ChangeState(MyGameStateType.Paused);
if (gameStateManager.IsInState(MyGameStateType.Paused))
{
// Handle paused state
}
See Game State and Samples~/GameState/ for full examples.
Notifications¶
Enable in ServiceConfiguration:
[x] Enable Notification Service
Usage:
this.SendNotification(
"Achievement Unlocked!",
"You defeated your first enemy",
NotificationCategory.Achievement
);
Operational note:
NotificationService now emits periodic diagnostics and warns when subscriber counts grow unusually high.
Always unsubscribe listeners in OnDisable/OnDestroy to avoid stale callbacks.
Resource Management (Performance Tuning)¶
Resource cache behavior is controlled via ResourceManagementConfig:
Resource Service Settings:
├── Max Memory Budget MB: 512
└── Max Cache Entries: 100
Max Memory Budget MBlimits total cached memory (0 or negative = unlimited)Max Cache Entrieslimits cache item count (0 or negative uses default 100)- Tune both values per game profile (RPG content-heavy vs roguelite churn-heavy)
8. Core Concepts¶
Service Locator Pattern¶
LoL Engine uses the Service Locator pattern instead of Singletons for better testability and decoupling.
Key Benefits: - Explicit dependencies (services are registered and retrieved explicitly) - Easy to test (services can be mocked) - Flexible (implementations can be swapped) - Thread-safe (production-ready concurrent access)
How It Works:
// 1. Services are registered during initialization
ServiceLocator.Instance.Register<IAudioService>(audioService);
// 2. Retrieve services when needed
var audioService = ServiceLocator.Instance.Get<IAudioService>();
// 3. Use the service
audioService.PlaySound("Audio/Click");
Configuration-Driven Design¶
LoL Engine uses ScriptableObjects for configuration:
Advantages: - Designer-friendly (configure in Inspector) - Version control friendly (assets, not scenes) - Runtime/Editor separation - Easy to create multiple configurations
Initialization Phases¶
LoL Engine initializes services in phases for proper dependency ordering:
- Core Phase — Essential services (EventManager, ResourceService, ObjectPool, TimeService)
- Feature Phase — Engine services (Audio, Serialization, Compression, Encryption)
- Game Phase — Game systems (Save System, Localization, Game State)
- Custom Phase — Your custom services (via
IServiceRegistraror inspector entries)
This ensures dependencies are always available when needed. See ServiceDependencies.md for attribute-based ordering hints.
9. Verification Checklist¶
Before Running¶
- [ ] ServiceConfiguration asset created
- [ ] ServiceConfiguration assigned to ImprovedGameInitializer
- [ ] Boot scene is Scene 0 in Build Settings
- [ ] No console compilation errors
After Pressing Play¶
Expected Console Output:
LoLEngine: ServiceLocator initialized
LoLEngine: Registering core services...
LoLEngine: EventManager initialized
LoLEngine: ResourceService initialized
...
LoLEngine: All services initialized successfully
Quick Test Script¶
Add this to verify everything works:
using UnityEngine;
using LoLEngine.Core.Events.Interfaces;
using LoLEngine.Core.ServiceManagement.Service;
using LoLEngine.Runtime;
public class EngineTest : MonoBehaviour
{
void Start()
{
ServiceAwaiter.WaitForServices(this, () =>
{
Debug.Log("=== LoL Engine Test ===");
// Test EventManager
var events = ServiceLocator.Instance.Get<IEventManager>();
Debug.Log($"EventManager: {(events != null ? "OK" : "FAIL")}");
// Test other services you enabled
// var audio = ServiceLocator.Instance.Get<IAudioService>();
// Debug.Log($"AudioService: {(audio != null ? "OK" : "FAIL")}");
Debug.Log("=== Test Complete ===");
}, () =>
{
Debug.LogError("Services failed to initialize!");
});
}
}
10. Troubleshooting¶
"Service not found" Error¶
Cause: Service not enabled or not initialized
Fix:
1. Check ServiceConfiguration - is the service enabled?
2. Check you're using ServiceAwaiter.WaitForServices() before accessing
3. Verify ImprovedGameInitializer has the configuration assigned
Services Timeout¶
Cause: Initialization failed or took too long
Fix: 1. Check console for earlier errors 2. Verify all config assets exist 3. Check service dependencies are enabled: - SaveSystem needs SerializationService - AudioService may need ResourceService
"Type not found" Compilation Errors¶
Cause: Missing packages
Fix: 1. Install Input System: Window > Package Manager > Input System 2. If using Addressables, install it too 3. Restart Unity
Audio Not Playing¶
Fix: 1. Check AudioService is enabled 2. Check AudioConfig exists and has tracks configured 3. Verify AudioListener exists in scene 4. Check audio clip path is correct
Save Not Working¶
Fix:
1. Check SaveSystem AND SerializationService are enabled
2. Verify SaveConfig exists
3. Check Application.persistentDataPath is writable
4. Look for save errors in console
For more, see the full Troubleshooting guide.
11. Next Steps¶
Recommended Reading¶
- CHEATSHEET-How-To-Use.md - Quick reference for all systems
- Documentation Index - Complete documentation list
- System-specific docs - Deep dives into each service
Explore Samples¶
LoL Engine ships samples under Samples~/ (import via Package Manager → Samples):
- BasicAudio — playback, fades, tracks
- DataPersistence — save/load with async UI
- GameState — define states at 100+; see
Samples~/GameState/ - Localization — CSV table + language switching
- NotificationSystem — categorized notifications
- ObjectPooling — bullet pool with prefab
- ResourceManagement — async loading + Addressables
- Scripts/ — 12 numbered code samples (events, RNG, music playlist, etc.)
See Samples~/README.md for the full walkthrough.
Common Patterns¶
Custom Events:
public class PlayerDiedEvent : GameEvent
{
public Vector3 DeathPosition { get; set; }
}
// Trigger
var evt = GameEvent.GetEvent<PlayerDiedEvent>();
evt.DeathPosition = transform.position;
GameEvent.Trigger(evt);
// Listen
public class GameOverUI : MonoBehaviour, IEventListener<PlayerDiedEvent>
{
void OnEnable() => this.EventStartListening<PlayerDiedEvent>();
void OnDisable() => this.EventStopListening<PlayerDiedEvent>();
public void OnGameEvent(PlayerDiedEvent e) => ShowGameOver(e.DeathPosition);
}
Custom Service:
public interface IScoreService : ILoLEngineService { }
public class ScoreService : IScoreService
{
public void Initialize() { /* Setup */ }
public void Shutdown() { /* Cleanup */ }
}
// Register manually after engine init
ServiceLocator.Instance.Register<IScoreService>(new ScoreService());
For auto-discovered registration, implement IServiceRegistrar — see Samples~/Scripts/09_GameServiceRegistrarSample.cs.
Quick Reference Card¶
Minimum Setup (5 minutes)¶
- Create
Assets/Resources/Configs/folder - Create ServiceConfiguration asset there
- Enable: EventManager, ResourceService
- Create Boot scene with ImprovedGameInitializer
- Assign ServiceConfiguration
- Set Boot as Scene 0
Service Access Pattern¶
if (ServiceAwaiter.AreServicesReady())
UseServices();
else
ServiceAwaiter.WaitForServices(this, UseServices, OnFail);
Common Extensions¶
this.PlaySound("path"); // Audio
this.Spawn(prefab, pos, rot); // Pool
this.Despawn(obj); // Pool
this.EventStartListening<T>(); // Events
this.DelayedCall(action, delay); // Time
Common Interfaces¶
| Interface | Purpose |
|---|---|
ILoLEngineService |
Base service interface |
IAudioService |
Audio playback |
IEventManager |
Event management |
ISaveSystem |
Save/load system |
IResourceService |
Asset loading |
IObjectPoolService |
Object pooling |
ILocalizationService |
Localization |
Important Notes¶
Service Dependencies: Some services require others to be enabled. Check the ServiceConfiguration inspector for warnings.
Addressables: If using Addressables, ensure assets are properly marked and catalogs are built before building your game.
Thread Safety: All core services are thread-safe, but Unity APIs must still be called from the main thread.
IL2CPP builds: Read IL2CPP.md before shipping with managed code stripping enabled.
You're ready to build with LoL Engine!
For questions or issues, check the Troubleshooting guide or the samples.