Small Components
Part of the Game Architecture in Unity section of Coddy's Unity journey. Lesson 1 of 64.
A GameObject is a list of components, and each script you write is one more of them. Unity games are built by giving each script one job and putting several scripts on an object. A player's moving, shooting and hit points could all live in one PlayerController, but as three components, Mover, Shooter and Health, each one can go on other objects too:
public class Health : MonoBehaviour
{
public int hp = 3;
public void TakeDamage(int amount)
{
hp -= amount;
if (hp <= 0)
{
Destroy(gameObject);
}
}
}- Player: Mover, Shooter, Health
- Turret: Shooter, Health
- Crate: Health
With plain C# classes you might build a tree instead: Character, then ShootingCharacter : Character, then Player : ShootingCharacter. A turret shoots but never walks and a crate only breaks, so every new kind of object means reshaping the tree. With components, a new kind of object is a new mix of scripts that already exist, put together in the Inspector, and each script can have its own values there: a slow Mover on one object, a fast one on another.
Components on one object share its Transform, so each should change only the part it owns. A Mover that adds to x and z with transform.position += leaves y alone, so a Jumper on the same object can still change the height. A Mover that set the whole position to new Vector3(x, 0.5f, z) would put y back every frame and cancel the jump.
Challenge
EasySplit Boat.cs so each script does one job.
- Move the bobbing into
Bobber:startYset inStart(), the bobbing inUpdate(), using its ownheightandspeed. - Move the blinking into
Blinker, with its own timer. - Delete both jobs and their fields from
Boat, so it only steers.
Press Play: the duck bobs, the buoy blinks, and the boat steers. Then Check.
Try it yourself
using UnityEngine;
using UnityEngine.InputSystem;
// One script, three jobs: steering, bobbing and blinking.
public class Boat : MonoBehaviour
{
public float speed = 3f;
public float bobHeight = 0.1f;
public float bobSpeed = 2f;
public Renderer lamp;
public float blinkInterval = 0.5f;
private InputAction moveAction;
private float startY;
private float blinkTimer;
void Start()
{
moveAction = InputSystem.actions.FindAction("Move");
startY = transform.position.y;
}
void Update()
{
// steering
Vector2 input = moveAction.ReadValue<Vector2>();
transform.position += new Vector3(input.x, 0f, input.y) * speed * Time.deltaTime;
// bobbing
Vector3 p = transform.position;
p.y = startY + Mathf.Sin(Time.time * bobSpeed) * bobHeight;
transform.position = p;
// blinking
blinkTimer += Time.deltaTime;
if (blinkTimer >= blinkInterval)
{
blinkTimer -= blinkInterval;
lamp.enabled = !lamp.enabled;
}
}
}
All lessons in Game Architecture in Unity
1Components, Not Hierarchies
Small ComponentsA Base Enemy ScriptAbstract ComponentsComponents Working TogetherRecap: Modular TurretRecap: Twin Cannon4Serialized Data
Serializable ClassesLists in the InspectorEnums in the InspectorRecap: Loot TableRecap: Roll the Loot2Interfaces in Unity
IDamageableInterfaces and TryGetComponentGetComponentsRecap: Interact KeyRecap: Nearest in ReachPractice on your own: Unity playground