Syntax Differences - T# v/s C#

This page lists everything that is currently not supported in T#

This section covers core language-level differences in T# that affect how you write basic logic, class structures, and common C# patterns. These are not Unity-specific, but general constraints imposed by the T# interpreter.

๐Ÿง  MonoBehaviour vs TerraBehaviour

In Unity, scripts connect to the engine by extending the built-in MonoBehaviour class. This allows the script to be attached to GameObjects and use lifecycle methods like Start() and Update(). T# scripts , however, don't inherit from the Monobehaviour Class.

public class MyFirstScript : MonoBehaviour {
    void Start() {
        // Initialization logic
    }

    void Update() {
        // Per-frame logic
    }
}

๐Ÿ” What you instead need to do in T#: All scripts must derive from TerraBehaviour ( (or TerraNetBehaviour in case of multiplayer games) instead of MonoBehaviour. This is the base class recognized by Terra Studioโ€™s runtime for regular game scripts.

public class MyFirstScript : TerraBehaviour {
    void Start() {
        // Initialization logic
    }

    void Update() {
        // Per-frame logic
    }
}

๐Ÿ› ๏ธ Default Variable Assigning

In Unity, it's common (and convenient) to assign default values to variables directly when declaring them. However, this pattern is not supported in T# if the value is assigned outside a method.

private string var1 = "hello world"; // โŒ Not allowed in T#
void Start() {
    // Do something
}

๐Ÿ” What you instead need to do in T# to avoid inline assignment: Always initialize variables inside a method like Start().

private string var1;

void Start() {
    var1 = "hello world"; // โœ… Allowed since you are assigning the value for the variable  within a method
}

๐ŸŽ›๏ธ Serialized Fields

In Unity, developers often use public or [SerializeField] fields to expose values in the Inspector. This lets you easily assign GameObjects, floats, and other data through the Unity Editor.This allows you to assign values directly in the Unity Editor but this method isn't supported in T#.

public float moveSpeed;
[SerializeField] private GameObject target;

๐Ÿ” What you instead need to do in T# to access Inspector-like values:

T# doesnโ€™t support public fields or [SerializeField]. Use built-in variable getter methods instead.

๐Ÿ‘‰ Instead, use the built-in variable getters like the following:

Variable Getter
Description

GetObjectVariable(string name)

Gets GameObject variable with the specified name

GetIntVariable(string name)

Gets integer variable with the specified name

GetFloatVariable(string name)

Gets float variable with the specified name

GetBoolVariable(string name)

Gets boolean variable with the specified name

GetCurveVariable(string name)

Gets AnimationCurve variable with the specified name

// This is allowed in T# since you are using variable getters instead of using Serialized Fields
private float moveSpeed;
private GameObject target;

void Start() {
    moveSpeed = GetFloatVariable("moveSpeed");
    target = GetObjectVariable("target");
}

๐Ÿงฌ Generic Methods

Unity supports generic methods like GetComponent<T>(), AddComponent<T>(), and FindObjectOfType<T>() for flexible and type-safe component handling. These are popular for writing clean, reusable code. However, Generic versions of Unity methods like GetComponent<T>, AddComponent<T>, FindObjectOfType<T>, and similar methods involving generics are not supported in T#.

๐Ÿ” What you instead need to do in T# to work with components:

Instead, in T#, non-generic alternatives should be used such as the following:

// Example of how to use GetComponent without generics
Rigidbody rb = (Rigidbody)gameObject.GetComponent(typeof(Rigidbody)) as Rigidbody;

๐ŸŽฎ Enums

In Unity, developers often use enum to define named states or categories for readability and cleaner switch logic.This is not supported in T#.

enum GameState {
    Playing,
    Paused,
    GameOver
}

๐Ÿ” What you instead need to do in T# to represent states: Use constants (int or string) to represent each state.

private const int STATE_PLAYING = 0;
private const int STATE_PAUSED = 1;
private const int STATE_GAMEOVER = 2;

๐Ÿ”„ Switch

In Unity, switch statements are a clean way to handle multiple branches based on an integer, enum, or string value. This is not supported in T#.

switch (state) {
    case 0:
        // Do something
        break;
    default:
        // Fallback logic
        break;
}

๐Ÿ” What you instead need to do in T#: Use if-else chains to replicate switch behavior.

if (state == 0) {
    // Do something
}
else {
    // Fallback logic
}

๐Ÿ” foreach Loops

foreach is a clean and readable way to iterate over children or elements in a collection without worrying about indexing. Itโ€™s especially popular when working with Transform, GameObject, or any IEnumerable. However, foreach is not supported in T#.

foreach (Transform child in transform) {
    // Do something
}

๐Ÿ” What you instead need to do in T# to avoid foreach:

T# currently doesnโ€™t support foreach, so always use a classic for loop when working with collections or child transforms.

for (int i = 0; i < transform.childCount; i++) {
    Transform child = transform.GetChild(i);
    // Do something
}

Last updated