Unity

[Unity] Game Creator 2 Advanced — Audio, Signals, Save & Load, Tweening

[Unity] Game Creator 2 Advanced — Audio, Signals, Save & Load, Tweening

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.

Complete Article List — Game Creator 2 Complete Guide Series Indexen.senkohome.com/gamecreator2-series-index/

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: IGameSave interface and SaveLoadManager / Remember components
  • 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

ChannelPurposeMain Instructions
AmbientEnvironmental sounds (loop, both diegetic and non-diegetic)Play Ambient / Stop Ambient / Fade All Ambient
MusicBGM (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 defaultPlay Sound Effect / Stop Sound Effect
UIUI operation sounds (hover, click, craft complete, etc. Non-diegetic)Play UI Sound
SpeechCharacter-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 Pitch
  • Audio Source Volume
  • Audio 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) / internally Raise Signal
  • Receive: Set a Trigger’s Event to On Receive Signal and 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.


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.Guid is not serializable, but UniqueID is 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)
  • Instance is 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)
  • foreach enumerates 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 / WhenUpdate per State
  • Events like EventOnEnter / EventOnExit / EventOnBeforeUpdate are also exposed
  • State Machine’s EventStateEnter / EventStateExit for 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

TypeDescription
NoneNo encryption (default)
XORSimple obfuscation via XOR with a passphrase
CaesarShifts each character by a specified amount
CustomFreely 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 / MethodMeaning
string SaveIDUnique ID identifying this data
bool IsSharedWhether this value is shared across all save slots
Type SaveTypeThe type to save
object SaveDataThe instance to save
LoadMode LoadModeLazy (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>
  • Commit is 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

FieldMeaning
start / endStart and end values. Works with any type — Vector3, float, Color, Quaternion, etc.
durationDuration in seconds for the interpolation
updateCallFunction called every frame. Receives (start, end, ratio) and applies the interpolated result
hashIdentifier for this Tween. Starting a different Tween with the same hash auto-cancels the previous one
easingEasing 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:

  1. Open Edit > Project Settings > Editor > Enter Play Mode Settings
  2. Turn Enter Play Mode Options ON
  3. 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)

CategoryInstructionOverview
StorageSave GameSaves to a specified slot
Load GameLoads from a specified slot
Load Latest GameLoads the most recent save
Delete GameDeletes a slot
Reset GameResets the current runtime state
AudioPlay Ambient / Music / Sound Effect / Speech / UI SoundPlays on each channel
Stop Ambient / Music / Sound Effect / Speech On Game ObjectStops playback
Fade All Ambient / Fade All MusicFades all ambient/BGM
Change Master / Ambient / Music / Sound Effects / Speech / UI VolumeChanges channel volume with time transition
Change SnapshotSwitches AudioMixer snapshot
Audio Source Pitch / VolumeAdjusts individual AudioSources
Audio Mixer ParameterChanges exposed AudioMixer parameters
Visual ScriptingEmit SignalFires a signal
Broadcast MessageSends a message to a target GameObject (Upwards/Downwards)
Invoke MethodCalls a method on any component
Run Actions / Conditions / TriggerExecutes other components (with Wait Until Complete)
Stop Actions / Conditions / TriggerStops running components
Restart InstructionsRe-executes own Actions from the beginning
Check ConditionsEarly exit on condition failure mid-way (AND/OR selectable)
Activate HotspotsToggles Hotspot activation by type

Conditions (Audio / Storage / Visual Scripting)

CategoryConditionCheck
AudioIs Ambient / Music / Sound Effect / Speech / Speech Target / UI PlayingWhether each is currently playing
StorageHas SaveWhether any slot has a save
Has Save At SlotWhether a specified slot has a save
Visual ScriptingConditions As AndEvaluates nested Conditions with AND
Run Conditions As OrEvaluates nested Conditions with OR

Events (Audio / Storage / Logic)

CategoryEventTrigger Timing
AudioOn Change Master / Ambient / Music / Sound Effects / Speech / UI VolumeWhen volume changes
StorageOn Save / On Load / On DeleteWhen save / load / delete occurs
LogicOn Hotspot Activate / DeactivateWhen the associated Hotspot’s state changes
On Receive SignalWhen a signal with the specified ID is received

Practical Usage — Configuration Guide by Use Case

Context-Based BGM Switching

  • On battle start: Fade All Music to fade out current BGM → Play Music for battle BGM
  • On battle end: Reverse the procedure. Combining with Change Snapshot also 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 IGameSave and Subscribe in OnEnable, Unsubscribe in OnDisable
  • IDs must be unique strings or collisions will occur

Signal Use Cases

  • UI updates: Emit Signal with "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;


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.

Complete Article List — Game Creator 2 Complete Guide Series Indexen.senkohome.com/gamecreator2-series-index/

We hope you’ll check out our other articles as well.