Skip to content

02 — Click Counter

TL;DR: A UnityEngine.UI.Button.onClick is wired in the Unity inspector to a public method on the ClickCounter behaviour. At CCK build time, that persistent call is rewritten so the click arrives at the WASM guest as a TriggerScriptEvent("OnClicked"). The counter renders into a TextMeshProUGUI label.

  • A Canvas with world-space rendering.
  • A Button (UnityEngine.UI.Button) as a child of the Canvas.
  • A TextMeshProUGUI as another child for the display.
  • Optional: a second Button for reset.
  • A GameObject with the ClickCounter component. Drag the display text into the Display field.
  • In the button’s OnClick () list in the inspector, target the ClickCounter component and pick its OnClicked method (void).
  • In the reset button’s OnClick () list, target OnResetClicked.
  • CCKWasmProjectDescriptor on the content (world) root.

No field on the script holds a reference to the button. UnityEngine.UI.Button isn’t in the WASM binder surface, so keeping one would suggest capabilities the script doesn’t actually have. The wiring lives entirely in the Unity persistent-call system.

using TMPro;
using UnityEngine;
using WasmScripting;
public partial class ClickCounter : WasmBehaviour
{
public TextMeshProUGUI display;
[WasmSerialized] private int count;
void Start() => Refresh();
[ExternallyVisible] public void OnClicked() { count++; Refresh(); }
[ExternallyVisible] public void OnResetClicked() { count = 0; Refresh(); }
[ExternallyVisible] public void AddAmount(int amount) { count += amount; Refresh(); }
[ExternallyVisible] public void SetLabel(string label) { if (display != null) display.text = $"{label}: {count}"; }
private void Refresh()
{
if (display != null) display.text = $"Clicks: {count}";
}
}

Source file: examples/02_ClickCounter.cs.

For each PersistentCall on Button.onClick that targeted a WasmBehaviour:

  • The m_Target is redirected to the replacement WasmRuntimeBehaviour (same GameObject).
  • The m_MethodName is replaced with TriggerScriptEvent (for void callbacks like OnClicked).
  • The serialized method name "OnClicked" is stored as the m_StringArgument.

At runtime, clicking the button fires WasmRuntimeBehaviour.TriggerScriptEvent("OnClicked") which ultimately calls the guest export scripting_call_trigger_script_event with the method name. The guest dispatcher looks up OnClicked on this behaviour and invokes it.

See Unity Events Rewiring for the full mechanism, including the two-call form used for typed arguments.

  • AddAmount(int) — bind to a button with OnClick(Int) (via a custom UnityEvent<int>, or configure an inspector mode that supplies an int). The processor inserts a set__InternalEventIntArg(42) + TriggerScriptEventInt("AddAmount") pair.
  • SetLabel(string) — similar for string.

Only single-argument methods are rewireable. See Events → Script-defined events.

UI interaction runs on the world-context client. ClickCounter is world-context; the call chain goes: Unity input → Button.onClick → persistent call → WasmRuntimeBehaviour → guest export → your method. No CheckAccess failures because no scope-gated binding is touched here.

  • Add a TextMeshProUGUI for time since last click: compute Time.time deltas in Update.
  • Add a slider whose onValueChanged(float) calls a public void SetFrequency(float) — single float arg is rewireable.
  • Persist the count across sessions: combine with 05 — File Storage Notepad.