NexusScript basics & lifecycle¶
A NexusScript is a C#‑style class that extends NexusBehaviour. You write it as a .cs file in your project; the SDK compiles it with NexusVM and you assign the result to a NexusComponent on a GameObject.
using UnityEngine;
using NexusVM.Unity; // NexusBehaviour + the script APIs
class DoorController : NexusBehaviour
{
public float openAngle = 90f; // public fields show up in the inspector
public Transform door;
protected override void Start()
{
Debug.Log("Door ready.");
}
void OnTriggerEnter(Collider other)
{
if (Player.IdOf(other.gameObject) != "") // a player walked in
door.localRotation = Quaternion.Euler(0, openAngle, 0);
}
}
Adding [Synced] or an RPC later? You need a second using
The attributes live in a different namespace from NexusBehaviour — add
using SocialScape.SDK; as well, or you get CS0246: The type or namespace name
'SyncedAttribute' could not be found. See Networking.
Lifecycle methods¶
The runtime calls these for you (define only the ones you need):
| Method | When |
|---|---|
protected override void Awake() |
once, as the script loads |
protected override void Start() |
once, before the first frame it's active |
protected override void OnEnable() / OnDisable() |
when enabled / disabled |
protected override void Update() |
every frame |
protected override void FixedUpdate() |
every physics step |
protected override void LateUpdate() |
every frame, after Update |
protected override void OnDestroy() |
when removed |
void OnTriggerEnter/Stay/Exit(Collider other) |
physics trigger overlap |
void OnCollisionEnter/Stay/Exit(Collision c) |
physics collision |
Two call styles
Engine lifecycle (Start, Update, …) is declared on NexusBehaviour, so you override it. Physics callbacks (OnTriggerEnter, …) are matched by name, so they're plain methods. Your own custom methods (action handlers, event callbacks like OnPlayerJoined) are also plain public methods.
Public fields → inspector¶
Any public field becomes an inspector slot on the NexusComponent — drag in scene references (a Transform, a Light, an array of NPCs) or set values. This is how you wire a script to your scene without hard‑coding names.
public Light lamp;
public GameObject[] targetNpcs;
public int maxScore = 10;
What you can use¶
- Core C# — variables (incl. multiple in one statement:
int a, b, c;/float x = 0f, y = 1f;),if/for/while/do/foreach/switch, methods,class/struct/enum/interface, generics, arrays (incl. 2‑D and jagged),List/Dictionary/HashSet/Queue/Stack+ LINQ, properties (incl.{ get; set; }),try/catch/finally, lambdas + closures,delegate/event,yielditerators. - Modern C# conveniences — interpolated strings
$"…",??/?.,is Type xpatterns,switchexpressions (x switch { 1 => "a", _ => "b" }), expression‑bodied members (int Area => w*h;,void Hi() => …;),nameof(x), digit separators (1_000),base.Method()/base.Field, tuples ((a, b),var (x, y) = pair;,(int, int) F(), and tupleswitchpatterns(0, 0) => …),string.Format/Join,int.Parse/.ToString(). - Math —
Mathf.*(Mathf.Abs,Mathf.Clamp,Mathf.Lerp,Mathf.PI, …).Math.*works too — it's aliased toMathf, soMath.Abs/Math.Max/Math.PIcompile (results arefloat). Plus fullVector2/3/4,Quaternion,Matrix4x4,Color,Rect,Bounds, andRandom. - Numbers — all the C# numeric types and conversions: every width (
byte…ulong, with real unsigned math), casts, literals (5u,1.5f,0xFF), constants (int.MaxValue,float.NaN), and parsing (int.Parse,int.TryParse(s, out n),Convert.ToInt32). See Numbers, casts & parsing. - Unity value types —
Vector3,Quaternion,Color,Transform,GameObject,Light,Collider, … Debug.Log(...)for console output.- The platform APIs —
Player.*,NPC.*/Self.*,Storage.*,HTTP.*,Json.*.
struct is a reference type here
NexusScript has no value types, so a struct behaves exactly like a class — reference semantics: assigning one struct to another shares the same object (no value‑copy). Use struct freely for little data bundles; just don't rely on struct copy‑on‑assignment.
Not everything from modern C#
A few conveniences aren't in the subset yet: when guards / type‑pattern case, params + optional/named arguments, typeof/default(T). Use overloads instead of optional args. async/await is replaced by coroutines. (Tuples are supported — see Tuples.)
Behaviour & gotchas¶
The catalog tells you what to call; these are the behaviours that decide whether it's correct.
==on objects tests identity.if (hit.transform == myTransform)correctly asks "is it the same object?" — the same object always compares equal however you got the reference. Don't compare.name(duplicates share names). Value types (Vector3,Color,Quaternion) compare by value, as usual. Avoid== nullon an object you've alreadyDestroyd — track that yourself.- Objects are truthy.
if (go)/if (!go)/go ? a : bwork on a GameObject, component, or script reference — they mean "is it not null?", exactly like Unity. (Numbers, strings andVector3/Colorstill need an explicit comparison —if (count > 0), notif (count).) renderer.materialis the SHARED material. Settingrenderer.material.colorrecolours every object using that material. To tint one object, userenderer.SetColor(color)(a MaterialPropertyBlock — sets_Color/_BaseColor). Emission has no per‑instance path, so an emissive glow always changes every copy of the material.- No tween libraries. External tween libraries aren't available — animate by moving a little each
UpdatewithTime.deltaTime+Vector3.Lerp(or a coroutine withWaitForSeconds).Mathf.PingPong/Mathf.MoveTowardsaren't included; useMathf.Sinand clamp yourself. outparameters work, includingPhysics.Raycast(origin, dir, out RaycastHit hit, dist)— then readhit.point/hit.transform/hit.collider. (The API reference shows one Raycast form; theout hit,maxDistance, andlayerMaskvariants all work.)GetComponent<T>is an allowlist. Call it bare (GetComponent<Renderer>(), implicitthis) or on an object (gameObject.GetComponent<T>()) — both work. The whole family is available:GetComponentInChildren<T>/GetComponentInParent<T>(search the hierarchy) and the pluralGetComponents<T>/GetComponentsInChildren<T>/GetComponentsInParent<T>(return aT[]you canforeach/index). Works forTransform,Rigidbody,Collider(s),Renderer(s),AudioSource,Animator,Light,CharacterController,NavMeshAgent,ParticleSystem, and the uGUI/TMP UI types. Blocked (returnsnull):Camera,Canvas,AudioListener,EventSystem. UseCamera.mainfor camera rays.- Silent limits: audio is capped at ~120 plays/second;
Instantiateis rate‑limited and you can onlyDestroyobjects your script created;Physics.gravityandTime.timeScaleare read‑only. Over‑budget calls no‑op rather than error.
What you can't (the sandbox)¶
NexusScript is deliberately limited so worlds are safe to run:
- ❌ No file system, no direct OS / process access.
- ❌ No reflection, no arbitrary .NET libraries.
- ❌ No raw sockets — use
HTTP.*instead.
If something you need isn't reachable, that's usually on purpose — there's typically a safe API for it.
Helpers you'll use a lot¶
Json.FromJsonToDict(jsonString)— parse a JSON string into a dictionary (action params, event data).GameObject.Find(name)— find a scene object by name.
→ Next: the Player API, or see real scripts in Examples.