Summary
A variable is a named container that holds a value the game needs to remember. C# is a statically typed language — every variable must declare its type, and that type cannot change. The four types used throughout Unity game scripting are int, float, bool, and string. Choosing the right type matters: speed can be 2.5 units, but not 2.5 lives.
Key ideas
Core types:
| Type | Stores | Game examples |
|---|---|---|
int | Whole numbers | score, lives, level, health |
float | Decimal numbers | moveSpeed, jumpForce, timer |
bool | true or false | isAlive, isGameOver, isGrounded |
string | Text | playerName, levelName |
Can an int hold a decimal? No. An int stores whole numbers only, and C# will not silently throw away the fractional part for you:
int a = 5.5f; // compile error CS0266: Cannot implicitly convert type 'float' to 'int'.
// An explicit conversion exists (are you missing a cast?)
int b = (int)5.9f; // 5: an explicit cast truncates toward zero (it does not round)
int c = (int)-5.9f; // -5, not -6: toward zero, not down
int d = 7 / 2; // 3: int divided by int is integer division
float e = 7 / 2; // 3 (stored as 3.0): the division happened in ints before the assignment
float f = 7 / 2f; // 3.5: make either operand a float to get a decimal result
int r = Mathf.RoundToInt(5.6f); // 6: round to nearest instead of truncatingMicrosoft’s C# reference states that there is no implicit conversion from float or double to int, and that when you convert a float or double to an integral type explicitly, “this value is rounded toward zero to the nearest integral value” (Microsoft, Built-in numeric conversions (C# reference)). The other direction is fine: float speed = 5; compiles, because every int converts implicitly to float. In Unity, choose the rounding you mean: Mathf.RoundToInt (nearest; a value ending in exactly .5 goes to the even neighbour, so 2.5f becomes 2), Mathf.FloorToInt (down) or Mathf.CeilToInt (up) (Unity Technologies, Scripting API: Mathf.RoundToInt). Integer division is the usual cause of a health bar stuck at 0: currentHealth / maxHealth with two ints is 0 until health is full, so write (float)currentHealth / maxHealth.
const: A value that is fixed at compile time and can never be modified. Use it for values that must not change, such as maximum health or a fixed damage multiplier.
Access modifiers in Unity:
public— accessible from other scripts; also appears in the Inspector.private— accessible only within this script; hidden from the Inspector by default.[SerializeField]— makes aprivatefield visible in the Inspector without making it accessible to other scripts. Preferred overpublicwhen Inspector access is needed but external access is not.
[Header("...")]: An Inspector attribute that adds a bold label above a group of fields. Used to organise related variables visually in the Inspector.
Arrays: An ordered collection of values of the same type. Size is fixed at initialisation. Elements are accessed by their zero-based index; the Length property returns the number of elements.
Fields vs local variables: A field is declared at class level, outside any method. It belongs to the object and remembers its value between calls to Start, Update and other methods. A local variable is declared inside a method or block. It exists only while that method or block is running.
In practice
// Basic type declarations
int score = 0;
int lives = 3;
float moveSpeed = 5.5f; // float literals require the 'f' suffix
bool isAlive = true;
string playerName = "Hero";
// const — value cannot be changed anywhere
private const int MaxHealth = 100;// Inspector-visible fields using public and [SerializeField]
[Header("Player State")]
public int health = 100; // public — visible in Inspector, accessible to other scripts
[SerializeField]
private float jumpForce = 8f; // private — visible in Inspector, not accessible externally// Arrays
int[] coinValues = { 10, 25, 10, 50, 15 }; // initialise with values
string[] levelNames = new string[4]; // initialise empty with size
// Access by index (zero-based)
int first = coinValues[0]; // 10
int last = coinValues[4]; // 15
// Length property
int count = coinValues.Length; // 5Compound assignment operators:
score += 10; // same as: score = score + 10
score -= 5; // same as: score = score - 5
health *= 2; // same as: health = health * 2Tracing state through a small game rule:
[SerializeField] private int health = 100; // field: remembered by the object
private void TakeDamage(int amount)
{
int oldHealth = health; // local variable: exists only during this call
health -= amount; // field changes and stays changed
Debug.Log($"Health changed from {oldHealth} to {health}");
}Read this code in order:
healthstarts as object state and can be seen in the Inspector.amountis supplied by whoever callsTakeDamage.oldHealthtemporarily remembers the previous value so the log message can explain the change.health -= amountchanges the field, so the new value remains after the method ends.
Gotchas
floatliterals must have anfsuffix:5.5fnot5.5. Without it, C# treats the value as adoubleand the assignment will fail to compile.- Putting a decimal into an
intis a compile error (CS0266), and the explicit(int)cast truncates rather than rounds;(int)0.99fis 0. UseMathf.RoundToIntwhen you mean “nearest”. - Dividing two
ints discards the remainder (7 / 2is 3,1 / 2is 0), even if you store the result in afloat. Cast one side tofloatfirst. - Array indices start at zero. An array of 5 elements has indices 0–4; accessing index 5 throws an
IndexOutOfRangeException. - Prefer
[SerializeField] privateoverpublicwhen you only need Inspector access. Making a fieldpublicfor Inspector convenience exposes it to unintended external mutation. constfields are implicitlystatic— they belong to the type, not to an instance. They cannot be modified at runtime and cannot be exposed to the Inspector.- A local variable declared inside
Updateresets every frame. If a timer, score or state flag needs to remember its value, declare it as a field.
Related
- csharp-control-flow — using variables in conditions and loops
- csharp-methods — passing variables as parameters
- monobehaviour-lifecycle — where variable declarations live in a Unity script
- unity-inspector-references — assigning object references in the Inspector