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 "orthographic.camera"

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

The camera API is inspired by the Phaser camera component.

CODE: https://github.com/britzl/defold-orthographic
DEMO: http://britzl.github.io/publicexamples/orthographic/index.html

TODO:

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

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)
4 Likes

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
	msg.post("/camera#script", "changeZoom")
end

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

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:

msg.post("collectionid:/gameobject#component")

2 Likes

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

My code for testing:

--render_script
if message_id == hash("window_resized") then
	print("window_resized")
	msg.post("level1:/camera#script", "changeZoom")
end

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

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 msg.post() you should see an error in the console? Do you see anything there?

No errors. But if I send message like this (without /)

msg.post("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 (bjorn.ritzl@king.com) 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

2 Likes

Thank you. :man_facepalming:

Hello,

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: britz_camera.zip (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: orthographic.camera:15: 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