F01


Learning Outcomes

  • Describe the basics of C# scripting in Unity. For preparation, read the provided descriptions on Unity C# scripting, and if you have time, explore the Unity C# scripting overview for extra context.
  • Set up Visual Studio Code as the external script editor for Unity. Ahead of class, make sure Unity and VS Code are installed, configure VS Code in Unity’s preferences, and add only the “C# for Visual Studio Code” extension.
  • Create and attach a script that inherits from MonoBehaviour. As your pre-class exercise, create a new script, attach it to a GameObject, and log a message in Start() to verify it runs in Play mode.
  • Declare and print variables in C#. Before the session, write code that defines a string, int, and bool, then print each one to the Unity Console with Debug.Log().
  • Use string interpolation for formatted output. Update your script in advance so that it combines multiple variables into a single Debug.Log() statement using string interpolation.
  • Perform and log basic math operations in C#. In your prep work, add code that calculates a value using operators like + or * and outputs the result to the Console.
  • Convert string data to integers using int.TryParse(). Prior to class, implement code that converts a numeric string into an integer with int.TryParse() and logs the result.

C# Scripting in Unity

Unity primarily uses C# (pronounced “C-sharp”) as its scripting language, offering an accessible and powerful way to develop interactive content. Whether you are new to programming or transitioning from another language like C++ or Java, C# provides a modern, flexible, and XR-friendly development environment. C# is essential for developing custom behaviors and immersive interactions in XR applications. In complex, interactive environments like XFactory, where users engage with intelligent systems—from robotic assembly to drone logistics—C# scripting allows you to bring these virtual engineering processes to life.

  • Enables Custom XR Functionality: Unity offers many built-in components (e.g., colliders, rigidbodies, UI elements), but engineering-specific behaviors—like grabbing a CNC tool, triggering a drone delivery, or activating a PLC-driven process—require scripting in C#. With C#, you can define interaction logic using XR Interaction Toolkit and OpenXR for grabbing objects with precise physics, simulating machine states and responses, or managing multi-modal feedback like audio, haptics, and UI overlays in immersive environments.

  • Industry-Standard, Beginner-Friendly: C# is widely adopted in gaming, enterprise, and simulation industries. Its clean syntax, strong type system, and memory safety make it ideal for beginners. C#’s automatic memory management reduces common errors like memory leaks. It is also easier than C++ (used in Unreal Engine) and safer for rapid prototyping in XR environments.

  • Managed Language = Stability: Running on the .NET runtime, C# provides managed execution with garbage collection, helping you build stable, crash-resistant XR applications.

  • Tight Unity Integration: C# scripts integrate directly with Unity through the MonoBehaviour class. MonoBehaviour uses lifecycle methods like Start(), Update(), and OnTriggerEnter() to handle events. You can simply attach scripts to GameObjects in scenes—such as forklifts, robots, or AR terminals—to drive interactivity.

  • Object-Oriented Modeling for XR Systems: Object-Oriented Programming (OOP) enables modular, reusable components—essential for scalable XR development. Model your XR scene using classes that represent RobotArmController.cs, MobileRobotNavigator.cs, and DroneDeliverySystem.cs.

  • Powerful Tooling & IDE Support: Use Visual Studio Code or Visual Studio with features like IntelliSense (helps autocomplete XR APIs), Debugger (step through your logic), and Profiler (optimize frame rate).

  • Rapid Iteration in XR Prototyping: Unity’s live play mode lets you immediately test C# scripts inside your virtual factory. This is vital in XR, where iterative design improves immersion and fast tweaks ensure smooth user interactions (e.g., grabbing, teleporting, UI control).

  • Scalable for Advanced XR Scenarios: C# scales from educational demos to large digital twin simulations. As your app grows to include real-time multimodal data, AI agents, or cloud-based monitoring, your codebase can evolve to meet enterprise-grade needs.

F02

Review Microsoft’s C# Language Documentation, which offers a comprehensive overview of the language, including a guided C# tour, core fundamentals, the C# for Beginners video series, and self-paced Learn C# courses.


Setting Up an IDE

An Integrated Development Environment (IDE) is a one-stop toolset for software development. It typically includes:

  • A code editor (with features like syntax highlighting, code completion, and refactoring tools)
  • A compiler or interpreter (for building and running your code)
  • Debugging tools (to help you inspect variables, monitor execution flow, and fix errors)
  • Additional productivity features (e.g., integrated version control, project navigation, code analysis)

Visual Studio Code

