Skip to content

Camera

Two components: CameraComponent is the camera itself, CameraFollowComponent is the behaviour that makes it track something.

CameraComponent

Priority

Which camera wins when a scene has more than one. Higher takes over. Read and write — switching cameras is a priority change, not an enable/disable dance.

csharp
GetComponent<CameraComponent>().Priority = 10;

OrthographicSize

Half the camera's visible height in world units. Smaller is more zoomed in. Read and write.

csharp
private System.Collections.IEnumerator ZoomTo(float target, float duration)
{
    CameraComponent cam = GetComponent<CameraComponent>()!;
    float start = cam.OrthographicSize, t = 0;
    while (t < duration)
    {
        t += Time.UnscaledDeltaTime;
        cam.OrthographicSize = start + (target - start) * (t / duration);
        yield return null;
    }
}

WorldToScreen(Vector3 world)

Projects a world position into screen space: pixels, origin top-left, +Y pointing down — the same convention as Input.GetMousePosition(), so a value from one can be handed straight to the other.

csharp
Vector2 screen = cam.WorldToScreen(enemy.Translation);
m_HealthBar.Translation = new Vector3(screen.X, screen.Y, 0);

ScreenToWorld(Vector2 screen)

The exact inverse: unprojects a screen position onto the world's Z=0 plane, where every sprite, collider and particle lives unless deliberately placed off it.

csharp
Vector3 world = cam.ScreenToWorld(Input.GetMousePosition());
Particles.Spawn("Effects/Click.jparticle", world);

World is +Y up, screen is +Y down

This pair is the boundary between the two conventions, and the only place a Y sign legitimately flips. Round-tripping a value through both returns what you started with. Both read (0,0) if the camera's viewport size hasn't been set yet — that is, if you call them before the scene's first frame.

CameraFollowComponent

Smooth follow, screen shake, and camera bounds.

You don't have to add this component first

Every setter here adds the component automatically on first write, and every getter returns a sensible default if it isn't there yet. So a script that only ever writes follow settings just works, even though HasComponent<CameraFollowComponent>() would have read false a moment earlier.

FollowTarget

The entity to follow, or null for none. Read and write.

csharp
GetComponent<CameraFollowComponent>()!.FollowTarget = FindEntityByName("Player");

Offset

Where the camera sits relative to its target, as a Vector3. Defaults to about (0, 0, 10). Read and write.

csharp
follow.Offset = new Vector3(0, 2, 10);   // look slightly ahead/above

Damping

How sluggishly the camera catches up, per axis. Defaults to about (0.15, 0.30, 0) — a little looser vertically than horizontally, which is what stops a platformer camera jittering on every small hop. Larger is slower and smoother. Read and write.

csharp
follow.Damping = new Vector3(0.10f, 0.40f, 0);

AddShake(float trauma)

Adds screen shake, 0 to 1. It decays automatically every frame, so you call it once per event rather than managing a timer.

csharp
protected override void OnCollisionEnter(Collision2D collision)
{
    m_Camera?.AddShake(0.4f);
}

Calls compound rather than overwrite — three explosions in quick succession shake harder than one, with the total clamped to 1. That's usually what you want; if it isn't, gate the calls yourself.

SetBounds(Vector2 min, Vector2 max)

Confines the camera to a rectangle in world space, so it stops at the edges of a level instead of showing the void beyond it.

csharp
follow.SetBounds(new Vector2(0, 0), new Vector2(200, 40));

ClearBounds()

Removes the confinement — for a boss arena that opens out, or a cutscene that needs to pan away.

Example: a platformer camera

csharp
using JoystickEngine;

public class LevelCamera : GameEntity
{
    private CameraFollowComponent? m_Follow;

    protected override void OnCreate()
    {
        m_Follow = GetComponent<CameraFollowComponent>();
        m_Follow!.FollowTarget = FindEntityByName("Player");
        m_Follow.Offset  = new Vector3(0, 1.5f, 10);
        m_Follow.Damping = new Vector3(0.12f, 0.35f, 0);
        m_Follow.SetBounds(new Vector2(0, 0), new Vector2(240, 60));
    }

    public void OnExplosion(float strength)
    {
        m_Follow?.AddShake(strength);
    }
}

See also

  • GameEntityFindEntityByName, Translation
  • Input — mouse position, in the same screen space as WorldToScreen
  • Coroutines — for camera moves over time