Creating & Using Scripts
๐ About T#
T# (pronounced T-Sharp) is Terra Studioโs scripting language, designed to feel familiar to Unity developers with a syntax similar to C#. It gives creators the freedom to write custom logic for their games .
If you already know Unity C#, youโll feel right at home. However, T# has a few important differences to support live editing and interpreted execution.
๐ ๏ธ Creating & Using Scripts in Terra Studio
โจ Step 1: Add the TerraMachine Component
In the latest Terra Studio workflow, scripts are attached to GameObjects through the TerraMachine
component.
To set this up:
Select your GameObject in the scene.
In the right-hand Inspector panel, click "Add Component".
Search for and add the
TerraMachine
component.In the dropdown, select the T# script you want this machine to run.
๐ก You must create the script before assigning it in the TerraMachine (see below).
โจ Step 2: Create a T# Script
Open the Scripts tab in the left panel.
Click the โ button to create a new script.
Name the script and press Enter.
Your script will open in Visual Studio Code, along with all other project scripts.
Youโll find your file in the Scripts Directory.
Now, edit the generated class to implement your desired game behavior.
๐ฆ Anatomy of a Script
Hereโs what a default T# script looks like:
using System;
using System.Collections;
using Terra.Studio;
using Terra.Studio.Exposed;
using Terra.Studio.Exposed.Layers;
using UnityEngine;
public class MyFirstScript : TerraBehaviour
{
private void Start()
{
// Initialization logic
}
private void Update()
{
// Frame-based logic
}
}
๐งฌ Key Concepts:
All scripts must extend
TerraBehaviour
orTerraNetBehaviour
(for multiplayer).The class name must match the file name.
Start()
runs once at the beginning.Update()
runs on every frame.
๐พ Multiplayer Scripting
For networked games, extend TerraNetBehaviour
instead:
public class MyMultiplayerScript : TerraNetBehaviour
{
public override void OnNetworkSpawn()
{
// Initialization when object spawns on network
}
public override void OnNetworkDespawn()
{
// Clean-up when object despawns
}
}
These methods are called automatically during multiplayer object lifecycles.
๐ช Setting Up Variables in the Unity Editor
To define variables for your script:
Select a GameObject in your Unity scene.
In the Inspector, add a TerraMachine component.
Select the T# script you want this object to run.
Once selected, a new section called Object Variables will appear below the script field.
Click the + icon to add a new variable.
You can create one of four types:
String
Float
Int
GameObject
Each variable must have:
A unique name
An initial value that the script can read when the game starts
These variables can only be accessed from the script attached to the same TerraMachine. They are not shared globally or across multiple objects unless explicitly managed.
๐งช Accessing Variables in T# Scripts
To use these variables in your script, you must:
Declare local variables inside your script to store their values.
Use Terraโs built-in getter methods like
GetFloatVariable()
orGetStringVariable()
inside a function likeStart()
to retrieve them.
โ Example: Accessing a string variable
Let's say you've added a string variable named myName
to a GameObjectโs TerraMachine and set it to "Terra"
.
using System;
using System.Collections;
using Terra.Studio;
using UnityEngine;
public class MainPlayer : TerraBehaviour
{
private string myVar; // Local variable to store the editor-defined value
void Start()
{
myVar = GetStringVariable("myName");
Debug.Log("I am alive and my name is " + myVar);
// Output: "I am alive and my name is Terra"
}
}
If the variable "myName"
does not exist on this object, your code will throw an error at runtime. You will also get an error if
๐งฉ Example: Accessing Multiple Types of variables
You can also fetch multiple variables of different types in one script:
public class MyFirstScript : TerraBehaviour
{
// Declare variables to store values fetched from Object Variables
private float myFloat;
private string myString;
private int myInt;
private GameObject myGameObject;
private void Start()
{
myFloat = GetFloatVariable("speed");
myString = GetStringVariable("label");
myInt = GetIntVariable("score");
myGameObject = GetGameObjectVariable("target");
// You can now use these variables in Update or other methods
}
private void Update()
{
// Example usage
transform.Translate(Vector3.forward * myFloat * Time.deltaTime);
}
}
Note that all variables values are assigned in the Start() method
โ๏ธ Event Functions in Terra Studio
In Terra Studio, you donโt write continuous loops like in traditional programming. Instead, the engine calls event functions in response to gameplay events โ such as object initialization, collisions, updates per frame, user clicks, and more.
If youโve worked with Unity before, this will feel very familiar. However, keep in mind that you are writing T# scripts that run inside the TerraMachine component added to GameObjects in your Unity scene.
T# supports a subset of Unity-style lifecycle methods, along with some limitations. This section outlines which events are supported and how to use them effectively.
โถ๏ธ Game Lifecycle Events
Start()
Start()
The Start
method runs once at the beginning of a GameObjectโs lifecycle โ just after all variables and components have been initialized. This is where you should fetch object variables, set up references, or run any custom initialization logic.
private void Start()
{
Debug.Log("GameObject has started!");
}
Update()
Update()
The Update
method is called once per frame. Use this for dynamic logic such as input handling, movement, or timers.
private void Update()
{
float distance = speed * Time.deltaTime * Input.GetAxis("Horizontal");
transform.Translate(Vector3.right * distance);
}
๐ Physics Events
FixedUpdate()
FixedUpdate()
This is used for physics-based updates. It runs at a fixed interval and is ideal for applying forces or detecting rigidbody behavior.
private void FixedUpdate()
{
Vector3 force = transform.forward * driveForce * Input.GetAxis("Vertical");
rigidbody.AddForce(force);
}
Note: LateUpdate()
is not supported in T#. To execute logic after rendering or animations, use a coroutine with WaitForEndOfFrame()
.
โณ Coroutines
T# supports Unity-style coroutines using IEnumerator
. These let you pause and resume logic across multiple frames โ useful for animations, time-based triggers, or conditional delays.
Hereโs a basic coroutine:
IEnumerator Fade()
{
Color c = renderer.material.color;
for (float alpha = 1f; alpha >= 0; alpha -= 0.1f)
{
c.a = alpha;
renderer.material.color = c;
yield return new WaitForSeconds(0.1f); // Waits before next iteration
}
}
You start a coroutine using:
StartCoroutine(Fade());
โฑ Coroutine Timing Example
Letโs say you want to check if an enemy is nearby, but only once every 0.1 seconds:
IEnumerator DoCheck()
{
for (;;)
{
if (ProximityCheck())
{
Debug.Log("Enemy nearby!");
}
yield return new WaitForSeconds(0.1f);
}
}
Start this in Start()
or Update()
:
private void Start()
{
StartCoroutine(DoCheck());
}
๐ฑ Input Event: Mouse Clicks
You can detect when a GameObject is clicked using OnMouseDown()
:
public class ClickHandler : TerraBehaviour
{
private void OnMouseDown()
{
Debug.Log("GameObject clicked!");
doSomething();
}
}
Make sure the GameObject has a collider component to receive click events.
๐ฅ Collision Events
Detect object collisions using OnCollisionEnter
. Combine this with an object variable to filter specific GameObjects.
public class CollisionHandler : TerraBehaviour
{
private GameObject targetObject;
private void Start()
{
targetObject = GetGameObjectVariable("cube");
}
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject == targetObject)
{
Debug.Log("Collided with cube!");
}
}
}
๐ Multiplayer Events
When using TerraNetBehaviour
(instead of TerraBehaviour
), two special methods become available:
public override void OnNetworkSpawn()
{
// Called when this object is spawned on the network
}
public override void OnNetworkDespawn()
{
// Called when this object is removed from the network
}
Use these to initialize or clean up network-specific data.
๐ก Broadcasts (Manual Handling)
In earlier versions of Terra Studio, there was an OnBroadcasted()
method that responded to broadcast messages. This is no longer supported.
To implement custom broadcast behavior:
Use shared variables or flags
Poll for signals in
Update()
or trigger logic manually via coroutines or function callsHandle events using Unity-style component communication (
GetComponent
, method calls, etc.)
Multiplayer-Specific Events
For multiplayer games using TerraNetBehaviour
, there are special network lifecycle methods:
public override void OnNetworkSpawn()
{
// Code to execute when the object spawns on the network
// This is a good place to initialize network variables
}
public override void OnNetworkDespawn()
{
// Code to execute when the object despawns from the network
// Clean up any network-specific resources here
}
๐ก Broadcasts (Manual Handling)
In earlier versions of Terra Studio, there was an OnBroadcasted()
method that responded to broadcast messages. This is no longer supported.
To implement custom broadcast behavior:
Use shared variables or flags
Poll for signals in
Update()
or trigger logic manually via coroutines or function callsHandle events using Unity-style component communication (
GetComponent
, method calls, etc.)
Last updated