Thank you for visiting this site.
In this article, we will provide a detailed explanation of the “Advanced Features” included in Game Creator 2’s core.
These are cross-cutting mechanisms shared across the main pillars — Characters, Cameras, Visual Scripting, and Variables — and include many extension APIs for programmers. From Audio management to Save & Load and Tweening, these cover features frequently used in game development.
Official documentation: Game Creator 2 Documentation
You can find a list of all articles in this series below.
Overview
The Advanced chapter in the official documentation is a toolbox for users and programmers who understand the basics of Unity and GC2. This chapter covers:
- Audio: 5-channel audio management (Ambient / Music / SFX / UI / Speech)
- Signals: Loosely-coupled communication via ID-based broadcasting
- Data Structures: Serializable dictionary, tree, ring buffer, spatial hash, state machine, etc.
- Variables API: Script-based access to local/global variables
- Properties: Field abstraction with dropdown-switchable value sources
- Save & Load:
IGameSaveinterface andSaveLoadManager/Remembercomponents - Tweening: Value interpolation animations
- Custom Installs: Sample/template distribution for module developers
- Domain Reload: Unity reload skip support
Audio — 5-Channel Sound System
GC2’s Audio Manager automatically optimizes AudioSource creation and destruction. There are 5 channels, each with independent volume sliders.
Channel List
| Channel | Purpose | Main Instructions |
|---|---|---|
| Ambient | Environmental sounds (loop, both diegetic and non-diegetic) | Play Ambient / Stop Ambient / Fade All Ambient |
| Music | BGM (non-diegetic, added in v2.6.22+) | Play Music / Stop Music / Fade All Music |
| Sound Effects (SFX) | One-shot sound effects. Diegetic with spatial positioning by default | Play Sound Effect / Stop Sound Effect |
| UI | UI operation sounds (hover, click, craft complete, etc. Non-diegetic) | Play UI Sound |
| Speech | Character-bound speech (one clip per character at a time) | Play Speech / Stop Speech On Game Object |
Sound Variation
To prevent the same SFX from sounding unnatural when repeated, a mechanism is built in that automatically slightly varies pitch and playback speed. Even rapid-fire SFX like machine guns sound natural with the same clip.
Snapshot
Use Change Snapshot to switch AudioMixer snapshots. Useful for indoor/outdoor reverb changes or applying low-pass filters in specific scenes.
Direct AudioSource Control
You can also change individual AudioSource Pitch and Volume via instructions.
Audio Source PitchAudio Source VolumeAudio Mixer Parameter
Signals — Loosely-Coupled Communication
GC2 already provides rich means for linking Triggers / Actions / Conditions, but there are still cases where you want to fire custom events by ID (e.g., boss-defeated, cinematic-end). Signal is the minimal mechanism for this.
- Send: Instruction
Emit Signal(Visual Scripting) / internallyRaise Signal - Receive: Set a Trigger’s Event to
On Receive Signaland specify the identifier - The sender and receiver don’t know about each other, making it great for prefabbing and reuse
Favorites
To prevent signal name typos, you can register names as favorites (select from the dropdown on the right). Toggle registration with the star icon.
Properties
A common mechanism that provides dropdowns to dynamically select field values like “constant / variable / player position / …”.
See the Properties section in the Variables article for details and C# usage.
Level Up! The Guide to Great Video Game DesignView on Amazon →
Introduction to Game Design, Prototyping, and DevelopmentView on Amazon →
Data Structures (ADS: Advanced Data Structures)
A collection of serializable and easily extensible general-purpose data structures provided by GC2. All are used from C#.
Unique ID
public class MyComponent : MonoBehaviour
{
public UniqueID myID = new UniqueID();
}
System.Guidis not serializable, butUniqueIDis serializable and shows a custom UI with a regenerate button in the Inspector- Comparison is faster using Hash:
int hash = this.myID.Get.Hash; - Use string only when you need persistence:
string id = this.myID.Get.String;
Singleton<T>
public class MyClass : Singleton<MyClass>
{
protected override void OnCreate() { base.OnCreate(); /* setup */ }
protected override void OnDestroy() { base.OnDestroy(); /* teardown */ }
protected override bool SurviveSceneLoads => false; // set to destroy on scene change
}
// Usage: MyClass.Instance
- Requires MonoBehaviour (
Singleton<T>inherits it internally) Instanceis auto-created on first reference. Survives scene loads by default- Toggle survival policy with
SurviveSceneLoads
Serializable Dictionary
public class MyDictionary : TSerializableDictionary<string, GameObject> {}
// Usage is the same as System.Collections.Dictionary
Serializable HashSet
public class MyHashSet : TSerializableHash<string> {}
Serializable LinkedList
public class MyLinkedList : TSerializableLinkList<GameObject> {}
// Add / AddFirst / AddLast / First() etc., same as LinkedList
Serializable Matrix 2D
public class MyMatrix : TSerializableMatrix2D<GameObject> {}
MyMatrix matrix = new MyMatrix(10, 5);
matrix[2, 3] = gameObject;
Tree<T>
- A general-purpose tree representing non-cyclic parent-child dependencies
- Each node is itself a tree:
tree.Parent,tree.Children(dictionary keyed by Id) foreachenumerates child nodes,AddChild(value)adds children
Ring<T> (Ring Buffer)
Ring<string> myRing = new Ring<string>("1", "2", "3", "4", "5");
myRing.Index = 0;
for (int i = 0; i < 100; i++) Debug.Log(myRing.Next()); // cycles 20 times
myRing.Update(Debug.Log); // applies a function to each element
State Machine (Generic State Machine)
public class MyState1 : StateMachine.State
{
protected override void WhenEnter(StateMachine m) {}
protected override void WhenExit(StateMachine m) {}
protected override void WhenUpdate(StateMachine m) {}
}
public class MyStateMachine : StateMachine
{
public MyStateMachine(State state) : base(state) {}
}
var m = new MyStateMachine(new MyState1());
m.Change(new MyState2());
- Override
WhenEnter/WhenExit/WhenUpdateper State - Events like
EventOnEnter/EventOnExit/EventOnBeforeUpdateare also exposed - State Machine’s
EventStateEnter/EventStateExitfor transition notifications - Update must be called by the developer (from MonoBehaviour’s Update)
- The constructor requires an initial State
Spatial Hash
A fast non-physics-based spatial query. Radius searches in O(log n).
// Domain (static class)
public static class MySpatialHash
{
public static SpatialHash Value { get; private set; } = new SpatialHash();
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void OnSubsystemsInit() => Value = new SpatialHash();
}
// Implement ISpatialHash on target
public class MyComponent : MonoBehaviour, ISpatialHash
{
void OnEnable() => MySpatialHash.Value.Insert(this);
void OnDisable() => MySpatialHash.Value.Remove(this);
void Update() => MySpatialHash.Value.Update(this);
Vector3 ISpatialHash.Position => this.transform.position;
int ISpatialHash.UniqueCode => this.gameObject.GetInstanceID();
}
// Query
var list = MySpatialHash.Value.Query(new Vector3(0,0,0), 10f);
- Skipping Update calls on frames where position hasn’t changed is an optimization
- Truly shines when many queries are made per frame
Variables API
An API for reading and writing variable runtime values from scripts. See the “Variables API” section in the Variables article for details.
Save & Load
A flexible save/load system. The default uses Unity’s PlayerPrefs, but both the storage backend and encryption can be custom-built.
Storage Location
- Default: PlayerPrefs
- Switchable via dropdown. Can be replaced with custom storage (your own DB / cloud)
Encryption
| Type | Description |
|---|---|
| None | No encryption (default) |
| XOR | Simple obfuscation via XOR with a passphrase |
| Caesar | Shifts each character by a specified amount |
| Custom | Freely implementable with a custom class (see below) |
Saveable Types
- Primitives (int / bool / string / Vector / Quaternion)
- Managed classes/structs with
[System.Serializable] - Types inheriting from
UnityEngine.Object(GameObject / Transform / MonoBehaviour, etc.) cannot be saved
Slots (Save Slots)
- Identified by integers 1 to 999
- Slot 0 is reserved for shared settings (values shared across all slots)
Save / Load / Delete (API)
// Save (returns Task. PlayerPrefs blocks the main thread)
_ = SaveLoadManager.Instance.Save(1);
// Or await in an async function
await SaveLoadManager.Instance.Save(1);
// Load (unloads current scene and reloads the scene from save time)
_ = SaveLoadManager.Instance.Load(1);
// Delete
_ = SaveLoadManager.Instance.Delete(1);
Events (6 Types)
SaveLoadManager.Instance.EventBeforeSave += slot => {};
SaveLoadManager.Instance.EventAfterSave += slot => {};
SaveLoadManager.Instance.EventBeforeLoad += slot => {};
SaveLoadManager.Instance.EventAfterLoad += slot => {};
SaveLoadManager.Instance.EventBeforeDelete += slot => {};
SaveLoadManager.Instance.EventAfterDelete += slot => {};
Always unsubscribe in OnDestroy or similar.
Custom Data — IGameSave Interface
A mechanism to mark any component as “saveable”.
| Property / Method | Meaning |
|---|---|
string SaveID | Unique ID identifying this data |
bool IsShared | Whether this value is shared across all save slots |
Type SaveType | The type to save |
object SaveData | The instance to save |
LoadMode LoadMode | Lazy (typical, ~90%) / Greedy (for cross-scene surviving objects) |
void OnLoad(object value) | Called on load. Cast value to the appropriate type and restore |
Example implementation for saving whether a treasure chest has been opened:
public class MyChest : MonoBehaviour, IGameSave
{
public bool hasBeenOpened = false;
void OnEnable() => _ = SaveLoadManager.Subscribe(this);
void OnDisable() => _ = SaveLoadManager.Unsubscribe(this);
public string SaveID => "my-chest";
public bool IsShared => false;
public Type SaveType => typeof(bool);
public object SaveData => this.hasBeenOpened;
public LoadMode LoadMode => LoadMode.Lazy;
public void OnLoad(object value) => this.hasBeenOpened = (bool)value;
}
LoadMode (Lazy vs. Greedy)
- Lazy: Restores when the target object is created. This works for the majority of cases
- Greedy: For objects surviving via
DontDestroyOnLoad/ singletons. Restored immediately on the load event
Custom Storage (TDataStorage)
[Title("My Online Database")]
[Category("My Online Database")]
[Image(typeof(IconDiskSolid), ColorTheme.Type.TextLight)]
[Description("Stores the data in a custom database location")]
[Serializable]
public class MyOnlineDatabase : TDataStorage
{
public override Task DeleteAll() { /* ... */ }
public override Task DeleteKey(string key) { /* ... */ }
public override Task<bool> HasKey(string key) { /* ... */ }
public override Task<object> Get(string key, Type type) { /* ... */ }
public override Task Set(string key, object value) { /* ... */ }
public override Task Commit() { /* ... */ }
}
- Recommended naming convention:
Storage<Name> Commitis for batch commits after bulk writes
Custom Encryption (TDataEncryption)
[Title("My Custom Encryption")]
[Serializable]
public class EncryptionMyCustom : TDataEncryption
{
[SerializeField] private string privateKey;
[SerializeField] private int salt;
public override string Encrypt(string input) { /* ... */ }
public override string Decrypt(string input) { /* ... */ }
}
[SerializeField]fields appear directly in the Settings screen
Remember Component
A component for finely selecting “what to save” on a per-GameObject basis. By default, it saves position, rotation, and scale.
Adding Memories
Select a type and add via the Add Memory button. A single component can hold multiple Memories.
Custom Memory / Token
[Serializable]
public class MemoryName : Memory
{
public override string Title => "Name of Game Object";
public override Token GetToken(GameObject target) => new TokenName(target);
public override void OnRemember(GameObject target, Token token)
{
if (token is TokenName tokenName) target.name = tokenName.text;
}
}
[Serializable]
public class TokenName : Token
{
public string text;
public TokenName(GameObject target) : base() => this.text = target.name;
}
- Memory classes can use decorators like
[Title],[Category],[Image],[Description]
Tweening (Interpolation Animation)
A lightweight API that interpolates from a start value to an end value over a specified duration. Convenient for opening a door 2m upward, fading UI alpha, gradually changing colors, and similar tasks.
Basic Usage
Vector3 start = door.position;
Vector3 end = door.position + Vector3.up * 2;
float duration = 5f;
ITweenInput tween = new TweenInput<Vector3>(
start,
end,
duration,
(a, b, t) => door.position = Vector3.Lerp(a, b, t), // updateCall
Tween.GetHash(typeof(Transform), "transform"), // hash
Easing.Type.QuadInOut // easing
);
Tween.To(door.gameObject, tween);
Parameters
| Field | Meaning |
|---|---|
start / end | Start and end values. Works with any type — Vector3, float, Color, Quaternion, etc. |
duration | Duration in seconds for the interpolation |
updateCall | Function called every frame. Receives (start, end, ratio) and applies the interpolated result |
hash | Identifier for this Tween. Starting a different Tween with the same hash auto-cancels the previous one |
easing | Easing function (linear if unspecified) |
Custom Installs (Sample Distribution)
A mechanism that lets module developers distribute “examples/templates for their modules” through the Install... window.
Two Folders
- Installer: Distribution source. Contains the Installer settings asset +
Package.unitypackage - Installation Location: Install destination. Fixed at
Assets/Plugins/Game Creator/Installs/<ModuleName>.<ExampleName>@<Version>/
Installer Asset
- Create: Right-click in Project →
Create > Game Creator > Developer > Installer - Naming convention:
<ModuleName>.<ExampleName> - Main settings:
- Name / Module: Affects categorization
- Description / Author: For informational display
- Version: Semantic version (must increment on updates)
- Complexity: Difficulty display
- Dependencies: Can specify dependencies on other examples (module + example ID)
Dependencies
The Install window automatically resolves and installs dependencies. If a dependency is not found, it shows an error and aborts.
Domain Reload Handling
GC2 supports Unity’s Domain Reload skip. To shorten reload time when switching to Play mode:
- Open
Edit > Project Settings > Editor > Enter Play Mode Settings - Turn Enter Play Mode Options ON
- Turn Reload Domain OFF
GC2’s singletons are designed to remain intact even with this configuration (recommended in the official guide).
Visual Scripting Reference
A summary of Visual Scripting nodes related to Advanced features.
Instructions (Storage / Audio / Visual Scripting)
| Category | Instruction | Overview |
|---|---|---|
| Storage | Save Game | Saves to a specified slot |
| Load Game | Loads from a specified slot | |
| Load Latest Game | Loads the most recent save | |
| Delete Game | Deletes a slot | |
| Reset Game | Resets the current runtime state | |
| Audio | Play Ambient / Music / Sound Effect / Speech / UI Sound | Plays on each channel |
| Stop Ambient / Music / Sound Effect / Speech On Game Object | Stops playback | |
| Fade All Ambient / Fade All Music | Fades all ambient/BGM | |
| Change Master / Ambient / Music / Sound Effects / Speech / UI Volume | Changes channel volume with time transition | |
| Change Snapshot | Switches AudioMixer snapshot | |
| Audio Source Pitch / Volume | Adjusts individual AudioSources | |
| Audio Mixer Parameter | Changes exposed AudioMixer parameters | |
| Visual Scripting | Emit Signal | Fires a signal |
| Broadcast Message | Sends a message to a target GameObject (Upwards/Downwards) | |
| Invoke Method | Calls a method on any component | |
| Run Actions / Conditions / Trigger | Executes other components (with Wait Until Complete) | |
| Stop Actions / Conditions / Trigger | Stops running components | |
| Restart Instructions | Re-executes own Actions from the beginning | |
| Check Conditions | Early exit on condition failure mid-way (AND/OR selectable) | |
| Activate Hotspots | Toggles Hotspot activation by type |
Conditions (Audio / Storage / Visual Scripting)
| Category | Condition | Check |
|---|---|---|
| Audio | Is Ambient / Music / Sound Effect / Speech / Speech Target / UI Playing | Whether each is currently playing |
| Storage | Has Save | Whether any slot has a save |
| Has Save At Slot | Whether a specified slot has a save | |
| Visual Scripting | Conditions As And | Evaluates nested Conditions with AND |
| Run Conditions As Or | Evaluates nested Conditions with OR |
Events (Audio / Storage / Logic)
| Category | Event | Trigger Timing |
|---|---|---|
| Audio | On Change Master / Ambient / Music / Sound Effects / Speech / UI Volume | When volume changes |
| Storage | On Save / On Load / On Delete | When save / load / delete occurs |
| Logic | On Hotspot Activate / Deactivate | When the associated Hotspot’s state changes |
| On Receive Signal | When a signal with the specified ID is received |
Practical Usage — Configuration Guide by Use Case
Context-Based BGM Switching
- On battle start:
Fade All Musicto fade out current BGM →Play Musicfor battle BGM - On battle end: Reverse the procedure. Combining with
Change Snapshotalso switches audio filters
Async Save with Toast Notification
public async void OnSaveClick()
{
uiToast.Show("Saving...");
await SaveLoadManager.Instance.Save(1);
uiToast.Show("Saved!");
}
When using PlayerPrefs it’s effectively synchronous since it blocks, but the key point is that switching to an online DB requires no code changes.
Making Any Script Saveable
- Implement
IGameSaveandSubscribeinOnEnable,UnsubscribeinOnDisable - IDs must be unique strings or collisions will occur
Signal Use Cases
- UI updates:
Emit Signalwith"score-changed"inside a Variable change Trigger → multiple HUDs/screens subscribe - Tutorial progression: Advance to the next step with a
"tutorial-step-3-ok"signal known only to the tutorial system
UI Fade with Tween
CanvasGroup group = ...;
float start = 0f, end = 1f, dur = 0.5f;
Tween.To(group.gameObject, new TweenInput<float>(
start, end, dur,
(a, b, t) => group.alpha = Mathf.Lerp(a, b, t),
Tween.GetHash(typeof(CanvasGroup), "alpha"),
Easing.Type.QuadInOut
));
Starting a different Tween with the same hash auto-cancels the previous one, so there are no conflicts.
Spatial Hash + Perception Complement
When the Perception module’s Sight/Hearing becomes heavy with many agents, applying a rough proximity filter with Spatial Hash before running Perception’s detailed checks improves performance.
Game Director with Singleton
public class GameDirector : Singleton<GameDirector>
{
public int stageIndex;
protected override bool SurviveSceneLoads => true;
}
// Usage: GameDirector.Instance.stageIndex = 3;
Level Up! The Guide to Great Video Game DesignView on Amazon →
Introduction to Game Design, Prototyping, and DevelopmentView on Amazon →
Official Links
Summary
In this article, we covered the Advanced features of Game Creator 2.
From audio management with 5-channel Audio, loosely-coupled communication with Signals, rich Data Structures, a flexible Save & Load system, to interpolation animation with Tweening — cross-cutting features useful in various game development scenarios are all available.
The Save & Load system in particular has a flexible design where simply implementing the IGameSave interface makes any data saveable, with customizable storage backends and encryption.
We hope you’ll check out our other articles as well.
📚 Series: Game Creator 2 Complete Guide (6/16)