Defold Orthographic - The Orthographic Camera API

Have you ever been frustrated when converting screen to world coordinates in a game with a camera? Have you ever wished it was simple to get a camera to smoothly follow a game object while also having a defined dead zone?

The Orthographic Camera API is designed to simplify these and other camera related functions. Using it in your 2D game is super simple:

  1. Add the camera.go to your game
  2. Make sure your render script handles the set_view_projection message properly
  3. Interact with the camera either via the camera module or via messages to the camera.go

The API :

local camera = require ""

local world = camera.screen_to_world(camera_id, screen)
camera.shake(camera_id, [intensity], [duration], [direction], [cb])
camera.follow(camera_id, target, [lerp])
camera.deadzone(camera_id, left, top, right, bottom)

The camera API is inspired by the Phaser camera component.



  • Add functionality to do culling of game objects outside camera view
  • Add functionality to specify camera bounds

Nice! Just yesterday I’ve implemented camera shake for my game, nice coincidence.

1 Like

I’ve updated the Orthographic Camera API with a couple of new functions:

-- limit camera position to within a rectangle (bounds of a tilemap for instance)
camera.bounds(camera_id, left, top, right, bottom)

-- translate world coordinates to screen coordinates (useful when culling)
local screen = camera.world_to_screen(camera_id, world)

I have camera with FIXED_ZOOM_2 How can I change zoom_factor depending on width/height of the window?

Something like this:

--my render script
if message_id == hash("window_resized",  { height<320, width<240}) then"/camera#script", "changeZoom")

--my camera script
if message_id == "changeZoom" then
	self.projection = hash(FIXED_ZOOM_1)

The main thing here I don’t understand - how to pass messages to active collection from render script? How should the path look like? Tried some simple examples and it seems that I use wrong paths - my messages do not reach the camera script.

There is no “active collection” concept in Defold. You can have many collections loaded at the same time. Sending a message to a game object in another collection is a matter specifying the full path of the URL including the name of the collection itself. Like this:"collectionid:/gameobject#component")


Of course, I’ve tried this way of message passing but it doesn’t work.

My code for testing:

if message_id == hash("window_resized") then
	print("window_resized")"level1:/camera#script", "changeZoom")

--camera script
if message_id == "changeZoom" then
	self.projection = hash(FIXED_ZOOM_1)

Hierarchy of the project:

“window_resized” is printed, “Message” is not. Also, I’ve edited the name of collection, it’s level1 for sure.

If the URL is wrong when doing the you should see an error in the console? Do you see anything there?

No errors. But if I send message like this (without /)"level1:camera#script", "changeZoom")

There is an error:

ERROR:GAMEOBJECT: Instance 'camera' could not be found when dispatching message 'changeZoom' sent from @render:#

UPD: I’ve also copied scripts from orthographic extension, because one couldn’t save changes of extensions directly. So this is not the case of this problem too.

Well, this is very strange and I honestly can’t explain it. Maybe if you share the project with me ( somehow and I can take a look.

1 Like

So, any progress on this? :slight_smile:

Nope, I’ve been in Jordan all week (small but growing game dev community over there) doing a Defold training and a game jam and I’m writing this from Heathrow… :slight_smile: I’ll take a look now and let you know how it goes.

1 Like

What is the name of the project? I have a very long list of projects and I can’t seem to find yours.

Reactor Defence. :slight_smile: Btw, my level1.collection is loaded with collection proxy from initial main.collection. Maybe this causing some troubles?

Anyway, don’t rush with this. I was just curious of have you received my invite or not, actually. :slight_smile: Don’t want to hurry you up. Thanks!

Note that it’s the id of the collection that must be ”level1”, not filename. Click the root node in the collection outline to see the property.

1 Like

Thank you. But I know that already because I had some problems with that in past.

1 Like

In your camera.script you do a string comparison with the message id:

if message_id == "changeZoom" then

Message ids are always hashed strings:

if message_id == hash("changeZoom") then


Thank you. :man_facepalming:


I’ve tried to use your camera, but i’ve got a strange bug when the render script is launching.

Your sample is working, so it’s a problem with my project, but i don’t understand.

The problem is in the script camera.lua, required by the renderer script.

For narrowing the issue, i’ve made a debug project: (6.9 KB)

git clone defold-orthographic

copy orthographic directory to my new project.

creating game.project.

creating main.collection , input.input_binding.

adding to game project the collection, the input binding and the render found in /orthographic/render/orthographic.render

At this step, i already have the error:

ERROR:SCRIPT: attempt to perform arithmetic on local ‘DISPLAY_WIDTH’ (a nil value)

Same problem with DISPLAY_HEIGHT.

sys.get_config(…) returns nil !

local DISPLAY_WIDTH = tonumber(sys.get_config("display.width"))
local DISPLAY_HEIGHT = tonumber(sys.get_config("display.height"))

(the script is working if i assign numerical values to DISPLAY_WIDTH and DISPLAY_HEIGHT )

I don’t understand, because your sample is working.

Thank you for reading :slight_smile:

Oh, sorry, i’ve understood the problem!

If i leave the default values for display section in the game.project, then the querying of display.width and display.height will return nil.

If i change the default values (960x640) to something different (1024x768), then the sys.get_config will return the correct values.

So that’s only annoying if you want your game running in 960x640 resolution :slight_smile:

Thank you for reading :slight_smile:

1 Like

You can probably type 960x640 manually in game.project and get that to work.

1 Like