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.
Scene setup (World context)
Section titled “Scene setup (World context)”- A
Canvaswith world-space rendering. - A
Button(UnityEngine.UI.Button) as a child of the Canvas. - A
TextMeshProUGUIas another child for the display. - Optional: a second
Buttonfor reset. - A GameObject with the
ClickCountercomponent. Drag the display text into theDisplayfield. - In the button’s OnClick () list in the inspector, target the
ClickCountercomponent and pick itsOnClickedmethod (void). - In the reset button’s OnClick () list, target
OnResetClicked. CCKWasmProjectDescriptoron 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.
What happens at build time
Section titled “What happens at build time”For each PersistentCall on Button.onClick that targeted a WasmBehaviour:
- The
m_Targetis redirected to the replacementWasmRuntimeBehaviour(same GameObject). - The
m_MethodNameis replaced withTriggerScriptEvent(for void callbacks likeOnClicked). - The serialized method name
"OnClicked"is stored as them_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.
Typed argument examples
Section titled “Typed argument examples”AddAmount(int)— bind to a button withOnClick(Int)(via a customUnityEvent<int>, or configure an inspector mode that supplies an int). The processor inserts aset__InternalEventIntArg(42)+TriggerScriptEventInt("AddAmount")pair.SetLabel(string)— similar forstring.
Only single-argument methods are rewireable. See Events → Script-defined events.
Permission model
Section titled “Permission model”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.
Extensions to try
Section titled “Extensions to try”- Add a
TextMeshProUGUIfor time since last click: computeTime.timedeltas inUpdate. - Add a slider whose
onValueChanged(float)calls apublic void SetFrequency(float)— single float arg is rewireable. - Persist the count across sessions: combine with 05 — File Storage Notepad.
Related
Section titled “Related”- Unity Events Rewiring — full details.
- Events — supported script-method argument types.