4. Your First Script
The one pattern that unlocks the whole framework, plus copy-paste snippets for the five services you will use first.
4.1 The quick start
Create a new C# script, paste this in, drop it on any GameObject in any scene, and press Play:
using CommonGameSystem.Core;
using UnityEngine;
public class HelloCgs : MonoBehaviour
{
private void Start()
{
var scheduler = ServiceLocator.Resolve<IScheduler>();
var tween = ServiceLocator.Resolve<ITweenService>();
scheduler.After(1f, () => Debug.Log("One second after Play."));
tween.To(1f, 2f, 0.5f,
scale => transform.localScale = Vector3.one * scale,
EaseType.OutBack);
}
}
The object pops to double size with a springy overshoot, and a message appears one second later. Notice what is missing: no manager prefab, no initialization scene, no setup component. The bootstrap registered all 23 services before your Start ran.
4.2 How resolving services works
Every CGS service is reached the same way: ask the service locator for the interface you need.
var save = ServiceLocator.Resolve<ISaveService>();
Three rules keep this fast and safe:
- Resolve early, cache the result. Services register before the first scene loads, so
AwakeandStartare both safe places to resolve. Store the reference in a field and reuse it — never callResolveinsideUpdate. - Missing services throw.
Resolve<T>()throws a clear exception if nothing is registered for that interface. For a soft check, useServiceLocator.TryResolve(out T service)orServiceLocator.IsRegistered<T>(). - Anything can be swapped.
ServiceLocator.Replace<T>(instance)substitutes your own implementation, or a do-nothing null version, at any time (chapter 1, section 1.4).
The typical consumer looks like this:
public class GameHud : MonoBehaviour
{
private ISaveService _save; // cached once, used many times
private void Awake()
{
_save = ServiceLocator.Resolve<ISaveService>();
}
}
4.3 The five services you will use first
Each snippet below runs inside a MonoBehaviour, after the usings from section 4.1.
Saving and loading
Any serializable class can be a save file. Writes are atomic — a crash mid-save never corrupts the previous file. Full reference: Save/Load.
[System.Serializable]
public class PlayerData { public int Level; public float Health; }
var save = ServiceLocator.Resolve<ISaveService>();
save.Save("slot0", new PlayerData { Level = 3, Health = 75f });
var result = save.Load<PlayerData>("slot0");
if (result.Status == SaveStatus.Ok)
Debug.Log("Loaded level " + result.Value.Level);
Events
Any class can be an event. Publishers and subscribers never reference each other — only the event type. Full reference: Event Bus.
public sealed class CoinCollected { public int Amount; }
var events = ServiceLocator.Resolve<IEventBus>();
System.IDisposable ticket = events.Subscribe<CoinCollected>(
e => Debug.Log("Coins gained: " + e.Amount));
events.Publish(new CoinCollected { Amount = 5 });
ticket.Dispose(); // stop listening (do this in OnDestroy)
Timers
Timers fire in the order they were scheduled. One-shot timers clean up after themselves; repeating timers run until you dispose them. Full reference: Scheduler.
var scheduler = ServiceLocator.Resolve<IScheduler>();
scheduler.After(2f, () => Debug.Log("Two seconds later, exactly once."));
System.IDisposable heartbeat =
scheduler.Every(0.5f, () => Debug.Log("Every half second."));
heartbeat.Dispose(); // stop the repeating timer when done
Tweening
A tween animates a value from one number to another and hands you each step. By default tweens run on the gameplay clock, so they pause when your game pauses. Full reference: Tween.
var tween = ServiceLocator.Resolve<ITweenService>();
CanvasGroup group = GetComponent<CanvasGroup>();
tween.To(1f, 0f, 0.75f,
alpha => group.alpha = alpha,
EaseType.OutQuad,
onComplete: () => Debug.Log("Fade finished."));
Input
Input is read through named action maps from your input actions asset. Replace "Gameplay" and "Jump" with names from your own asset. Add using UnityEngine.InputSystem; for the InputAction type. Full reference: Input.
private IInputService _input;
private InputAction _jump;
private void Start()
{
_input = ServiceLocator.Resolve<IInputService>();
_jump = _input.GetAction("Gameplay", "Jump");
}
private void Update()
{
if (_jump != null && _input.WasPressedThisFrame(_jump))
Debug.Log("Jump!");
}
4.4 Where to go next
You now know the one pattern that unlocks the entire framework: resolve an interface, cache it, call it. From here:
- Service reference. Every service has its own page — start at the documentation index, or in your project under
Assets/CommonGameSystem.Core/Documentation/Modules/(for exampleSaveLoad.mdorTween.md). Each page covers the full API, common patterns, and the caveats that matter. - Samples. The RPG Starter Sample (chapter 3) shows several of the services above cooperating in one small game slice.
- The rest of this manual. Chapter 5 explains the five core concepts; chapter 6 connects the framework to your own assets.
- Changelog. The Welcome window's quick links (chapter 3) open the documentation and the changelog for your installed version.
Next: 5. Core Concepts