local obj = require "obj"
local text = require "text"
obj.load_types()
line = love.graphics.line
function box(x, y, w, h) line(x, y, x + w, y, x + w, y + h, x, y + h, x, y) end
set_color = love.graphics.setColor
local line_width = 0.4
local cam = {
x = 0, y = 0,
scale = 1.1,
panning = false,
}
local drag_start
local dragging
local selecting
local selection
for i = 1, 100 do
obj.new("test", {math.random() * 1000 - 500, math.random() * 1000 - 500}, {
avel = math.random() * 0.5 - 0.25,
vel = {math.random() * 1 - 0.5, math.random() * 1 - 0.5}
})
end
obj.new("test", {0, 0})
obj.new("x", {0, 60}, {avel = 100})
local function window_scale()
local w, h = love.graphics.getDimensions()
return 256 / math.min(w, h)
end
local function view_scale()
return window_scale() / cam.scale
end
local function view_dimensions()
local w, h = love.graphics.getDimensions()
local scale = view_scale()
return w * scale, h * scale
end
local function window_transform()
local scale = window_scale()
local trans = love.math.newTransform(0, 0, 0, 1/scale, 1/scale)
return trans
end
local function view_transform()
local w, h = view_dimensions()
local trans = window_transform()
trans:scale(cam.scale, cam.scale)
trans:translate(-cam.x + w/2, -cam.y + h/2)
return trans
end
local function draw_world()
local w, h = view_dimensions()
local cx1, cy1 = cam.x - w/2, cam.y - h/2
local cx2, cy2 = cam.x + w/2, cam.y + h/2
love.graphics.push()
love.graphics.applyTransform(view_transform())
-- the line thickness will scale according to the zoom amount. counteract this.
love.graphics.setLineWidth(line_width / cam.scale)
-- draw a grid
set_color(0.1, 0.1, 0.1)
for x = cx1 - cx1%64, cx2, 64 do
for y = cy1 - cy1%64, cy2, 64 do
line(x, y, x + 64, y)
line(x, y, x, y + 64)
end
end
-- draw all possibly visible objects
for o in obj.in_box(
cx1 - obj.max_size, cy1 - obj.max_size,
cx2 + obj.max_size, cy2 + obj.max_size) do
set_color(1, 1, 1)
o:draw()
end
set_color(1, 1, 0.5)
if selection then
for o in pairs(selection) do
local x, y = unpack(o.data.pos)
box(x - o.hitbox, y - o.hitbox, o.hitbox*2, o.hitbox*2)
end
end
if selecting then
local x1, y1 = unpack(selecting.p1)
local x2, y2 = unpack(selecting.p2)
local w, h = x2 - x1, y2 - y1
box(x1, y1, w, h)
end
love.graphics.pop()
end
local function draw_hud()
love.graphics.push()
love.graphics.applyTransform(window_transform())
love.graphics.setLineWidth(line_width)
-- things
set_color(1, 1, 1)
local total_energy = obj.total_energy()
text.draw(("e: %f"):format(total_energy), 10, 10, {scale = 0.4})
love.graphics.pop()
end
function love.draw()
love.graphics.clear(0, 0, 0)
draw_world()
draw_hud()
end
function love.update()
if not (selection or selecting) then
for o in obj.all() do
o:tick()
end
end
end
function love.mousepressed(x, y, button)
local x, y = view_transform():inverseTransformPoint(x, y)
if button == 1 then
drag_start = {x, y}
elseif button == 2 then
cam.panning = true
end
end
function love.mousereleased(x, y, button)
local x, y = view_transform():inverseTransformPoint(x, y)
if button == 1 then
if not dragging then
local clicked = obj.at(x, y)()
if not love.keyboard.isDown "lshift" then
if clicked and not (selection and selection[clicked]) then
selection = {[clicked] = true}
else
selection = nil
end
elseif clicked then
selection = selection or {}
selection[clicked] = true
end
end
dragging = false
drag_start = nil
selecting = nil
elseif button == 2 then
cam.panning = false
end
end
function love.mousemoved(x, y, dx, dy)
local x, y = view_transform():inverseTransformPoint(x, y)
local scale = view_scale()
dx, dy = dx * scale, dy * scale
if drag_start then
if not dragging then
local clicked = obj.at(x, y)()
selecting = not clicked and not love.keyboard.isDown "lshift"
end
if selecting then
local sx, sy = unpack(drag_start)
selecting = {
p1 = {math.min(x, sx), math.min(y, sy)},
p2 = {math.max(x, sx), math.max(y, sy)},
}
selection = {}
for o in obj.in_box(
selecting.p1[1], selecting.p1[2],
selecting.p2[1], selecting.p2[2]) do
selection[o] = true
end
if not next(selection) then selection = nil end
elseif selection then
for o in pairs(selection) do
o:set_pos(o.data.pos[1] + dx, o.data.pos[2] + dy)
end
end
dragging = true
elseif cam.panning then
cam.x = cam.x - dx
cam.y = cam.y - dy
end
end
function love.wheelmoved(_, y)
cam.scale = math.min(math.max(cam.scale + (y * 0.1), 0.25), 4)
end