Unity supports multiple IDEs (Visual Studio, Visual Studio Code, JetBrains Rider). Visual Studio Code (VS Code) is particularly popular, especially for students and developers working across different platforms, due to its lightweight footprint, cross-platform compatibility (Windows, macOS, Linux), extensive ecosystem of extensions (including C# development and Unity-specific tools), and active developer community.

01

  • Prerequisites: Before configuring VS Code to work with Unity, confirm the following:
    • Unity is Installed: If you haven’t already, install a recent version of Unity (2020+ recommended). The Unity Hub can help manage versions and project templates.
    • Visual Studio Code is Installed: Download and install the latest version of Visual Studio Code.
    • Unity Editor Project Ready: Open an existing Unity project or create a new one.
  • IDE Preference: To set VS Code as your script editor:
    • In the Unity Editor, go to Edit > Preferences (on macOS, Unity > Settings...).
    • Select External Tools in the left navigation panel.
    • Under External Script Editor, select Visual Studio Code from the dropdown. If VS Code is not shown, select Browse… and locate your VS Code executable.
    • When you double-click a C# script in the Unity Editor, it will now open in VS Code by default.

02

Configuring VS Code

For a full IDE experience—code completion (IntelliSense), debugging, code analysis, and code generation (GitHub Copilot)—you will need specific extensions and Unity packages.

  • VS Code Extensions:
    • C# for Visual Studio Code: Provides core C# editing features like IntelliSense, syntax checking, and basic debugging support.
    • C# Dev Kit: Enhances the base C# extension with richer editing, diagnostics, and code navigation tools.
    • Unity for Visual Studio Code: Offers Unity-specific integrations such as code snippets, event function templates (e.g., Start(), OnTriggerEnter()), and helpful Unity metadata.

03

  • Unity Packages:
    • Unity Visual Studio Editor: (com.unity.ide.visualstudio) This package connects Unity with Visual Studio Code or Visual Studio. Version 2.0.20+ is included with most recent Unity installations.
    • Confirm your External Script Editor is set to VS Code (as described above).

04

The com.unity.ide.vscode package is deprecated. Stick with com.unity.ide.visualstudio, which now supports both Visual Studio and VS Code.

IntelliSense

IntelliSense provides real-time code suggestions and helps reduce syntax errors.

  • Code Completion: Open a C# script and start typing. You should see suggestions for Unity types and methods (e.g., SetActive() or GetComponent<T>()). If suggestions don’t appear, make sure Omnisharp is running and your Unity project is correctly referenced in VS Code.

  • Debugging: In Unity, enable Script Debugging in the play/build configuration. In VS Code, go to the Run and Debug view, select the Unity launch configuration, and click Start Debugging. You can set breakpoints, inspect variables, and trace execution flow.

GitHub Copilot

GitHub Copilot is an AI-powered coding assistant that uses large language models to suggest code completions, generate entire functions, and offer documentation-like guidance as you type. It works directly within your IDE, including VS Code, and can be a valuable companion while scripting in Unity.

  • Code Suggestions and Autocompletion: Copilot can suggest complete lines or blocks of C# code based on your comments or partial input. For example, typing a comment like // Move drone to target position may prompt Copilot to generate a full Update() function using transform.position and Vector3.MoveTowards().

  • Learning Aid and Productivity Booster: Copilot can serve as a real-time coding tutor, demonstrating Unity scripting patterns as you work. It can help you recall Unity API usage or suggest proper syntax when working with components like Animator or Collider.

  • Setup Requirements: You need a GitHub account with Copilot enabled (free for students through GitHub Student Developer Pack). Install the GitHub Copilot extension from the VS Code marketplace. Sign in with your GitHub credentials and authorize the extension.

  • Using Responsibly: Treat Copilot’s suggestions as a starting point. Always review and test the generated code to ensure it fits your logic and doesn’t introduce bugs or inefficiencies.

05

GitHub Copilot is a powerful tool for accelerating development and overcoming coding blocks, but it does not replace understanding the Unity API or C# fundamentals. Use it to support—not substitute—your learning and engineering judgment.


What Is MonoBehaviour?

As we begin working with C# scripts in Unity, it is important to understand what MonoBehaviour is—at a high level for now. MonoBehaviour is a base class from which all Unity scripts derive by default. It provides a wide range of built-in functionality that allows Unity to recognize your script and run specific event-driven methods like Start(), Update(), and OnTriggerEnter(). These methods are called automatically by Unity at appropriate times during the game or simulation loop. You don’t need to write any special code to enable this behavior—just inherit from MonoBehaviour, and Unity takes care of the rest. MonoBehaviour connects your C# code to the GameObject system in Unity. When you create a script and attach it to a GameObject in your scene:

  • Unity treats the script as a Component—just like a Rigidbody, Collider, or Audio Source.
  • Your script gains access to Unity’s game loop and lifecycle.
  • You can define behaviors and interactions that run automatically without needing to call them manually.

Review this Unity documentation to learn more about MonoBehaviour.

Workflow in Unity

  1. Create a new script in Unity. It automatically inherits from MonoBehaviour.
  2. Attach the script to a GameObject (e.g., a robot arm or a cube) using one of the following methods:
    • Drag and Drop: Drag the script from the Project window onto the GameObject in the Hierarchy or Scene window.
    • Inspector Add Component: Select the GameObject, click Add Component in the Inspector, then search for and select the script.
    • From Code: (less common) Use gameObject.AddComponent<ScriptName>(); in another script to attach it programmatically.
  3. Unity runs the appropriate methods based on what’s happening in the game or simulation. For example, Unity calls Start() once when the GameObject is initialized, Update() once per frame, or OnTriggerEnter() when a collider interacts with another collider.

It is important to remember that MonoBehaviour scripts are always Components. Therefore, they must be attached to an active GameObject to work. Sometimes, it is better to attach custom scripts to an empty GameObject—such as a “Manager” (e.g., TeleportationManager or InteractionManager)—to keep your scene clean, organized, and easier to maintain.

MonoBehaviour Example

Let’s say we want Spot, the quadruped robot in the assembly station, to move forward as soon as the scene starts. You can make it happen using a simple MonoBehaviour script:

  1. Create a New Script:
    • In the Unity Editor, navigate to the Project window.
    • Create a folder where you would like to store your script (e.g., Assets/XFactory/Scripts/Spot).
    • Right click on the folder and select Create > MonoBehaviour Script. Name the script SpotWalker.cs.

      The name of the script file must exactly match the class name inside the script to avoid compilation errors in Unity.

  2. Attach the Script to the GameObject:
    • In the Hierarchy window, select the quadruped robot GameObject (Spot).
    • Either drag the SpotWalker.cs script from the Project window into the Inspector panel of the selected GameObject, or click Add Component in the Inspector, search for MobileRobotMover, and select it.

    06

  3. Write the Script:
    • Double-click the SpotWalker.cs script in the Project window to open it in your code IDE (e.g., VS Code).
    • Replace any existing template code with the following:
    using UnityEngine;
    
    public class SpotWalker : MonoBehaviour
    {
        public float speed = 2.0f;
           
        // The Start() method prints a message when the simulation begins.
        void Start()
        {
            Debug.Log("Quadruped robot initialized.");
        }
    
        // The Update() method moves the robot forward every frame,
        // making it appear to move automatically.
        void Update()
        {
            // Move the robot forward continuously
            transform.Translate(Vector3.forward * speed * Time.deltaTime);
        }
    }
    
  4. Test the Movement:
    • Click the Play button at the top of the Unity Editor to enter Play mode.
    • Adjust the public Speed variable from the Inspector and observe the effect.
    • The robot should automatically begin moving forward, following the logic defined in your script.

    07


Data & Variables in C#

In Unity development with C#, data storage and manipulation are essential for creating responsive, dynamic XR applications. C# is a strongly-typed language, which means every variable must be declared with a specific data type. This helps prevent type mismatches and supports clear, maintainable code.

Example Scene

In the remainder of this session, we will review core C# concepts by writing simple MonoBehaviour scripts. Instead of logging output in Unity’s Console with Debug.Log(), let’s create an interactive experience at XFactory’s manufacturing station, where script results appear on a large display screen (Display GT) when you press a Play button.

  1. Set Up the Display Canvas:
    • Follow the instructions in B4 > UI Fundamentals to add a Canvas to Display GT.
    • Set the Canvas to World Space.
    • Add a Text - TextMeshPro UI element to display messages.
    • Add a Button and set its icon to a Play symbol (>). F03
  2. Create a Manager Object:
    • In the Hierarchy, right-click on the same Canvas and select Create Empty.
    • Rename it to ScriptDebugger.
    • This empty GameObject will hold your custom script and keep your scene organized.
  3. Hook Up the Button Event:
    • Select the play button.
    • In the OnClick() section, add the ScriptDebugger GameObject.
    • Choose SetActive (bool) and check the box to activate the debugger when the button is pressed.

    F04

  4. Create the C# Script:
    • In the Project window, right-click the Scripts folder.
    • Select Create > MonoBehaviour Script, and name it CsharpFundamentals.
    • Double-click to open it in your IDE (e.g., VS Code).
    • Replace the default content with the following:
     using UnityEngine;
     using TMPro;
    
     public class CsharpFundamentals : MonoBehaviour
     {
         public TMP_Text myText; // Reference to the display text
    
         void Start()
         {
             myText.text = "Hello, Jackets!"; // Display message at start
         }
    
         void Update()
         {
             // Future logic can go here
         }
     }
    
  5. Configure the Script in Inspector:
    • Attach the CsharpFundamentals script to the ScriptDebugger GameObject.
    • Drag the Text - TextMeshPro element from the Canvas into the myText field in the Inspector.
    • Deactivate the ScriptDebugger GameObject by unchecking the box on the top left side of its Inspector, as we want it to be activated on button press.

    F05

  6. Run the Scene:
    • Press Play in Unity.
    • Click the play button (>) on the display.
    • The message "Hello, Jackets!" should appear on the Display GT.

    F06

Attaching utility scripts like this to empty GameObjects (such as a ScriptDebugger, InteractionManager, or TeleportationManager) helps keep your scene hierarchy clean and modular. This display-based logging system will be used throughout this session to visually debug and review your C# learning progress.

Literals

A literal is a hardcoded, constant value directly used in code. Literals are used to define specific values like strings, numbers, characters, and booleans in your scripts. The following updated CsharpFundamentals script introduces important literals in C# and shows the result on the display at XFactory’s manufacturing station:

using UnityEngine;
using TMPro;

public class CsharpFundamentals : MonoBehaviour
{
    public TMP_Text myText; // Reference to the display text

    void Start()
    {
        // Clear previous output
        myText.text = "";

        // String literal
        myText.text += "Loading logistics station...\n";

        // Character literal
        char zoneLabel = 'M';
        myText.text += "Zone label: " + zoneLabel + "\n";

        // Integer literal
        int cncMachineCount = 2;
        myText.text += "CNC machines: " + cncMachineCount + "\n";

        // Float literal
        float droneSpeed = 3.14F;
        myText.text += "Drone speed: " + droneSpeed + " m/s\n";

        // Double literal
        double machiningTolerance = 2.71828;
        myText.text += "Machining tolerance: " + machiningTolerance + " mm\n";

        // Decimal literal
        decimal exhibitBudget = 10.25m;
        myText.text += "Exhibit budget (k$): " + exhibitBudget + "\n";

        // Boolean literal
        bool isWeldingActive = true;
        myText.text += "Is welding station active? " + isWeldingActive + "\n";
    }
}
  • String (string): A sequence of text characters enclosed in double quotes (e.g., "Loading logistics station...").
  • Character (char): A single character enclosed in single quotes (e.g., 'R').
  • Integer (int): Whole numbers, both positive and negative (e.g., 2, -20, 2025).
  • Floating-Point Numbers (float, double): Numbers with decimal points. Use float with an F suffix for lower precision (e.g., 3.14F). Use double for higher precision without a suffix (e.g., 2.71828)
  • Decimal (decimal): High-precision decimal values, typically used for financial calculations. Note that it requires an m or M suffix (e.g., 10.25m).
  • Boolean (bool): Represents a truth value—either true or false.

F07

Variables

A variable is a named container used to store information in your program. You define a variable by specifying its type followed by its name. In the CsharpFundamentals.cs script above, we use variables to represent real-world values from the XFactory environment. Here are examples from the script that demonstrate different literal types stored in variables:

  • string factoryName = "XFactory"; — the name of the facility.
  • int cncMachineCount = 2; — number of CNC machines in the production area.
  • bool isWeldingActive = true; — status of the welding station.
  • char zoneLabel = 'M'; — identifier for the manufacturing zone.
  • float droneSpeed = 3.14F; — speed of a drone in meters/second.
  • double armTolerance = 2.71828; — movement tolerance of robotic arms.
  • decimal exhibitBudget = 10.25m; — high-precision budget for installations (in thousands).

Declaring First, Naming Later: You can declare a variable without giving it a value right away:

int robotCount;
robotCount = 3;

Modifying Variables: Variables are mutable—you can update their values as the application runs:

int score = 0;
score += 10;

Variable Naming Rules:

  • Must begin with a letter or underscore (_).
  • Cannot begin with a number.
  • Cannot contain special characters except underscores.
  • Cannot use C# reserved keywords (e.g., class, public, int)
  • Are case-sensitive — status and Status are treated as different variables

Variable Naming Conventions: Use the camelCase style for naming local variables. This means the first word starts with a lowercase letter, while each additional word starts with an uppercase letter. Choose names that are descriptive but concise—your goal is clarity, not cleverness.

  • Good examples: robotName, droneStatus, isEngineInstalled.
  • Avoid: iei (too vague), PName (doesn’t follow camelCase), 123score (starts with a number).

Data Types

Choosing the correct data type helps optimize memory, improve performance, and prevent bugs. Unity uses both standard C# types and Unity-specific types extensively in XR development. In the CsharpFundamentals.cs script, we explored several key data types through meaningful examples tied to real-world XR scenarios.

  • Value Types: Value types store their actual data directly in memory. When copied, a completely new and independent copy is created. Examples from the script:

  • int cncMachineCount = 2; — number of CNC machines in production.
  • float droneSpeed = 3.14F; — drone speed in meters per second.
  • double armTolerance = 2.71828; — precision movement tolerance.
  • decimal exhibitBudget = 10.25m; — high-precision financial value.
  • char zoneLabel = 'M'; — single-character zone label.
  • bool isWeldingActive = true; — status flag for welding station.

Unity-specific value type: Vector3 partLocation = new Vector3(3f, 0f, 2f);. (used to represent a part’s position in 3D space). Vector3 is a struct, so it behaves like a value type.

  • Reference Types: Reference types store a reference (or pointer) to the data in memory. When you assign one reference type variable to another, both variables point to the same underlying data. Examples include strings and arrays:

  • string factoryName = "XFactory"; — represents the name of the factory. Although strings behave like value types in many cases, they are technically reference types.
  • Arrays are also reference types. In the script below, droneIDs and backupIDs both reference the same memory location. Modifying one affects the other.

    int[] droneIDs = new int[2];
    int[] backupIDs = droneIDs;
    backupIDs[0] = 7; // droneIDs[0] is now also 7
    

    Understanding the difference between value and reference types is critical for managing object behavior and performance in interactive XR scenes—especially when working with positions, settings, and real-time updates.

Implicitly Typed Variables

The var keyword lets C# infer the variable’s type based on the value assigned during declaration. It can make code shorter and cleaner—especially when the type is obvious from context. Examples from the he CsharpFundamentals.cs script include:

var robotName = "Robot1";   // Inferred as string
var distance = 12.5f;       // Inferred as float

Important Considerations:

  • Implicitly typed variables must be initialized at declaration. You cannot declare a var without assigning a value (e.g., var x; leads to compilation error).
  • Type is fixed after inference. Once the compiler infers the type, it cannot be changed. For example, var score = 10; is inferred as int. Later assigning a float will cause an error.
  • Use var when:
    • The type is clear from the context. For example, var speed = 5.0f; (obviously a float).
    • You are working with complex or verbose types. For example, var components = GetComponentsInChildren<MeshRenderer>();.
  • Avoid var when:
    • It makes the code less readable.
    • The inferred type is not obvious, which can lead to confusion (e.g., var data = Load(); → What type is data?).
  • Use meaningful variable names to compensate for missing type information when using var.

Unity-Specific Data

Unity extends C# with powerful types that let us control and monitor objects in 3D environments. Here are the key Unity-specific data types:

  • Vector3: Represents 3D positions or directional vectors. Commonly used for moving objects, setting positions, or determining directions. Example:
Vector3 position = new Vector3(0f, 1f, 0f);
transform.position = position;
  • Transform: A core Unity component that holds a game object’s position, rotation, and scale. Directly used to manipulate game objects in the scene. Example:
Transform objectTransform = transform;
objectTransform.position = new Vector3(1f, 2f, 3f);
  • Quaternion: Represents rotations in 3D space without suffering from gimbal lock. Essential for smoothly rotating game objects. Example:
Quaternion rotation = Quaternion.Euler(0f, 45f, 0f);
transform.rotation = rotation;

Example: Let’s build on our previous script to track the real-time position and rotation of the quadruped robot Spot and display it on the Display GT.

  1. Update the Script:
    • Open the CsharpFundamentals.cs script in your IDE.
    • Replace the script with the following:
     using UnityEngine;
     using TMPro;
    
     public class CsharpFundamentals : MonoBehaviour
     {
         public TMP_Text myText;         // Reference to display text
         public Transform spotTransform; // Assign Spot's Transform in Inspector
    
         string staticInfo; // To hold the initial info shown in Start()
    
         void Start()
         {
             staticInfo = "";
             staticInfo += "Loading logistics station...\n";
    
             char zoneLabel = 'M';
             int cncMachineCount = 2;
             float droneSpeed = 3.14F;
             double machiningTolerance = 2.71828;
             decimal exhibitBudget = 10.25m;
             bool isWeldingActive = true;
    
             staticInfo += $"Zone label: {zoneLabel}\n";
             staticInfo += $"CNC machines: {cncMachineCount}\n";
             staticInfo += $"Drone speed: {droneSpeed} m/s\n";
             staticInfo += $"Machining tolerance: {machiningTolerance} mm\n";
             staticInfo += $"Exhibit budget (k$): {exhibitBudget}\n";
             staticInfo += $"Is welding station active? {isWeldingActive}\n";
         }
    
         void Update()
         {
             Vector3 pos = spotTransform.position; // Get the position of the spotTransform
             Vector3 rot = spotTransform.rotation.eulerAngles; // Get the rotation in Euler angles 
    
             myText.text = staticInfo + "\nSpot status:\n";
             myText.text += $"Position: X={pos.x:F2}, Y={pos.y:F2}, Z={pos.z:F2}\n";
             myText.text += $"Rotation: X={rot.x:F1}, Y={rot.y:F1}, Z={rot.z:F1}\n";
         }
     }
    
  2. Configure the Script:
    • Select the ScriptDebugger GameObject.
    • In the Inspector, drag the Spot GameObject into the spotTransform field.

    F08

  3. Run the Scene:
    • Press Play in Unity.
    • Click the play button (>) on the display.
    • You will now see live position and rotation updates on Display GT as Spot moves.

    F09

Unity-Specific Notes

  • Inspector Exposure: Unity’s Inspector allows developers and designers to tweak variables without modifying code. Declaring a variable as public makes it visible and editable in the Inspector, while declaring it as private hides it from the Inspector, helping enforce encapsulation. You can use [SerializeField] with a private variable to expose it in the Inspector without making it publicly accessible in code.

  • Data Persistence: Variables exist only while the GameObject or scene they belong to is active. For data that needs to persist across scenes or game sessions, consider using PlayerPrefs for simple key-value data (e.g., settings, scores) and JSON files for structured and serializable data. ScriptableObjects or Singleton-based managers for runtime state sharing.

  • Variable Scopes: Scope determines where a variable can be accessed. Local scope is declared within a method; accessible only inside that method. Class-level scope is declared directly inside the class (but outside any method); accessible across methods within the class based on access modifiers (public, private, etc.). Variables with broader access should be used carefully to avoid unintended side effects and tightly coupled code.


String Formatting

String formatting is a key programming skill when building interactive XR applications in Unity. Whether you are displaying sensor values in a UI, logging robot states to the Console, or generating real-time messages for diagnostics and alerts, mastering string manipulation makes your C# scripts more readable and functional.

Character Escape Sequences

Escape sequences insert special characters into strings. They start with a backslash \ followed by a character. In Unity, you will often use them in Debug.Log messages for clarity or when formatting multi-line tooltips or logs.

  • \n inserts a new line
  • \t inserts a tab
  • \" inserts a double quote
  • \\ inserts a single backslash

Example:

staticInfo += "XFactory status:\n";
staticInfo += "\tLoading logistics station...\n";
staticInfo += $"\tZone label: {zoneLabel}\n";
staticInfo += $"\tCNC machines: {cncMachineCount}\n";
staticInfo += $"\tDrone speed: {droneSpeed} m/s\n";
staticInfo += $"\tMachining tolerance: {machiningTolerance} mm\n";
staticInfo += $"\tExhibit budget (k$): {exhibitBudget}\n";
staticInfo += $"\tIs welding station active? {isWeldingActive}\n";

F10

String Concatenation

Concatenation combines multiple strings using the + operator. It’s a straightforward method, but can get unwieldy when assembling dynamic scene information.

string station = "Logistics";
int droneCount = 3;

// Basic concatenation for display info
myText.text += "Station: " + station + ", Drones Active: " + droneCount + "\n";

// Real-time operation message
myText.text += "Scanning in progress: " + droneCount + " units at " + station + "\n";

While concatenation works, it can reduce readability—especially when you mix multiple variables or calculations.

String Interpolation

String interpolation allows you to embed variables directly within a string using the $ prefix and {} braces. It produces clean, readable output—perfect for displaying real-time data in XR environments like Display GT. In the CsharpFundamentals.cs script, interpolation is used to show system and robot status clearly:

// Static info using interpolation
staticInfo += $"\tZone label: {zoneLabel}\n";
staticInfo += $"\tCNC machines: {cncMachineCount}\n";
staticInfo += $"\tDrone speed: {droneSpeed} m/s\n";
staticInfo += $"\tMachining tolerance: {machiningTolerance} mm\n";
staticInfo += $"\tExhibit budget (k$): {exhibitBudget}\n";
staticInfo += $"\tIs welding station active? {isWeldingActive}\n";

In the Update() method, interpolation dynamically formats Spot’s transform data:

Vector3 pos = spotTransform.position;
Vector3 rot = spotTransform.rotation.eulerAngles;

myText.text += $"Position: X={pos.x:F2}, Y={pos.y:F2}, Z={pos.z:F2}\n";
myText.text += $"Rotation: X={rot.x:F1}, Y={rot.y:F1}, Z={rot.z:F1}\n";

Note that {pos.x:F2} limits the position values to two decimal places for cleaner display, while {rot.y:F1} limits rotation values to one decimal place for readability.

String interpolation is especially useful for logging XR sensor values, system states, and real-time positions—without needing cumbersome + concatenation.


Math Operations

In Unity-based XR environments like XFactory, C# math operations are essential for scripting dynamic behaviors—such as synchronizing robot movements, calculating CNC cycle times, or converting real-time sensor data into displayable values on the Display GT. Key concepts include:

  • Literal Values: Fixed values typed directly into your code (e.g., 7, 3.14F).
  • Variables: Named storage locations for dynamic data.
  • Operators: Symbols that perform math or logic between values and variables.

Common Operators

  • Addition (+) — Combines two numbers.
  • Subtraction (-) — Subtracts one number from another.
  • Multiplication (*) — Multiplies values together.
  • Division (/) — Divides one number by another. For integers, results are truncated.

Example: Below is a simple math operations example demonstrating the distribution of tasks across drones in the logistics station. Replace the CsharpFundamentals.cs script with the following and test the result:

using UnityEngine;
using TMPro;

public class CsharpFundamentals : MonoBehaviour
{
    public TMP_Text myText;

    void Start()
    {
        int packages = 14;
        int drones = 3;

        myText.text = "Logistics Task Allocation:\n";
        myText.text += $"\tTotal Items: {packages + drones}\n";       // 17
        myText.text += $"\tRemaining Packages: {packages - drones}\n"; // 11
        myText.text += $"\tLoad Spread: {packages * drones}\n";       // 42
        myText.text += $"\tItems per Drone: {packages / drones}\n";   // 4
    }
}

Operator Overloading

In C#, a single operator (like +) can have different meanings depending on its context:

  • Numeric Addition: When both operands are numbers, + adds them.
  • String Concatenation: When at least one operand is a string, + combines them into one string.

Example: Report CNC machine’s assigned task.

using UnityEngine;
using TMPro;

public class CsharpFundamentals : MonoBehaviour
{
    public TMP_Text myText;

    void Start()
    {
        int packages = 14;
        int drones = 3;

        myText.text = "Logistics Task Allocation:\n";
        myText.text += $"\tTotal Items: {packages + drones}\n";       // 17
        myText.text += $"\tRemaining Packages: {packages - drones}\n"; // 11
        myText.text += $"\tLoad Spread: {packages * drones}\n";       // 42
        myText.text += $"\tItems per Drone: {packages / drones}\n";   // 4


        string machineName = "CNC_Mill";
        int partsCompleted = 10;

        myText.text += $"The {machineName} machined {partsCompleted + 5} parts.\n";
        // Output: The CNC_Mill machined 15 parts.
    }
}

Use parentheses to clarify the order of operations when mixing types.

Order of Operations

C# follows standard mathematical conventions (similar to PEMDAS) to decide which operations to perform first:

  1. Parentheses: Operations inside parentheses are computed first.
  2. Multiplication and Division: Performed next, from left to right.
  3. Addition and Subtraction: Performed last, from left to right.

No Exponent Operator: While many languages have an exponentiation operator, C# does not. Instead, use the System.Math.Pow method when you need to raise a number to a power.

Example: Calculating cycle durations.

int fastCycle = 3 + 4 * 5;       // 3 + (4 * 5) = 23
int slowCycle = (3 + 4) * 5;     // (3 + 4) * 5 = 35

myText.text += $"Fast Cycle Time: {fastCycle}\n"; // Output: Fast Cycle Time: 23
myText.text += $"Slow Cycle Time: {slowCycle}\n"; // Output: Slow Cycle Time: 35

Modulus

The modulus operator (%) returns the remainder after division. This is useful for repetitive or periodic behaviors in XFactory simulations, such as rotating a status display every few seconds or checking if an object is at a boundary condition.

Example: Calculating the remainder of a number.

int steps = 7;

myText.text += $"7 % 3 = {steps % 3}\n";  // Output: 1

Compound Assignment

Use compound assignment operators to simplify arithmetic updates. These are commonly used when simulating frame-based updates or physical motion. For example, value += 5 is the same as value = value + 5, value -= 1 subtracts 1 and then assigns the result back to value, and value *= 2 doubles value.

Example: Increasing score.

int score = 10;
score += 5; // Increases score by 5
myText.text += $"Updated Score: {score}\n";

Increment/Decrement

Increment (++) and decrement (--) operators are shorthand operators for increasing or decreasing a variable by 1.

  • Pre-Increment/Pre-Decrement: When placed before a variable (e.g., ++value), the variable is modified before its value is used in any expression.
  • Post-Increment/Post-Decrement: When placed after a variable (e.g., value++), the original value is used first, and then the variable is updated.

Example: Tracking part count in assembly.

int parts = 1;
myText.text += $"Initial Parts: {parts}\n"; // 1

parts++; // Post-increment
myText.text += $"\tAfter parts++: {parts}\n"; // 2

++parts; // Pre-increment
myText.text += $"\tAfter ++parts: {parts}\n"; // 3

parts--; // Post-decrement
myText.text += $"\tAfter parts--: {parts}\n"; // 2

--parts; // Pre-decrement
myText.text += $"\tAfter --parts: {parts}\n"; // 1

F11


Data Conversion

In XR systems and applications, such as simulating digital twins in XFactory, you will often collect or process data from user input, sensors, or external systems. These values are frequently received as string, but calculations, condition checks, and visual feedback require converting that data into proper numeric types like int or float. Converting these string values to numeric types is essential for multiple reasons:

  • Mathematical Operations: To add or compare values, convert strings to numeric types (e.g., int, float).
  • Formatted Output: When displaying results, you might need to convert numbers back to strings using string interpolation.
  • Error Prevention: Not all string values represent valid numbers. Incorrect conversions can throw runtime exceptions or result in data loss.

Implicit Conversion

Unity’s C# compiler automatically converts between compatible types when there’s no risk of data loss (called widening conversion). This often happens when assigning an int to a float or decimal.

int robotCount = 3;
float smoothValue = robotCount;  // Implicit conversion from int to float
myText.text += $"Robots (float): {smoothValue}\n"; // Output: 3.0

Explicit Conversions (Casting)

Casting is an explicit way of converting a value from one data type to another. This is done by placing the desired data type in parentheses before the value. Casting is used when you convert a value from a data type that may hold more information into one that holds less (a narrowing conversion). This is common when converting from a float (or decimal) to an int. Note that casting may truncate values.

float weldingTemp = 75.6f;
int tempRounded = (int)weldingTemp;  // Output: 75
myText.text += $"Rounded Temperature: {tempRounded}°C\n";

Precision with Division:

int partsCompleted = 7;
int shiftHours = 5;

// Without casting → integer division (truncates decimal)
float avgPerHour = (float)partsCompleted / shiftHours;
myText.text += $"Average parts/hour: {avgPerHour}\n";  // Output: 1.4

Using Parse() Methods

Use Parse() to convert a string to a number—ideal when you are sure the input is valid (e.g., controlled kiosk input).

int robotCount = 3;
float smoothValue = robotCount;  // Implicit conversion from int to float
myText.text += $"Robots (float): {smoothValue}\n"; // Output: 3

If the input is invalid (e.g., contains letters), this will throw an exception. Use TryParse() if safety is a concern.

Using the Convert Class

The Convert class can also transform strings into numbers. It offers slightly more flexibility (e.g., with null values), but still throws exceptions on bad input. Convert is part of the System namespace, which contains core C# classes like Convert, Math, DateTime, etc. At the top of your script, add: using System;. We will learn about namespaces later in this module.

string tempInput = "82";
int temp = Convert.ToInt32(tempInput);
myText.text += $"Converted temperature: {temp}°C\n"; // Output: 82°C

Using ToString() for Output

Convert numbers back into strings when building messages, updating UI text, or logging.

float conveyorSpeed = 3.5f;
string speedLabel = conveyorSpeed.ToString("F1");  // 1 decimal place
myText.text += $"Speed Display: {speedLabel} m/s\n"; // Output: 3.5 m/s

Using TryParse() Method

When input may be unreliable (e.g., a user typing via VR keyboard), TryParse() helps you avoid crashes. It returns true if successful, and safely assigns the result via out.

string inputHeight = "175";
int height;

if (int.TryParse(inputHeight, out height))
{
    myText.text += $"Converted height: {height} cm\n";
}
else
{
    myText.text += "Invalid height. Please enter a numeric value.\n";
}

Use TryParse() when building user-facing XR systems—like kiosks, form fields, or machine setup panels—where input may be unpredictable.


Key Takeaways

In this session, we explored the fundamentals of C# scripting in Unity, from setting up Visual Studio Code as our development environment to creating and attaching MonoBehaviour scripts that drive interactive XR experiences. We covered how to declare variables, work with literals, choose appropriate data types, and understand the difference between value and reference types. You learned essential string handling techniques—including concatenation, interpolation, and escape sequences—to produce clear, dynamic output, as well as math operations for real-time calculations and logic. Finally, we examined data conversion methods like casting, Parse(), Convert, and TryParse() to safely handle user input and sensor data. Together, these skills form a solid foundation for building, debugging, and scaling interactive systems in Unity’s immersive environments.