97 lines
2.9 KiB
Lua
97 lines
2.9 KiB
Lua
local Vec3 = require "lib.utils.vec3"
|
|
local utils = require "lib.utils.utils"
|
|
|
|
local EPSILON = 0.001
|
|
|
|
--- @class Camera
|
|
--- @field position Vec3
|
|
--- @field velocity Vec3
|
|
--- @field speed number
|
|
--- @field pixelsPerMeter integer
|
|
--- @field scale number
|
|
local camera = {
|
|
position = Vec3 {},
|
|
velocity = Vec3 {},
|
|
acceleration = 0.2,
|
|
speed = 5,
|
|
pixelsPerMeter = 24,
|
|
}
|
|
|
|
function camera:getDefaultScale()
|
|
return love.window.getDesktopDimensions() /
|
|
(self.pixelsPerMeter * 30) -- 30 meters wide regardless of the actual screen size
|
|
end
|
|
|
|
camera.__index = camera
|
|
camera.scale = camera:getDefaultScale()
|
|
|
|
---------------------------------------------------
|
|
|
|
love.wheelmoved = function(x, y)
|
|
if camera.scale > camera:getDefaultScale() * 5 and y > 0 then return end;
|
|
if camera.scale < camera:getDefaultScale() / 5 and y < 0 then return end;
|
|
camera.scale = camera.scale + (camera.scale * 0.1 * y)
|
|
end
|
|
|
|
local controlMap = {
|
|
cameraMoveUp = Vec3({ 0, -1 }),
|
|
cameraMoveLeft = Vec3({ -1 }),
|
|
cameraMoveDown = Vec3({ 0, 1 }),
|
|
cameraMoveRight = Vec3({ 1 })
|
|
}
|
|
|
|
function camera:update(dt)
|
|
local ps = Tree.panning
|
|
if ps.delta:length() > 0 then
|
|
local worldDelta = ps.delta:scale(1 / (self.pixelsPerMeter * self.scale)):scale(dt):scale(self.speed)
|
|
self.velocity = self.velocity + worldDelta
|
|
elseif utils.any(utils.keys(controlMap), function(el)
|
|
return Tree.controls:isDown(el)
|
|
end) then
|
|
local input = Vec3 {}
|
|
for k, v in pairs(controlMap) do
|
|
if Tree.controls:isDown(k) then input = input + v end
|
|
end
|
|
input = input:normalize() or Vec3 {}
|
|
|
|
self.velocity = self.velocity:add(input:scale(self.acceleration):scale(dt))
|
|
if self.velocity:length() > self.speed then self.velocity = self.velocity:normalize() * self.speed end
|
|
end
|
|
|
|
self.position = self.position + self.velocity
|
|
self.velocity = self.velocity -
|
|
self.velocity * 5 *
|
|
dt -- магическая формула, которая означает "экспоненциально замедлиться до нуля"
|
|
if self.velocity:length() < EPSILON then self.velocity = Vec3 {} end
|
|
end
|
|
|
|
function camera:attach()
|
|
local wc, hc = love.graphics.getWidth() / 2, love.graphics.getHeight() / 2
|
|
love.graphics.push()
|
|
love.graphics.translate(wc, hc)
|
|
love.graphics.scale(self.pixelsPerMeter * self.scale)
|
|
love.graphics.translate(-self.position.x, -self.position.y)
|
|
end
|
|
|
|
--- @param position Vec3
|
|
function camera:toWorldPosition(position)
|
|
local wx, wy = love.window.getMode()
|
|
position = Vec3 {
|
|
(position.x - wx / 2) / self.pixelsPerMeter / self.scale + self.position.x,
|
|
(position.y - wy / 2) / self.pixelsPerMeter / self.scale + self.position.y
|
|
}
|
|
return position
|
|
end
|
|
|
|
function camera:detach()
|
|
love.graphics.pop()
|
|
end
|
|
|
|
--- @return Camera
|
|
local function new()
|
|
return setmetatable({
|
|
}, camera)
|
|
end
|
|
|
|
return { new = new }
|