1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
local Camera = {}
Camera.__index = Camera
function Camera:new(target, width, height, mouseFollow, screenToWorldScale)
local self = setmetatable({}, Camera)
self.target = target
self.width = width
self.height = height
self.mouseFollow = mouseFollow or false
self.mouseRadius = math.min(self.width, self.height) * 0.35
self.mouseWeight = 0.1
self.screenToWorldScale = screenToWorldScale
self.x = target.x + (target.width) / 2 - self.width / 2
self.y = target.y + (target.height) / 2 - self.height / 2
self.vx = 0
self.vy = 0
self.stiffness = 50
self.damping = 2 * math.sqrt(self.stiffness)
self.limits = {
maxX = nil,
minX = nil,
maxY = nil,
minY = nil,
}
return self
end
function Camera:setTarget(target)
self.target = target
end
function Camera:setLimits(minX, maxX, minY, maxY)
self.limits.minX = minX
self.limits.maxX = maxX
self.limits.minY = minY
self.limits.maxY = maxY
end
function Camera:update(dt)
if not self.target then return end
local cx = self.target.x + (self.target.width or 0) / 2
local cy = self.target.y + (self.target.height or 0) / 2
local targetX = cx - self.width / 2
local targetY = cy - self.height / 2
if self.mouseFollow then
local sw = love.graphics.getWidth()
local sh = love.graphics.getHeight()
local mx, my = love.mouse.getPosition()
local offsetX = (mx - sw / 2) * self.screenToWorldScale
local offsetY = (my - sh / 2) * self.screenToWorldScale
local dist = offsetX * offsetX + offsetY * offsetY
if dist > self.mouseRadius * self.mouseRadius then
local inv = self.mouseRadius / math.sqrt(dist)
offsetX = offsetX * inv
offsetY = offsetY * inv
end
targetX = targetX + offsetX * self.mouseWeight
targetY = targetY + offsetY * self.mouseWeight
end
local accelerationX = (targetX - self.x) * self.stiffness - self.vx * self.damping
local accelerationY = (targetY - self.y) * self.stiffness - self.vy * self.damping
self.vx = self.vx + accelerationX * dt
self.vy = self.vy + accelerationY * dt
self.x = self.x + self.vx * dt
self.y = self.y + self.vy * dt
local lim = self.limits
if lim.minX ~= nil then self.x = math.max(lim.minX, self.x) end
if lim.maxX ~= nil then self.x = math.min(self.x, lim.maxX - self.width) end
if lim.minY ~= nil then self.y = math.max(lim.minY, self.y) end
if lim.maxY ~= nil then self.y = math.min(self.y, lim.maxY - self.height) end
end
function Camera:set(padding)
padding = padding or 0
love.graphics.push()
local canvasW = love.graphics.getCanvas():getWidth()
local canvasH = love.graphics.getCanvas():getHeight()
local viewW = self.width + padding * 2
local viewH = self.height + padding * 2
local scaleX = canvasW / viewW
local scaleY = canvasH / viewH
local scale = math.floor(math.min(scaleX, scaleY))
love.graphics.scale(scale)
local snapX = math.floor(self.x)
local snapY = math.floor(self.y)
love.graphics.translate(-(snapX - padding), -(snapY - padding))
end
function Camera:unset()
love.graphics.pop()
end
function Camera:getSubPixelOffset()
local dx = self.x - math.floor(self.x)
local dy = self.y - math.floor(self.y)
return dx, dy
end
return Camera
|