My requirements were:
- As easy to use as possible
- Should be small, and don't rely on external libs or class systems
- Only translation; no rotation/scaling
- Should be "clampable" to a map area
- Should use the whole screen; no "windows" needed
- No paralax scrolling needed
Code: Select all
-- camera.lua
-- viewport and boundaries are expressed as left, top, width and height
local viewport = {
l = 0,
t = 0,
w = love.graphics.getWidth(),
h = love.graphics.getHeight()
}
local boundary = {
l = 0,
t = 0,
w = viewport.width,
h = viewport.height
}
local function clampNumber(v, min, max)
if max < min then return 0 end -- this happens when viewport is bigger than boundary
return v < min and min or (v > max and max or v)
end
local function clampCamera()
viewport.l = clampNumber(viewport.l, boundary.l, boundary.l + boundary.w - viewport.w)
viewport.t = clampNumber(viewport.t, boundary.t, boundary.t + boundary.h - viewport.h)
end
local function setViewport(l, t, w, h)
viewport.l, viewport.t, viewport.w, viewport.h = l, t, w or viewport.w, h or viewport.h
clampCamera()
end
local function setBoundary(l, t, w, h)
boundary.l, boundary.t, boundary.w, boundary.h = l, t, w, h
clampCamera()
end
local function lookAt(x,y)
setViewport(math.floor(x - viewport.w / 2), math.floor(y - viewport.h / 2))
end
local function draw(f)
love.graphics.push()
love.graphics.translate(-viewport.l, -viewport.t)
f()
love.graphics.pop()
end
local function getViewport()
return viewport.l, viewport.t, viewport.w, viewport.h
end
return {
setViewport = setViewport,
setBoundary = setBoundary,
getViewport = getViewport,
lookAt = lookAt,
draw = draw
}
Usage:
Code: Select all
local camera = require 'camera'
local worldWidth, worldHeight = 3000, 2000
function love.load()
-- The camera is bound to a rectangle with corners in 0,0 and dimensions 3000x2000
camera.setBoundary(0,0, worldWidth, worldHeight)
end
function love.update(dt)
...
-- center the camera on coordinates 200, 300
camera.lookAt(200, 300)
...
end
function love.draw()
love.graphics.print(100, 100, "This will be drawn without the camera")
camera.draw(function()
love.graphics.print(100, 100, "This will be drawn with the camera")
end)
end
- You use camera.setBoundary to tell the camera how big is your "game world". This limits how you can move it.
- You can orientate the camera with camera.LookAt - this will center the view in a particular coordinate. Usually, this means the player coordinates
- camera.draw takes a function. What you put inside that function is drawn with the camera (this is, scrolled up/down/left/right accordingly to where the camera is looking at). The rest is drawn without it. In the sample above, the second message will be displaced.
Code: Select all
camera.setViewport(0,0, love.graphics.getWidth(), love.graphics.getHeight())
-- you will probably want to "look at what you were looking" after updating the viewport; for example:
camera.lookAt(player.x, player.y)