Godot Template: Understanding the Camera

Overview

The Camera scene follows the player, resets rooms that have been exited and initiates saves. It isn’t necessary to full understand it, but you should at least have an idea of what it impacts.

Scene Tree

  • Camera is type Camera2D
    • Tween is type Tween

Exports

  • SCREEN_SIZE
    • Defaults to Vector2.ZERO and if it is not set, it gets set based on ProjectSettings at runtime.

  • SCROLL_SPEED
    • Used by Tween

  • target
    • The path to the scene that the camera follows (expected to be the player)

Signals

  • screen_change:
    • This is emitted by _process while the tween is active

  • screen_change_started
    • This is connected to tween_started

    • This triggers:
      • Entities to paused (entity.gd)

      • Enemies reset (entity.gd)

      • Pickups with the “disappear” flag and not on screen to be deleted (pickup.gd)

  • screen_change_completed
    • This is connected to tween_completed

    • This triggers:
      • Entities to be unpaused if they’re in the camera rect (entity.gd)

      • The game to be saved (Main.gd)

Code

camera.gd

extends Camera2D

export(Vector2) var SCREEN_SIZE = Vector2.ZERO
export(float, 0, 5, .1) var SCROLL_SPEED    = 0.5
export(NodePath) var target

var target_grid_pos := Vector2(0,0)
var last_target_grid_pos := Vector2(0,0)
var camera_rect := Rect2()

signal screen_change
signal screen_change_started
signal screen_change_completed

func _ready():
    # target is set in the scene the camera lives in and is generally the player
    # setting it in the scene means not hard coding it
    target = get_node(target)

    if SCREEN_SIZE == Vector2.ZERO:
        SCREEN_SIZE = Vector2(ProjectSettings.get_setting("display/window/size/width"),ProjectSettings.get_setting("display/window/size/height"))

    # Find out which grid the target is in and
    # move the camera to the top left corner
    target_grid_pos = get_grid_pos(target.position)
    position = target_grid_pos * SCREEN_SIZE
    last_target_grid_pos = target_grid_pos

    # connect some actions - a tween is a flexible animator and handles
    # our smooth screen transitions
    $Tween.connect("tween_started", self, "screen_change_started")
    $Tween.connect("tween_completed", self, "screen_change_completed")


func _process(delta):
    camera_rect = Rect2(position, SCREEN_SIZE)

    # Signals are a way to communitcate with other scripts in the game
    if $Tween.is_active():
        emit_signal("screen_change")

    # if the player is no longer in the camera rectangle
    if !$Tween.is_active() && !camera_rect.has_point(target.position):
        scroll_camera()

func scroll_camera():
    target_grid_pos = get_grid_pos(target.position)
    $Tween.interpolate_property(self, "position", last_target_grid_pos * SCREEN_SIZE, target_grid_pos * SCREEN_SIZE, SCROLL_SPEED, Tween.TRANS_LINEAR, Tween.EASE_IN_OUT)
    $Tween.start()
    last_target_grid_pos = target_grid_pos

# find the position placement on an (x,y) grid
func get_grid_pos(pos):
    var x = floor(pos.x / SCREEN_SIZE.x)
    var y = floor(pos.y / SCREEN_SIZE.y)
    return Vector2(x,y)

# Signals are a way to communitcate with other scripts in the game
func screen_change_started(object, nodepath):
    emit_signal("screen_change_started")

func screen_change_completed(object, nodepath):
    emit_signal("screen_change_completed")

func area_exited(area):
    var body = area.get_parent()
    if body.get_groups().has("projectile"):
        body.queue_free()
    if area.get_groups().has("disappears"):
        area.queue_free()