C1. Fundamentals of C#
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 inStart()
to verify it runs in Play mode.- Declare and print variables in C#. Before the session, write code that defines a
string
,int
, andbool
, then print each one to the Unity Console withDebug.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 withint.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 likeStart()
,Update()
, andOnTriggerEnter()
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
, andDroneDeliverySystem.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.
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.
- 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
, selectVisual Studio Code
from the dropdown. If VS Code is not shown, selectBrowse…
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.
- In the Unity Editor, go to
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.
- 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).
- Unity Visual Studio Editor: (
The
com.unity.ide.vscode
package is deprecated. Stick withcom.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()
orGetComponent<T>()
). If suggestions don’t appear, make sureOmnisharp
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 theRun and Debug
view, select the Unity launch configuration, and clickStart 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 fullUpdate()
function usingtransform.position
andVector3.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
orCollider
. -
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.
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
, orAudio 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
- Create a new script in Unity. It automatically inherits from
MonoBehaviour
. - 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 theHierarchy
orScene
window. - Inspector Add Component: Select the GameObject, click
Add Component
in theInspector
, then search for and select the script. - From Code: (less common) Use
gameObject.AddComponent<ScriptName>();
in another script to attach it programmatically.
- Drag and Drop: Drag the script from the
- 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, orOnTriggerEnter()
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:
- 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 scriptSpotWalker.cs
.The name of the script file must exactly match the class name inside the script to avoid compilation errors in Unity.
- In the Unity Editor, navigate to the
- Attach the Script to the GameObject:
- In the
Hierarchy
window, select the quadruped robot GameObject (Spot
). - Either drag the
SpotWalker.cs
script from theProject
window into theInspector
panel of the selected GameObject, or clickAdd Component
in theInspector
, search forMobileRobotMover
, and select it.
- In the
- Write the Script:
- Double-click the
SpotWalker.cs
script in theProject
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); } }
- Double-click the
- Test the Movement:
- Click the
Play
button at the top of the Unity Editor to enterPlay
mode. - Adjust the public
Speed
variable from theInspector
and observe the effect. - The robot should automatically begin moving forward, following the logic defined in your script.
- Click the
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.
- Set Up the Display Canvas:
- Follow the instructions in B4 > UI Fundamentals to add a
Canvas
toDisplay 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 (>).
- Follow the instructions in B4 > UI Fundamentals to add a
- Create a Manager Object:
- In the
Hierarchy
, right-click on the sameCanvas
and selectCreate Empty
. - Rename it to
ScriptDebugger
. - This empty GameObject will hold your custom script and keep your scene organized.
- In the
- Hook Up the Button Event:
- Select the play button.
- In the
OnClick()
section, add theScriptDebugger
GameObject. - Choose
SetActive (bool)
and check the box to activate the debugger when the button is pressed.
- Create the C# Script:
- In the
Project
window, right-click theScripts
folder. - Select
Create > MonoBehaviour Script
, and name itCsharpFundamentals
. - 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 } }
- In the
- Configure the Script in
Inspector
:- Attach the
CsharpFundamentals
script to theScriptDebugger
GameObject. - Drag the
Text - TextMeshPro
element from the Canvas into themyText
field in theInspector
. - Deactivate the
ScriptDebugger
GameObject by unchecking the box on the top left side of itsInspector
, as we want it to be activated on button press.
- Attach the
- Run the Scene:
- Press Play in Unity.
- Click the play button (>) on the display.
- The message
"Hello, Jackets!"
should appear on theDisplay GT
.
Attaching utility scripts like this to empty GameObjects (such as a
ScriptDebugger
,InteractionManager
, orTeleportationManager
) 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. Usefloat
with anF
suffix for lower precision (e.g.,3.14F
). Usedouble
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 anm
orM
suffix (e.g.,10.25m
). - Boolean (
bool
): Represents a truth value—eithertrue
orfalse
.
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
andStatus
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
andbackupIDs
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 asint
. Later assigning afloat
will cause an error. - Use
var
when:- The type is clear from the context. For example,
var speed = 5.0f;
(obviously afloat
). - You are working with complex or verbose types. For example,
var components = GetComponentsInChildren<MeshRenderer>();
.
- The type is clear from the context. For example,
- 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 isdata
?).
- 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
.
- 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"; } }
- Open the
- Configure the Script:
- Select the
ScriptDebugger
GameObject. - In the
Inspector
, drag theSpot
GameObject into thespotTransform
field.
- Select the
- 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.
Unity-Specific Notes
-
Inspector Exposure: Unity’s
Inspector
allows developers and designers to tweak variables without modifying code. Declaring a variable aspublic
makes it visible and editable in theInspector
, while declaring it asprivate
hides it from theInspector
, 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) andJSON
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";
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:
- Parentheses: Operations inside parentheses are computed first.
- Multiplication and Division: Performed next, from left to right.
- 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
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.