Sure, let’s look at the default render script to see what’s going on. I’m assuming you’re using the default render script, however the following logic is the same across third-party libraries as well.
--
-- projection that centers content with maintained aspect ratio and optional zoom
--
local function get_fixed_projection(camera, state)
camera.zoom = camera.zoom or DEFAULT_ZOOM
local projected_width = state.window_width / camera.zoom
local projected_height = state.window_height / camera.zoom
local left = -(projected_width - state.width) / 2
local bottom = -(projected_height - state.height) / 2
local right = left + projected_width
local top = bottom + projected_height
return vmath.matrix4_orthographic(left, right, bottom, top, camera.near, camera.far)
end
--
-- projection that centers and fits content with maintained aspect ratio
--
local function get_fixed_fit_projection(camera, state)
camera.zoom = math.min(state.window_width / state.width, state.window_height / state.height)
return get_fixed_projection(camera, state)
end
--
-- projection that stretches content
--
local function get_stretch_projection(camera, state)
return vmath.matrix4_orthographic(0, state.width, 0, state.height, camera.near, camera.far)
end
--
-- projection for gui
--
local function get_gui_projection(camera, state)
return vmath.matrix4_orthographic(0, state.window_width, 0, state.window_height, camera.near, camera.far)
end
The above code snippet contains all of the built-in camera projection matrix calculations. The comments above each of these functions states if the content is centered, which is true for the fixed_fit
and fixed
projections, but not for the stretch
and gui
projections.
So what exactly makes these projections center the content? Take a look at the vmath.matrix4_orthographic()
function, which is called at the end of each of these projection functions.
The left
, right
, bottom
, and top
arguments specify the x_min
left side of your view, the x_max
right side of your view, the y_min
bottom side of your view, and the y_max
top side of your view, which of course creates a rectangle on the screen where graphics are drawn.
Take a look at the get_fixed_projection()
function. It claims to center content. It does this by shifting those left
, right
, bottom
, and top
coordinates leftward by half the width of the window, and downward by half the height of the window:
local left = -(projected_width - state.width) / 2
local bottom = -(projected_height - state.height) / 2
local right = left + projected_width
local top = bottom + projected_height
Therefore, when the camera game object is centered at (0, 0), and the sprite is centered at (0, 0), the sprite will appear centered on the window.
On the other hand, if you’re using a projection that sets left
and bottom
to 0 and right
and top
to the window width and height, then a camera game object at (0, 0) and a sprite at (0, 0) will result in the sprite appearing at the bottom-left of the window.
You can make your own projection functions like the ones in the default render script to change this behavior and make your own custom behaviors.