Skip to content

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

  1. What is LoL Engine?
  2. Prerequisites
  3. Installation
  4. Minimum Required Setup
  5. Your First Scene
  6. Using Services in Code
  7. Optional Services Setup
  8. Core Concepts
  9. Verification Checklist
  10. Troubleshooting
  11. 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
Package When to Install
Input System For game input (used in game code — see Input.md)
TextMeshPro Sample UI prefers TMP labels

3. Installation

  1. Open the Unity Asset Store in your browser or via Window > Asset Store in Unity.
  2. Purchase/download LoL Engine – Labour of Love Game Framework.
  3. In Unity, open Window > Package Manager, switch to My Assets, find LoL Engine, and click Import.
  4. 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.

  1. Right-click in Assets/Resources/Configs/
  2. Select: Create > LoLEngine > Service Configuration
  3. 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

This tells the engine where to find configuration files.

  1. Right-click in Assets/Resources/Configs/
  2. Select: Create > LoLEngine > Resource Path Config
  3. Name it: ResourcePathConfig
  4. 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.).

  1. File > New Scene (Empty scene)
  2. Save as: Assets/Scenes/Boot.unity (or any name you prefer)
  3. Create empty GameObject named EngineInitializer
  4. Add component: LoLEngine > Core > ImprovedGameInitializer
  5. In Inspector, assign:
  6. Service Configuration: Your ServiceConfiguration asset
  7. Resource Path Config: Your ResourcePathConfig asset (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

  1. File > Build Settings
  2. Add your entry scene as Scene 0 (first scene)
  3. 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 MB limits total cached memory (0 or negative = unlimited)
  • Max Cache Entries limits 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:

  1. Core Phase — Essential services (EventManager, ResourceService, ObjectPool, TimeService)
  2. Feature Phase — Engine services (Audio, Serialization, Compression, Encryption)
  3. Game Phase — Game systems (Save System, Localization, Game State)
  4. Custom Phase — Your custom services (via IServiceRegistrar or 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

  1. CHEATSHEET-How-To-Use.md - Quick reference for all systems
  2. Documentation Index - Complete documentation list
  3. 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)

  1. Create Assets/Resources/Configs/ folder
  2. Create ServiceConfiguration asset there
  3. Enable: EventManager, ResourceService
  4. Create Boot scene with ImprovedGameInitializer
  5. Assign ServiceConfiguration
  6. 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.