Question
How do you implement a camera with pan/zoom/rotation for a 2d game? Is it acceptable to multiply together a series of transformation matrixes to generate a final transformation matrix that is applied to the vectors/vertices in a scene, or is there a more efficient way?
Overview
Working on a 2d game in löve2d I recently tried implementing a camera class that allows for panning/rotation/scrolling.
I tried finding a good resource for how to implement such a 2d camera, but was unable to find one that covered all three degrees of movement, and so I came up with my own solution.
I would like some feedback on if this is a good approach, and how it could be optimized/improved upon.
My Attempt
My camera object stores the following values:
- position: (
Vector2
)(World-Space position relative to the origin) - angle: (
float
)(how much the world is rotated, in radians) - zoom: (
float
)(the zoom factor, 1 = normal, 0.5 = 2x zoom, etc) - offset_center: (
Vector2
)(center the camera on the point of rotation using[screen_width/2,screen_height/2]
) - offset: (
Vector2
)(any additional offset away from the center of rotation, typically just[0,0]
Whenever a camera value changes (basically each frame) I run camera:computeMatrix()
which calculates its transformation matrix:
Camera.computeMatrix = function (self)
local m_pos = Matrix{ -- World-space Position
{1, 0, self.position.x},
{0, 1, self.position.y},
{0, 0, 1}
}
local m_zoom = Matrix{ -- Zoom
{self.zoom, 0, 0},
{0, self.zoom, 0, 0},
{0, 0, 1}
}
local m_rot = Matrix{ -- Rotation
{math.cos(self.angle), math.sin(self.angle), 0},
{-math.sin(self.angle), math.cos(self.angle), 0},
{0, 0, 1}
}
local m_offset = Matrix{ -- Screen-space Offset
{1, 0, self.offset_center.x + self.offset.x},
{0, 1, self.offset_center.y + self.offset.y},
{0, 0, 1}
}
self.matrix = nil
-- reverse order than when applying them 1 by 1
self.matrix = m_offset * m_rot * m_zoom * m_pos
end
So once Camera.matrix
is calculated as a 3x3 matrix, I apply that to a given vertex/vector:
Vector2.TransformM = function (v, m)
-- m is a 3x3 matrix of format {{a,b,c},{d,e,f},{g,h,i}}
return Vector2(v.x*m[1][1]+v.y*m[1][2]+m[1][2], v.x*m[2][2]+v.y*m[2][2]+m[2][3])
end
An example of this implementation:
Download (pan with WASD, rotate with Q/E, zoom with 1/2)