diff --git a/.gitmodules b/.gitmodules index 5f93f23..55ab3e9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "lib/baton"] path = lib/baton url = https://github.com/tesselode/baton +[submodule "lib/cameramod"] + path = lib/cameramod + url = https://github.com/a327ex/ModifiedCamera diff --git a/def/Camera.d.lua b/def/Camera.d.lua index 292a7fc..08936c4 100644 --- a/def/Camera.d.lua +++ b/def/Camera.d.lua @@ -1,15 +1,15 @@ ---@meta ---@class Camera ----@field x number The x position of the camera in world coordinates ----@field y number The y position of the camera in world coordinates ----@field scale number The zoom level (scale) of the camera ----@field rot number The rotation of the camera in radians +---@field x number The x position of the Camera in world coordinates +---@field y number The y position of the Camera in world coordinates +---@field scale number The zoom level (scale) of the Camera +---@field rot number The rotation of the Camera in radians ---@field smoother fun(dx: number, dy: number, ...: any): number, number The smoothing function used for lock/window methods -local Camera = {} +Camera = {} ----@class camera.smooth -local smooth = {} +---@class Camera.smooth +smooth = {} --- No smoothing - instant movement. ---@return fun(dx: number, dy: number): number, number @@ -25,29 +25,29 @@ function smooth.linear(speed) end ---@return fun(dx: number, dy: number, s: number|nil): number, number function smooth.damped(stiffness) end ---- Sets the position the camera is looking at. +--- Sets the position the Camera is looking at. ---@param x number ---@param y number ---@return Camera function Camera:lookAt(x, y) end ---- Moves the camera by the given amount. +--- Moves the Camera by the given amount. ---@param dx number ---@param dy number ---@return Camera function Camera:move(dx, dy) end ---- Returns the current position of the camera. +--- Returns the current position of the Camera. ---@return number x ---@return number y function Camera:position() end ---- Rotates the camera by the given angle (radians). +--- Rotates the Camera by the given angle (radians). ---@param phi number ---@return Camera function Camera:rotate(phi) end ---- Sets the absolute rotation of the camera (radians). +--- Sets the absolute rotation of the Camera (radians). ---@param phi number ---@return Camera function Camera:rotateTo(phi) end @@ -62,7 +62,7 @@ function Camera:zoom(mul) end ---@return Camera function Camera:zoomTo(zoom) end ---- Begins drawing with this camera applied. +--- Begins drawing with this Camera applied. ---@param x number|nil Scissor x (default: 0) ---@param y number|nil Scissor y (default: 0) ---@param w number|nil Scissor width (default: screen width) @@ -70,16 +70,16 @@ function Camera:zoomTo(zoom) end ---@param noclip boolean|nil If true, scissor is not applied function Camera:attach(x, y, w, h, noclip) end ---- Ends drawing with this camera and restores previous transform/scissor. +--- Ends drawing with this Camera and restores previous transform/scissor. function Camera:detach() end ---- Draws a function within the camera's transform. +--- Draws a function within the Camera's transform. ---@overload fun(func: fun()) ---@overload fun(x: number, y: number, w: number, h: number, func: fun()) ---@overload fun(x: number, y: number, w: number, h: number, noclip: boolean, func: fun()) function Camera:draw(x, y, w, h, noclip, func) end ---- Converts world coordinates to screen/camera coordinates. +--- Converts world coordinates to screen/Camera coordinates. ---@param x number World x ---@param y number World y ---@param ox number|nil Offset x (default: 0) @@ -88,7 +88,7 @@ function Camera:draw(x, y, w, h, noclip, func) end ---@param h number|nil Screen height (default: love.graphics.getHeight()) ---@return number screenX ---@return number screenY -function Camera:cameraCoords(x, y, ox, oy, w, h) end +function Camera:CameraCoords(x, y, ox, oy, w, h) end --- Converts screen coordinates to world coordinates. ---@param x number Screen x @@ -110,21 +110,21 @@ function Camera:worldCoords(x, y, ox, oy, w, h) end ---@return number worldY function Camera:mousePosition(ox, oy, w, h) end ---- Smoothly moves the camera to center on x (horizontal only). +--- Smoothly moves the Camera to center on x (horizontal only). ---@param x number Target world x ---@param smoother fun(dx: number, dy: number, ...: any): number, number | nil ---@param ... any Extra args passed to smoother ---@return Camera function Camera:lockX(x, smoother, ...) end ---- Smoothly moves the camera to center on y (vertical only). +--- Smoothly moves the Camera to center on y (vertical only). ---@param y number Target world y ---@param smoother fun(dx: number, dy: number, ...: any): number, number | nil ---@param ... any Extra args passed to smoother ---@return Camera function Camera:lockY(y, smoother, ...) end ---- Smoothly moves the camera to center on (x,y). +--- Smoothly moves the Camera to center on (x,y). ---@param x number Target world x ---@param y number Target world y ---@param smoother fun(dx: number, dy: number, ...: any): number, number | nil @@ -142,11 +142,3 @@ function Camera:lockPosition(x, y, smoother, ...) end ---@param smoother fun(dx: number, dy: number, ...: any): number, number | nil ---@param ... any Extra args passed to smoother function Camera:lockWindow(x, y, x_min, x_max, y_min, y_max, smoother, ...) end - ----@class camera ----@field smooth camera.smooth ----@field new fun(x: number|nil, y: number|nil, zoom: number|nil, rot: number|nil, smoother: fun(dx: number, dy: number, ...: any): number, number | nil): Camera -local camera = {} - ----@overload fun(x: number|nil, y: number|nil, zoom: number|nil, rot: number|nil, smoother: fun(dx: number, dy: number, ...: any): number, number | nil): Camera -return camera diff --git a/def/Shake.d.lua b/def/Shake.d.lua new file mode 100644 index 0000000..69801e7 --- /dev/null +++ b/def/Shake.d.lua @@ -0,0 +1,37 @@ +---@meta + +---@class Shake : Object +---@field amplitude number The maximum shake strength in pixels +---@field frequency number How many shake samples per second +---@field duration number Duration of the shake in milliseconds +---@field samples number[] Pre-generated noise samples for smooth interpolation +---@field start_time number Timestamp (ms) when shake started +---@field t number Current elapsed time in milliseconds +---@field shaking boolean Whether the shake is still active +Shake = {} + +---Creates a new camera shake effect. +---@param amplitude number Maximum shake offset in pixels +---@param frequency number Samples per second (higher = more erratic) +---@param duration number Duration in milliseconds +function Shake:new(amplitude, frequency, duration) end + +---Updates the shake timer. Call every frame. +---@param dt number Delta time in seconds (from love.update) +function Shake:update(dt) end + +---Gets the current shake amplitude at time `t`. +---If `t` is not provided, uses current elapsed time. +---@param t? number Optional time in milliseconds +---@return number amplitude Current shake strength (0 when finished) +function Shake:getAmplitude(t) end + +---Internal: Gets noise value at sample index. +---@param s number Sample index (float allowed for interpolation) +---@return number noise Value between -1 and 1 +function Shake:noise(s) end + +---Internal: Linear decay envelope (1 → 0 over duration). +---@param t number Time in milliseconds +---@return number decay_factor From 1.0 down to 0.0 +function Shake:decay(t) end diff --git a/lib/cameramod b/lib/cameramod new file mode 160000 index 0000000..2aace9e --- /dev/null +++ b/lib/cameramod @@ -0,0 +1 @@ +Subproject commit 2aace9ee2560ab4389fe950bcf0b6b6eb779b102 diff --git a/main.lua b/main.lua index 0d248a2..0abd2bf 100644 --- a/main.lua +++ b/main.lua @@ -11,8 +11,9 @@ Object = require 'lib/classic/classic' Baton = require 'lib/baton/baton' ---@type Timer Timer = require 'lib/hump/timer' ----@type Camera -Camera = require 'lib/hump/camera' + +Camera = require 'lib/cameramod/camera' +require 'lib/cameramod/Shake' -- generic objects -- Room = require 'obj/Room' @@ -52,12 +53,16 @@ function love.load() move = {'left', 'right', 'up', 'down'} } } + camera = Camera() end function love.update(dt) - input:update(dt) if current_room then current_room:update(dt) end + input:update(dt) if input:pressed('f1') then gotoRoom('Stage') end + if input:pressed('f3') then camera:shake(4, 60, 1) end + + camera:update(dt) end function love.draw() @@ -128,3 +133,12 @@ function resize(s) love.window.setMode(s*gw, s*gh) sx, sy = s, s end + +---Returns random number +---@param min number minimum of range +---@param max number maximum of range +---@return number +function random(min, max) + local min, max = min or 0, max or 1 + return (min > max and (love.math.random()*(min - max) + max)) or (love.math.random()*(max - min) + min) +end diff --git a/obj/GameObject.lua b/obj/GameObject.lua index dc5622c..4cadefb 100644 --- a/obj/GameObject.lua +++ b/obj/GameObject.lua @@ -30,6 +30,7 @@ end function GameObject:draw() end ---Mark object for destruction +---@protected function GameObject:destroy() if self.timer then self.timer:clear() -- cancel all tweens/after/every diff --git a/obj/Room.lua b/obj/Room.lua index 427ec5c..f945190 100644 --- a/obj/Room.lua +++ b/obj/Room.lua @@ -17,6 +17,11 @@ end ---Updates room (see [love.update()](lua://love.update)) ---@param dt number delta time function Room:update(dt) +---@diagnostic disable-next-line: undefined-field + camera.smoother = Camera.smooth.damped(5) +---@diagnostic disable-next-line: param-type-mismatch + camera:lockPosition(dt, gw/2, gh/2) + self.area:update(dt) end @@ -25,7 +30,9 @@ end function Room:draw() love.graphics.setCanvas(self.main_canvas) love.graphics.clear() + camera:attach(0, 0, gw, gh) self:canvasDraw() + camera:detach() love.graphics.setCanvas() love.graphics.setColor(255, 255, 255, 255)