aboutsummaryrefslogtreecommitdiff
path: root/src/camera.lua
blob: e128c6967f6d3a0140cc57126e785508b5dbcf12 (plain)
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
local DEFAULT_CAMERA_SMOOTHING = 30

local SHAKE_NOISE_SPEED = 15

Cam = {}
Cam.__index = Cam

function Cam.new(x, y)
  local self = setmetatable({}, Cam)

  self.x = x or 0
  self.y = y or 0
  self.realx = self.x
  self.realy = self.y
  self.zoom = 1

  self.smoothing = DEFAULT_CAMERA_SMOOTHING

  self.shake_strength = 0
  self.shake_timer_max = 0
  self.shake_timer = 0
  self.shake_direction = 0

  self.shake_damp = EASING_FUNCTIONS.Lerp
  self.shake_noise = lmath.noise

  return self
end

function Cam:update(dt)
  self.realx = dlerp(self.realx, self.x, self.smoothing * dt)
  self.realy = dlerp(self.realy, self.y, self.smoothing * dt)

  self.shake_timer = self.shake_timer - dt
  if self.shake_timer < 0 then
    self.shake_strength = 0
  end
end

local active_cam = Cam.new()

function get_active_camera()
  return active_cam
end

function Cam:shake(strength, time, angle)
  if strength < self.shake_strength then
    return
  end

  self.shake_direction = angle -- if nil we just ignore it and randomize
  if self.shake_direction then
    self.shake_direction = math.rad(self.shake_direction)
  end
  self.noise_seed = lmath.random() * 1000
  self.shake_strength = strength
  self.shake_timer = time
  self.shake_timer_max = time
end

function set_active_camera(new_cam)
  active_cam = new_cam
end

function Cam:getshake()
  if self.shake_timer < 0 then
    return 0, 0
  end

  local shakex, shakey = 0, 0
  if self.shake_direction then
    local size = self.shake_noise(
      self.shake_timer * SHAKE_NOISE_SPEED + self.noise_seed)

    shakex = math.cos(self.shake_direction) * size
    shakey = math.sin(self.shake_direction) * size

  else
    shakex = self.shake_noise(
      self.shake_timer * SHAKE_NOISE_SPEED + self.noise_seed)

    shakey = self.shake_noise(
      -- 100 is a magic number to offset the x and y noise (so its not just a diagonal shake)
      self.shake_timer * SHAKE_NOISE_SPEED + self.noise_seed, 100)
  end

  local anim = self.shake_timer / self.shake_timer_max
  local strength = self.shake_strength * self.shake_damp(0, 1, anim)

  shakex = shakex * strength
  shakey = shakey * strength
  return shakex, shakey
end

function use_camera_transform()
  local w, h = SCR_WIDTH / 2, SCR_HEIGHT / 2
  lg.scale(active_cam.zoom)
  local ox, oy = -active_cam.realx + w / active_cam.zoom,
                 -active_cam.realy + h / active_cam.zoom
  
  local shakex, shakey = active_cam:getshake()

  lg.translate(
    round(ox + shakex),
    round(oy + shakey))
end