summaryrefslogtreecommitdiff
path: root/main.lua
diff options
context:
space:
mode:
Diffstat (limited to 'main.lua')
-rw-r--r--main.lua122
1 files changed, 122 insertions, 0 deletions
diff --git a/main.lua b/main.lua
new file mode 100644
index 0000000..087ae61
--- /dev/null
+++ b/main.lua
@@ -0,0 +1,122 @@
+local map = love.graphics.newImage("map.png")
+
+-- virtual game world
+local WORLD_WIDTH = 16 * 30
+local WORLD_HEIGHT = 16 * 30
+
+-- camera viewport
+local VIEW_WIDTH = 16 * 15
+local VIEW_HEIGHT = 16 * 15
+
+-- actual window size
+local SCREEN_WIDTH = 16 * 100
+local SCREEN_HEIGHT = 9 * 100
+
+local PLAYER_SIZE = 16
+local PLAYER_COLOR = {0.2, 0.6, 1, 1}
+
+local player = {
+ x = WORLD_WIDTH / 2 - PLAYER_SIZE / 2,
+ y = WORLD_HEIGHT / 2 - PLAYER_SIZE / 2,
+ speed = 80,
+}
+
+local camera = {
+ x = 0,
+ y = 0,
+ follow_speed = 2,
+}
+
+-- calcualte offset of camera position to the nearest integer pixel (grid space)
+function camera:getShaderOffset()
+ local sub_x = camera.x - math.floor(camera.x)
+ local sub_y = camera.y - math.floor(camera.y)
+ return {sub_x / VIEW_WIDTH, sub_y / VIEW_HEIGHT}
+end
+
+local canvas
+
+-- Toggle: when true, shader adds smooth sub-pixel interpolation; when false, integer-only (choppier)
+local smooth_shader_enabled = true
+
+function love.load()
+ canvas = love.graphics.newCanvas(VIEW_WIDTH, VIEW_HEIGHT)
+ canvas:setFilter("nearest", "nearest")
+ map:setFilter("nearest", "nearest")
+ love.window.setMode(SCREEN_WIDTH, SCREEN_HEIGHT)
+ camera.x = player.x + PLAYER_SIZE / 2 - VIEW_WIDTH / 2
+ camera.y = player.y + PLAYER_SIZE / 2 - VIEW_HEIGHT / 2
+
+ smooth_shader = love.graphics.newShader("smoothCamera.glsl")
+end
+
+function love.keypressed(key)
+ if key == "f1" then
+ smooth_shader_enabled = not smooth_shader_enabled
+ end
+end
+
+function love.update(dt)
+ local dx, dy = 0, 0
+ if love.keyboard.isDown("w") then dy = dy - 1 end
+ if love.keyboard.isDown("s") then dy = dy + 1 end
+ if love.keyboard.isDown("a") then dx = dx - 1 end
+ if love.keyboard.isDown("d") then dx = dx + 1 end
+ if dx ~= 0 or dy ~= 0 then
+ local len = math.sqrt(dx * dx + dy * dy)
+ dx, dy = dx / len, dy / len
+ player.x = player.x + dx * player.speed * dt
+ player.y = player.y + dy * player.speed * dt
+ end
+ player.x = math.max(0, math.min(WORLD_WIDTH - PLAYER_SIZE, player.x))
+ player.y = math.max(0, math.min(WORLD_HEIGHT - PLAYER_SIZE, player.y))
+
+ local target_x = player.x + PLAYER_SIZE / 2 - VIEW_WIDTH / 2
+ local target_y = player.y + PLAYER_SIZE / 2 - VIEW_HEIGHT / 2
+
+ -- camera follows the target position
+ camera.x = camera.x + (target_x - camera.x) * camera.follow_speed * dt
+ camera.y = camera.y + (target_y - camera.y) * camera.follow_speed * dt
+ -- clamp camera position to the world bounds
+ camera.x = math.max(0, math.min(WORLD_WIDTH - VIEW_WIDTH, camera.x))
+ camera.y = math.max(0, math.min(WORLD_HEIGHT - VIEW_HEIGHT, camera.y))
+end
+
+function love.draw()
+ love.graphics.setCanvas(canvas)
+ love.graphics.clear()
+ love.graphics.push()
+ local cam_x = math.floor(camera.x)
+ local cam_y = math.floor(camera.y)
+ -- translate the camera to the nearest integer pixel
+ -- this will allow the shader to work properly by calculating the offset from the nearest integer pixel
+ love.graphics.translate(-cam_x, -cam_y)
+ love.graphics.draw(map, 0, 0, 0, 2, 2)
+ love.graphics.setColor(PLAYER_COLOR)
+ love.graphics.rectangle("fill", player.x, player.y, PLAYER_SIZE, PLAYER_SIZE)
+ love.graphics.setColor(1, 1, 1, 1)
+ love.graphics.pop()
+ love.graphics.setCanvas()
+
+ -- calculate the scale of the viewport to the screen
+ local scale = math.floor(math.min(SCREEN_WIDTH / VIEW_WIDTH, SCREEN_HEIGHT / VIEW_HEIGHT))
+ scale = math.max(1, scale)
+ local draw_w = VIEW_WIDTH * scale
+ local draw_h = VIEW_HEIGHT * scale
+ local offset_x = (SCREEN_WIDTH - draw_w) / 2
+ local offset_y = (SCREEN_HEIGHT - draw_h) / 2
+
+ if smooth_shader_enabled then
+ -- calculate the offset of the camera position to the nearest integer pixel
+ local offset = camera:getShaderOffset()
+ -- send the offset to the shader
+ smooth_shader:send("offset", offset)
+ -- set the shader
+ love.graphics.setShader(smooth_shader)
+ end
+ -- print on screen if shader is enabled
+ love.graphics.print("Shader is " .. (smooth_shader_enabled and "enabled" or "disabled"), 10, 10)
+
+ love.graphics.draw(canvas, offset_x, offset_y, 0, scale, scale)
+ love.graphics.setShader()
+end \ No newline at end of file