The Transform
Position, rotation, scale, and parenting
The Transform is the only component every GameObject is guaranteed to have. It answers three questions: where the object is, which way it faces, and how big it is. It also defines the parent-child hierarchy you see in the Hierarchy window.
Local space and world space
This is the single most common source of "why is my object in the wrong place" confusion. Every transform has two sets of coordinates.
| Property | What it means | Note |
|---|---|---|
transform.position | Where it is in the world | Absolute, regardless of parents |
transform.localPosition | Offset from its parent | What the Inspector shows you |
transform.rotation | World rotation (Quaternion) | Absolute facing |
transform.localRotation | Rotation relative to parent | Also a Quaternion |
transform.localScale | Scale relative to parent | The one you normally set |
transform.lossyScale | Approximate world scale | Read-only, and lies under skewed parents |
(0, 0, 0) sits exactly on its parent, which may be nowhere near the world origin.Moving things
There are three common ways to move a transform, and they are not interchangeable.
using UnityEngine;
public class MoveExamples : MonoBehaviour
{
[SerializeField] private float speed = 5f;
private void Update()
{
// 1. Teleport - set the position outright
transform.position = new Vector3(0f, 1f, 0f);
// 2. Offset - add to the current position
transform.Translate(Vector3.forward * speed * Time.deltaTime);
// 3. Interpolate - ease toward a target
transform.position = Vector3.MoveTowards(
transform.position,
target.position,
speed * Time.deltaTime
);
}
}transform.position.x = 5f; does not compile, because position returns a copy of a struct. Build a new Vector3 and assign the whole thing.// Wrong - will not compile
// transform.position.x = 5f;
// Right - replace the whole vector
Vector3 p = transform.position;
p.x = 5f;
transform.position = p;Always multiply by Time.deltaTime
Update runs once per rendered frame, and frame rate varies between machines and moments. If you move by a fixed amount per frame, your game runs faster on a faster computer — which is a real bug, not a curiosity.
private void Update()
{
// 5 units per SECOND, on every machine
transform.Translate(Vector3.forward * 5f * Time.deltaTime);
}private void Update()
{
// 5 units per FRAME.
// 300 units/sec at 60fps, 750 units/sec at 150fps.
transform.Translate(Vector3.forward * 5f);
}Rotation, and why Quaternions
transform.rotation is a Quaternion, not the three angles you see in the Inspector. Quaternions avoid gimbal lock and interpolate cleanly, but they are not human-readable — you should essentially never set their x, y, z, w by hand.
// Build a rotation from readable angles
transform.rotation = Quaternion.Euler(0f, 90f, 0f);
// Turn a little each frame
transform.Rotate(0f, 90f * Time.deltaTime, 0f);
// Face a target
Vector3 direction = target.position - transform.position;
transform.rotation = Quaternion.LookRotation(direction);
// Ease toward a target rotation
transform.rotation = Quaternion.Slerp(
transform.rotation,
targetRotation,
5f * Time.deltaTime
);transform.eulerAngles back does not always give you the numbers you set. Quaternion.Euler(0, 190, 0) may read back as (180, 350, 180) — the same orientation, described differently. Store your own angle in a field if you need to accumulate it.Direction vectors
Every transform exposes its own axes, which is almost always what you want for movement relative to where something is facing.
| Vector | Points toward | Note |
|---|---|---|
transform.forward | The object’s own +Z | Where it is facing |
transform.right | The object’s own +X | Its right-hand side |
transform.up | The object’s own +Y | Its own up, not the world’s |
Vector3.forward | World +Z | Fixed, ignores rotation |
Vector3.up | World +Y | Use for gravity and jumping |
Parenting
Making one transform a child of another means it inherits position, rotation, and scale. Move the parent and the children come along.
// Attach to a parent, keeping the current world position
weapon.transform.SetParent(hand, worldPositionStays: true);
// Attach and snap to the parent's local origin instead
weapon.transform.SetParent(hand, false);
weapon.transform.localPosition = Vector3.zero;
// Detach
weapon.transform.SetParent(null);SetParent(hand, false) plus zeroing the local position. Dropping it is SetParent(null). No custom follow code needed.Two traps worth knowing early
Never scale a physics object non-uniformly
Colliders are scaled by the transform, and non-uniform scale — for example (2, 1, 1) — forces Unity to approximate the collision shape. Capsule and sphere colliders behave especially badly.
Worse, scaling a parent scales every child collider too. If physics feels subtly wrong, check for a scaled parent before you blame the physics settings. Scale the mesh in your 3D tool instead, and keep game object scale at (1, 1, 1).
Do not move Rigidbodies with the Transform
Setting transform.position on an object with a Rigidbody teleports it past the physics engine. Collisions get missed, and fast objects pass straight through walls.
Use rb.MovePosition() and rb.MoveRotation() in FixedUpdate instead, or apply forces and let physics resolve it. This is covered properly in the Colliders & Rigidbodies topic.
What to take away
- The Inspector shows local values;
transform.positionis world. - Multiply every per-frame movement by
Time.deltaTime. - You cannot assign to
transform.position.x— replace the whole vector. - Build rotations with
Quaternion.EulerorLookRotation, never by hand. transform.forwardis object-relative;Vector3.forwardis world-fixed.- Keep scale uniform on anything with a collider.