Compare commits
20 Commits
feed65cf6d
...
Chunk
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
577b7576cf | ||
|
|
fa4b2c86b5 | ||
|
|
e8cef497d4 | ||
|
|
b3a12305da | ||
|
|
236e23177d | ||
|
|
4d94cc805d | ||
|
|
9c4b5431ee | ||
|
|
ba1c0f0c89 | ||
|
|
ef632d50ee | ||
|
|
5bcf25a461 | ||
|
|
1039479c47 | ||
|
|
62555b4526 | ||
|
|
a4af57ca6c | ||
|
|
5189bef537 | ||
|
|
eab4cbbcdc | ||
|
|
829963e080 | ||
|
|
82246dc0c6 | ||
|
|
3a5e0b395b | ||
|
|
f091fba9f7 | ||
|
|
27f1dc71c0 |
@@ -77,3 +77,16 @@ function Camera:positionAt(x,y)
|
||||
self.pos.y = math.floor((y/self.height)*self.height)
|
||||
end
|
||||
|
||||
-- translate screen coordinates to game coordinates
|
||||
function Camera:ptScreenToGame(pt)
|
||||
return self.pos + pt
|
||||
end
|
||||
|
||||
function Camera:mouseScreenPos()
|
||||
return Point:new(love.mouse.getX(),love.mouse.getY()) / game.scale
|
||||
end
|
||||
|
||||
-- return the mouse position as game coordinates
|
||||
function Camera:mouseGamePos()
|
||||
return self:ptScreenToGame(self:mouseScreenPos())
|
||||
end
|
||||
|
||||
51
code/chunk.lua
Normal file
51
code/chunk.lua
Normal file
@@ -0,0 +1,51 @@
|
||||
-- pieces of levels
|
||||
|
||||
Chunk = {all = {}}
|
||||
Chunk.__index = Chunk
|
||||
|
||||
-- CLASS METHODS
|
||||
|
||||
-- box == nil for global chunks
|
||||
function Chunk:new(filename, box)
|
||||
local o = { filename = filename, box = box }
|
||||
setmetatable(o, self)
|
||||
self.all[o] = true
|
||||
end
|
||||
|
||||
function Chunk:getExportList()
|
||||
local r = {}
|
||||
for chunk in pairs(self.all) do
|
||||
table.insert(r, {chunk.filename, chunk.box})
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
-- INSTANCE METHODS
|
||||
|
||||
function Chunk:containsPoint(pt)
|
||||
return self.box == nil or self.box:containsPoint(pt)
|
||||
end
|
||||
|
||||
function Chunk:load()
|
||||
if self.loaded then
|
||||
return
|
||||
end
|
||||
logPrint("loading chunk "..self.filename)
|
||||
self.data = dofile(level_current.."/chunks/"..self.filename)
|
||||
self.loaded = { rooms = {}, collisions = {} }
|
||||
LevelTiles = self.data.tiles
|
||||
indexLevelTiles()
|
||||
optimizeTileObjects(self.loaded.collisions)
|
||||
|
||||
for _, v in ipairs(self.data.rooms or {}) do
|
||||
local room = Collision:new(v[1],v[2],v[3],v[4])
|
||||
table.insert(self.data.rooms, room)
|
||||
table.insert(LoadedObjects.Rooms, room)
|
||||
end
|
||||
logPrint("loaded chunk with "..#self.loaded.collisions.." collisions")
|
||||
end
|
||||
|
||||
function Chunk:save(chunkdir)
|
||||
return love.filesystem.write(chunkdir.."/"..self.filename, "return "..serialize_lua_value(self.data))
|
||||
end
|
||||
|
||||
@@ -88,3 +88,7 @@ function Collision:draw(color)
|
||||
love.graphics.setColor(0,1,90,0.5)
|
||||
love.graphics.rectangle("line",self.from.x-Camera.pos.x, self.from.y-Camera.pos.y, self.width, self.height)
|
||||
end
|
||||
|
||||
function Collision:asRect()
|
||||
return Rect:fromCoords(self.from.x, self.from.y, self.to.x, self.to.y)
|
||||
end
|
||||
|
||||
@@ -1,17 +1,37 @@
|
||||
assert(editor == nil)
|
||||
editor = {
|
||||
active = false,
|
||||
room_mode = false,
|
||||
--palette_mode = false,
|
||||
palette = {
|
||||
active = false,
|
||||
scroll = Point:new(0, 0),
|
||||
},
|
||||
multiselect = {
|
||||
active = false,
|
||||
sweeping = false,
|
||||
box = nil,
|
||||
},
|
||||
pan = { fixed = false, speed = 3 },
|
||||
}
|
||||
|
||||
function stepEditor()
|
||||
|
||||
|
||||
animateTiles()
|
||||
|
||||
local osweep = editor.multiselect.sweeping
|
||||
editor.multiselect.sweeping = Keybind:checkDown(Keybind.editor.entity_select)
|
||||
frameDebug("sweeping: "..tostring(editor.multiselect.sweeping))
|
||||
if editor.multiselect.sweeping and not editor.multiselect.active then
|
||||
print("multiselect enabled")
|
||||
editor.multiselect.active = true
|
||||
end
|
||||
if not osweep and osweep ~= editor.multiselect.sweeping then
|
||||
editor.multiselect.box = nil
|
||||
end
|
||||
if editor.multiselect.active then
|
||||
doEditorMultiselect()
|
||||
end
|
||||
|
||||
if Keybind:checkPressed(Keybind.editor.room_mode) then
|
||||
if love.keyboard.isDown("lshift") then
|
||||
editor.room_mode = "delete"
|
||||
@@ -80,7 +100,7 @@ function stepEditor()
|
||||
if name_prompt.canceled then return end
|
||||
Prompt:new({
|
||||
name = "filename",
|
||||
input = "level.lua",
|
||||
input = "unnamed_level",
|
||||
func = function(file_prompt)
|
||||
if file_prompt.canceled then return end
|
||||
exportLevel(name_prompt.input, file_prompt.input)
|
||||
@@ -89,13 +109,6 @@ function stepEditor()
|
||||
end,
|
||||
}):activate()
|
||||
end
|
||||
|
||||
if Keybind:checkPressed(Keybind.debug.editor) then
|
||||
editor_mode = not editor_mode
|
||||
deselectSpawns()
|
||||
createTileObjects()
|
||||
restartGame()
|
||||
end
|
||||
end
|
||||
|
||||
function scrollEditor(y)
|
||||
@@ -128,6 +141,10 @@ function drawEditor()
|
||||
if editor.palette.active then
|
||||
doEditorPalette()
|
||||
end
|
||||
if editor.multiselect.box ~= nil then
|
||||
frameDebug("drawing multiselect "..tostring(editor.multiselect.box))
|
||||
drawEditorMultiselect()
|
||||
end
|
||||
end
|
||||
|
||||
function doEditorEdit()
|
||||
@@ -204,7 +221,9 @@ function doEditorEdit()
|
||||
else
|
||||
if Keybind:checkDown(Keybind.editor.entity_select) then
|
||||
deselectSpawns()
|
||||
selectSpawns(mouse_x,mouse_y)
|
||||
if editor.multiselect.box then
|
||||
selectSpawns(editor.multiselect.box)
|
||||
end
|
||||
end
|
||||
if Keybind:checkDown(Keybind.editor.entity_move) then
|
||||
moveSpawns(mouse_x,mouse_y)
|
||||
@@ -353,7 +372,21 @@ end
|
||||
|
||||
function drawEditorRooms()
|
||||
for _, room in pairs(LoadedObjects.Rooms) do
|
||||
love.graphics.setColor(0,0,100,1)
|
||||
love.graphics.rectangle("line",room.from.x-Camera.pos.x, room.from.y-Camera.pos.y, room.width, room.height)
|
||||
love.graphics.setColor(0,0,1,1)
|
||||
room:asRect():draw("line")
|
||||
end
|
||||
end
|
||||
|
||||
function drawEditorMultiselect()
|
||||
love.graphics.setColor(0,1,1,1)
|
||||
editor.multiselect.box:draw("line")
|
||||
end
|
||||
|
||||
function doEditorMultiselect()
|
||||
local mousept = Camera:mouseGamePos()
|
||||
if editor.multiselect.box == nil then
|
||||
editor.multiselect.box = Rect:fromPoints(mousept, mousept)
|
||||
elseif editor.multiselect.sweeping then
|
||||
editor.multiselect.box.max = mousept
|
||||
end
|
||||
end
|
||||
|
||||
@@ -36,20 +36,30 @@ function Arrow:drawBackground()
|
||||
end
|
||||
|
||||
function Arrow:doPhysics()
|
||||
if not self:isCollidingAt(self.pos.x + self.vel.x, self.pos.y, LoadedObjects.Collisions) then
|
||||
self.pos.x = self.pos.x + self.vel.x
|
||||
else
|
||||
self.stuck = true
|
||||
end
|
||||
if not self:isCollidingAt(self.pos.x, self.pos.y + self.vel.y, LoadedObjects.Collisions) then
|
||||
self.pos.y = self.pos.y + self.vel.y
|
||||
else
|
||||
self.stuck = true
|
||||
-- horizontal collision
|
||||
self:moveX(
|
||||
self.vel.x,
|
||||
function()
|
||||
self.stuck = true
|
||||
end
|
||||
)
|
||||
|
||||
if not self.stuck then
|
||||
-- vertical collision
|
||||
self:moveY(
|
||||
self.vel.y,
|
||||
function()
|
||||
self.stuck = true
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
if self.stuck then
|
||||
self.pos.x = self.pos.x + self.vel.x * (2/3)
|
||||
self.pos.y = self.pos.y + self.vel.y * (2/3)
|
||||
self.vel.x = 0
|
||||
self.vel.y = 0
|
||||
end
|
||||
|
||||
self:adjustLight()
|
||||
end
|
||||
|
||||
@@ -67,6 +67,13 @@ function CursedBook:doLogic()
|
||||
elseif self.status == 4 then
|
||||
|
||||
end
|
||||
|
||||
if self.isFlying then
|
||||
local random_x = math.random(-4, 4)/100
|
||||
local random_y = math.random(-4, 4)/100
|
||||
self.vel.x = self.vel.x + random_x
|
||||
self.vel.y = self.vel.y + random_y
|
||||
end
|
||||
end
|
||||
|
||||
function CursedBook:handleAnimation()
|
||||
@@ -101,15 +108,21 @@ function CursedBook:handleAnimation()
|
||||
end
|
||||
|
||||
function CursedBook:doPhysics()
|
||||
if self.isFlying then
|
||||
local random_x = math.random(-4, 4)/100
|
||||
local random_y = math.random(-4, 4)/100
|
||||
self.vel.x = self.vel.x + random_x
|
||||
self.vel.y = self.vel.y + random_y
|
||||
end
|
||||
-- move
|
||||
|
||||
self:moveWithCollision()
|
||||
-- horizontal collision
|
||||
self:moveX(
|
||||
self.vel.x,
|
||||
function()
|
||||
self.vel.x = 0
|
||||
end
|
||||
)
|
||||
-- vertical collision
|
||||
self:moveY(
|
||||
self.vel.y,
|
||||
function()
|
||||
self.vel.y = 0
|
||||
end
|
||||
)
|
||||
-- final position
|
||||
self:adjustLight()
|
||||
end
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ function Fairy:new(x,y)
|
||||
end
|
||||
|
||||
function Fairy:doLogic()
|
||||
|
||||
if self:checkVisionLine(main_player,self.vision_range) then
|
||||
|
||||
self.target.x = main_player.pos.x + main_player.target_offset.x
|
||||
@@ -63,31 +62,19 @@ function Fairy:doLogic()
|
||||
|
||||
local distance_x = self.target.x - self.pos.x
|
||||
local distance_y = self.target.y - self.pos.y
|
||||
local angle = getAngleFromVector(distance_x,distance_y)
|
||||
local angle = getAngleFromVector(vector(distance_x,distance_y))
|
||||
local distance = math.sqrt(distance_x ^ 2 + distance_y ^ 2)
|
||||
|
||||
if distance < self.range then
|
||||
self.vel.x = self.vel.x * 0.9
|
||||
self.vel.y = self.vel.y * 0.9
|
||||
local random_x = math.random(-1, 1)
|
||||
local random_y = math.random(-1, 1)
|
||||
self.vel.x = self.vel.x * 0.9 + random_x/10
|
||||
self.vel.y = self.vel.y * 0.9 + random_y/10
|
||||
else
|
||||
self.vel.x = math.cos(angle)*self.speed
|
||||
self.vel.y = math.sin(angle)*self.speed
|
||||
end
|
||||
self.particle_timer = self.particle_timer + 1
|
||||
if self.particle_timer >= self.particle_time then
|
||||
self.particle_timer = 0
|
||||
|
||||
local particle_data = {
|
||||
animation = animation.particle.simple,
|
||||
animation_speed = 1,
|
||||
sprite_tint = hex2rgb("#fed100"),
|
||||
sprite_alpha_fade = true,
|
||||
direction = angle-math.rad(180+math.random(60)-30),
|
||||
speed = 0.8*(distance/50),
|
||||
speed_increase = -0.01,
|
||||
time = 0.75
|
||||
}
|
||||
Particle:new(self.pos.x,self.pos.y,particle_data)
|
||||
local random_x = math.random(-6, 6)
|
||||
local random_y = math.random(-6, 6)
|
||||
self.vel.x = math.cos(angle)*self.speed + random_x/10
|
||||
self.vel.y = math.sin(angle)*self.speed + random_y/10
|
||||
end
|
||||
end
|
||||
|
||||
@@ -95,19 +82,42 @@ function Fairy:handleAnimation()
|
||||
self.body:animate()
|
||||
--if self:isCollidingWith(main_player) then self.sprite_tint = {1,0,0} else self.sprite_tint = {1,1,1} end
|
||||
self:draw(self.body)
|
||||
|
||||
self.particle_timer = self.particle_timer + 1
|
||||
if self.particle_timer >= self.particle_time then
|
||||
local vector = vector(self.vel.x,self.vel.y)
|
||||
local angle = getAngleFromVector(vector)
|
||||
self.particle_timer = 0
|
||||
local particle_data = {
|
||||
animation = animation.particle.simple,
|
||||
animation_speed = 1,
|
||||
sprite_tint = hex2rgb("#fed100"),
|
||||
sprite_alpha_fade = true,
|
||||
direction = angle-math.rad(180+math.random(60)-30),
|
||||
speed = 1,
|
||||
speed_increase = -0.01,
|
||||
time = 0.75
|
||||
}
|
||||
Particle:new(self.pos.x,self.pos.y,particle_data)
|
||||
end
|
||||
end
|
||||
|
||||
function Fairy:doPhysics()
|
||||
local random_x = math.random(-4, 4)/10
|
||||
local random_y = math.random(-4, 4)/10
|
||||
|
||||
self.vel.x = self.vel.x + random_x
|
||||
self.vel.y = self.vel.y + random_y
|
||||
|
||||
self:moveWithCollision()
|
||||
self.vel.x = 0
|
||||
self.vel.y = 0
|
||||
|
||||
-- horizontal collision
|
||||
self:moveX(
|
||||
self.vel.x,
|
||||
function()
|
||||
self.vel.x = 0
|
||||
end
|
||||
)
|
||||
-- vertical collision
|
||||
self:moveY(
|
||||
self.vel.y,
|
||||
function()
|
||||
self.vel.y = 0
|
||||
end
|
||||
)
|
||||
-- final position
|
||||
self:adjustLight()
|
||||
end
|
||||
|
||||
|
||||
@@ -36,10 +36,6 @@ function HookAnchor:drawBackground()
|
||||
)
|
||||
end
|
||||
|
||||
function HookAnchor:doPhysics()
|
||||
end
|
||||
|
||||
|
||||
function Fairy:debug()
|
||||
Entity.debug(self)
|
||||
end
|
||||
|
||||
@@ -44,8 +44,9 @@ function Kupo:doLogic()
|
||||
self.target.y = main_player.pos.y - main_player.target_offset.y
|
||||
local distance_x = self.target.x - self.pos.x
|
||||
local distance_y = self.target.y - self.pos.y
|
||||
|
||||
local distance = math.sqrt(distance_x ^ 2 + distance_y ^ 2)
|
||||
local angle = getAngleFromVector(distance_x,distance_y)
|
||||
local angle = getAngleFromVector(vector(distance_x,distance_y))
|
||||
self.draw_bow = false
|
||||
if distance <= self.range then
|
||||
if self.hostile == true then
|
||||
@@ -153,7 +154,3 @@ function Kupo:handleAnimation()
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
function Kupo:doPhysics()
|
||||
self:moveWithCollision()
|
||||
end
|
||||
|
||||
@@ -89,26 +89,32 @@ function Particle:handleAnimation()
|
||||
end
|
||||
end
|
||||
|
||||
function Particle:doPhysics()
|
||||
function Particle:doLogic()
|
||||
-- adjust speed
|
||||
if self.speed_increase ~= 0 then
|
||||
self.speed = self.speed + self.speed_increase
|
||||
self.vel.x = self.speed * math.cos(self.direction)
|
||||
self.vel.y = self.speed * math.sin(self.direction)
|
||||
end
|
||||
-- move
|
||||
self:moveWithCollision()
|
||||
|
||||
if self.light ~= nil then
|
||||
self:adjustLight()
|
||||
self.light.range = self.light_range * self.sprite_alpha/2
|
||||
end
|
||||
|
||||
if self.time ~= nil then
|
||||
if self.timer >= self.time then self:kill() end
|
||||
end
|
||||
end
|
||||
|
||||
function Particle:doPhysics()
|
||||
-- horizontal collision
|
||||
self:moveX(
|
||||
self.vel.x
|
||||
)
|
||||
-- vertical collision
|
||||
self:moveY(
|
||||
self.vel.y
|
||||
)
|
||||
-- final position
|
||||
self:adjustLight()
|
||||
end
|
||||
|
||||
function Particle:debug()
|
||||
-- draw center CYAN
|
||||
love.graphics.setColor(0,1,1)
|
||||
|
||||
@@ -155,7 +155,7 @@ function Player:doLogic()
|
||||
end
|
||||
|
||||
-- set dash values
|
||||
self.dashDirection = getAngleFromVector(horizontal, vertical)
|
||||
self.dashDirection = getAngleFromVector(vector(horizontal, vertical))
|
||||
self.dash_timer = math.floor(self.dash_time * game.framerate)
|
||||
end
|
||||
else
|
||||
@@ -232,10 +232,10 @@ function Player:doPhysics()
|
||||
-- hook state
|
||||
if self.is_hooked then
|
||||
self.move_x = 0
|
||||
local hook = vector(self.pos.x, self.pos.y, self.hook_anchor.x, self.hook_anchor.y)
|
||||
local hook = vector(self.hook_anchor.x - self.pos.x, self.hook_anchor.y - self.pos.y)
|
||||
local dist = math.min(getVectorValue(hook), self.hook_distance)
|
||||
|
||||
local hook_angle = getAngleFromVector(hook[1],hook[2])-math.rad(180)
|
||||
local hook_angle = getAngleFromVector(hook)-math.rad(180)
|
||||
|
||||
if Keybind:checkDown(Keybind.move.right) then
|
||||
hook_angle = hook_angle - self.hook_swing_speed
|
||||
@@ -264,8 +264,13 @@ function Player:doPhysics()
|
||||
local pos_y = self.hook_anchor.y + dist * math.sin(hook_angle)
|
||||
self.vel.x = self.vel.x + pos_x - self.pos.x
|
||||
self.vel.y = self.vel.y + pos_y - self.pos.y
|
||||
self.pos.x = pos_x
|
||||
self.pos.y = pos_y
|
||||
|
||||
self:moveX(
|
||||
pos_x - self.pos.x
|
||||
)
|
||||
self:moveY(
|
||||
pos_y - self.pos.y
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
@@ -276,24 +281,26 @@ function Player:doPhysics()
|
||||
end
|
||||
|
||||
-- horizontal collision
|
||||
if not self:isCollidingAt(self.pos.x + self.vel.x, self.pos.y, LoadedObjects.Collisions) then
|
||||
self.pos.x = self.pos.x + self.vel.x
|
||||
self.wall_hit = 0
|
||||
else
|
||||
self.wall_hit = math.sign(self.vel.x)
|
||||
self.vel.x = 0
|
||||
end
|
||||
self.wall_hit = 0
|
||||
self:moveX(
|
||||
self.vel.x,
|
||||
function()
|
||||
self.wall_hit = math.sign(self.vel.x)
|
||||
self.vel.x = 0
|
||||
end
|
||||
)
|
||||
|
||||
-- vertical collision
|
||||
if not self:isCollidingAt(self.pos.x, self.pos.y + self.vel.y, LoadedObjects.Collisions) then
|
||||
self.pos.y = self.pos.y + self.vel.y
|
||||
else
|
||||
if self.vel.y > 0 then
|
||||
self.is_on_ground = true
|
||||
self.dash_count = self.dash_amount
|
||||
self:moveY(
|
||||
self.vel.y,
|
||||
function()
|
||||
if self.vel.y > 0 then
|
||||
self.is_on_ground = true
|
||||
self.dash_count = self.dash_amount
|
||||
end
|
||||
self.vel.y = 0
|
||||
end
|
||||
self.vel.y = 0
|
||||
end
|
||||
)
|
||||
|
||||
-- if u collision w hazard, respawn
|
||||
if self:isCollidingAt(self.pos.x, self.pos.y, LoadedObjects.Hazards) then
|
||||
|
||||
@@ -5,6 +5,7 @@ function Entity:new(x,y)
|
||||
local o = {}
|
||||
|
||||
o.pos = {x = x, y = y}
|
||||
o.move_remainder = {x = 0, y = 0}
|
||||
o.vel = {x = 0, y = 0}
|
||||
|
||||
o.direction = 0
|
||||
@@ -69,24 +70,53 @@ end
|
||||
function Entity:doLogic()
|
||||
end
|
||||
|
||||
function Entity:move()
|
||||
self.pos.x = self.pos.x + self.vel.x
|
||||
self.pos.y = self.pos.y + self.vel.y
|
||||
function Entity:moveX(amount, func)
|
||||
self.move_remainder.x = self.move_remainder.x + amount
|
||||
local move = math.round(self.move_remainder.x)
|
||||
if move ~= 0 then
|
||||
self.move_remainder.x = self.move_remainder.x - move
|
||||
local sign = math.sign(move)
|
||||
while math.round(move) ~= 0 do
|
||||
if not self:isCollidingAt(
|
||||
self.pos.x + sign,
|
||||
self.pos.y,
|
||||
LoadedObjects.Collisions
|
||||
) then
|
||||
self.pos.x = self.pos.x + sign
|
||||
move = move - sign
|
||||
if tostring(move) == "nan" then error() end
|
||||
else
|
||||
if func then
|
||||
func()
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Entity:moveWithCollision()
|
||||
-- horizontal collision
|
||||
if not self:isCollidingAt(self.pos.x + self.vel.x, self.pos.y, LoadedObjects.Collisions) then
|
||||
self.pos.x = self.pos.x + self.vel.x
|
||||
else
|
||||
self.vel.x = 0
|
||||
end
|
||||
|
||||
-- vertical collision
|
||||
if not self:isCollidingAt(self.pos.x, self.pos.y + self.vel.y, LoadedObjects.Collisions) then
|
||||
self.pos.y = self.pos.y + self.vel.y
|
||||
else
|
||||
self.vel.y = 0
|
||||
function Entity:moveY(amount, func)
|
||||
self.move_remainder.y = self.move_remainder.y + amount
|
||||
local move = math.round(self.move_remainder.y)
|
||||
if move ~= 0 then
|
||||
self.move_remainder.y = self.move_remainder.y - move
|
||||
local sign = math.sign(move)
|
||||
while math.round(move) ~= 0 do
|
||||
if not self:isCollidingAt(
|
||||
self.pos.x,
|
||||
self.pos.y + sign,
|
||||
LoadedObjects.Collisions
|
||||
) then
|
||||
self.pos.y = self.pos.y + sign
|
||||
move = move - sign
|
||||
if tostring(move) == "nan" then error() end
|
||||
else
|
||||
if func then
|
||||
func()
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -120,8 +150,9 @@ function Entity:checkVisionLine(entity,range)
|
||||
|
||||
local distance_x = target_x - self.pos.x
|
||||
local distance_y = target_y - self.pos.y
|
||||
local distance = vector(distance_x,distance_y)
|
||||
|
||||
local angle = getAngleFromVector(distance_x,distance_y)
|
||||
local angle = getAngleFromVector(distance)
|
||||
local distance = math.sqrt(distance_x ^ 2 + distance_y ^ 2)
|
||||
|
||||
local is_colliding = true
|
||||
@@ -227,8 +258,9 @@ function Entity:checkVisionLineDebug(entity,range)
|
||||
|
||||
local distance_x = target_x - self.pos.x
|
||||
local distance_y = target_y - self.pos.y
|
||||
local distance = vector(distance_x,distance_y)
|
||||
|
||||
local angle = getAngleFromVector(distance_x,distance_y)
|
||||
local angle = getAngleFromVector(distance)
|
||||
local distance = math.sqrt(distance_x ^ 2 + distance_y ^ 2)
|
||||
|
||||
if distance < range then
|
||||
@@ -277,6 +309,9 @@ function Entity:debug()
|
||||
end
|
||||
end
|
||||
|
||||
function Entity:doPhysics()
|
||||
end
|
||||
|
||||
function Entity:handleAnimation()
|
||||
end
|
||||
|
||||
|
||||
@@ -53,10 +53,6 @@ function stepGame()
|
||||
initMenu("dialog",dialog_sequence.example)
|
||||
end
|
||||
|
||||
if Keybind:checkPressed(Keybind.debug.editor) then
|
||||
editor_mode = true
|
||||
end
|
||||
|
||||
if Keybind:checkPressed(Keybind.debug.recording) then
|
||||
if DemoRecording then
|
||||
Demo:endRecord()
|
||||
|
||||
@@ -20,7 +20,6 @@ function drawGameworldBackground()
|
||||
for i = 1, #LevelTiles do
|
||||
for j = 1, #LevelTiles[i] do
|
||||
if LevelTiles[i][j].id ~= 0 then
|
||||
|
||||
local depth = TileData[LevelTiles[i][j].id].depth
|
||||
drawTile(
|
||||
LevelTiles[i][j],
|
||||
|
||||
129
code/in_out.lua
129
code/in_out.lua
@@ -1,90 +1,51 @@
|
||||
function exportLevel(levelname, filename)
|
||||
love.filesystem.createDirectory("export")
|
||||
filename = filename or "output.lua"
|
||||
if string.sub(filename, 1, 1) ~= "/" then
|
||||
filename = "export/"..filename
|
||||
function exportLevel(levelname, dirname)
|
||||
dirname = "export/"..dirname
|
||||
|
||||
if love.filesystem.exists(dirname) then
|
||||
-- TODO: prompt to overwrite
|
||||
error("file already exists")
|
||||
end
|
||||
|
||||
local ok = love.filesystem.createDirectory(dirname)
|
||||
if not ok then
|
||||
logPrint("error creating directory")
|
||||
end
|
||||
exportFile = io.open(filename, "w+")
|
||||
|
||||
if exportFile then
|
||||
logPrint("Exporting level \"".. levelname .. "\"...")
|
||||
exportFile:write("return {")
|
||||
|
||||
logPrint("- level name")
|
||||
exportFile:write("\n name = \"" .. levelname .. "\",")
|
||||
|
||||
logPrint("- tileset")
|
||||
for k, v in pairs(tileset) do
|
||||
if v == LevelData.tileset then
|
||||
exportFile:write("\n tileset = tileset." .. k .. ",")
|
||||
end
|
||||
end
|
||||
|
||||
logPrint("- properties")
|
||||
exportFile:write("\n properties = {")
|
||||
logPrint(" - darkness: ".. tostring(LevelData.properties.darkness))
|
||||
exportFile:write("\n darkness = " .. tostring(LevelData.properties.darkness))
|
||||
exportFile:write("\n },")
|
||||
|
||||
logPrint("- tiles")
|
||||
exportFile:write("\n tiles = {")
|
||||
local rows = #LevelTiles
|
||||
for i = 1, #LevelTiles do
|
||||
if i > 1 then
|
||||
exportFile:write(", ")
|
||||
end
|
||||
exportFile:write("\n { ")
|
||||
for j = 1, #LevelTiles[i] do
|
||||
if j ~= 1 then
|
||||
exportFile:write(", ")
|
||||
end
|
||||
exportFile:write(tostring(LevelTiles[i][j].id))
|
||||
end
|
||||
exportFile:write("}")
|
||||
logPrint(" - row "..i.."/"..rows.." "..math.floor(100*((i-1)*100/rows))/100 .."%")
|
||||
end
|
||||
exportFile:write("\n },")
|
||||
logPrint("- objects")
|
||||
exportFile:write("\n objects = {")
|
||||
logPrint(" - spawns")
|
||||
exportFile:write("\n spawns = {")
|
||||
for i, v in ipairs(LoadedObjects.Spawns) do
|
||||
if i > 1 then
|
||||
exportFile:write(",")
|
||||
end
|
||||
exportFile:write("\n {")
|
||||
exportFile:write(v.archetype.type)
|
||||
exportFile:write(",{")
|
||||
for i=1, #v.args do
|
||||
if i > 1 then
|
||||
exportFile:write(",")
|
||||
end
|
||||
exportFile:write(v.args[i])
|
||||
end
|
||||
exportFile:write("}}")
|
||||
end
|
||||
exportFile:write("\n },")
|
||||
logPrint(" - rooms")
|
||||
exportFile:write("\n rooms = {")
|
||||
for i, room in ipairs(LoadedObjects.Rooms) do
|
||||
if i > 1 then
|
||||
exportFile:write(",")
|
||||
end
|
||||
exportFile:write("\n {{")
|
||||
exportFile:write(room.from.x)
|
||||
exportFile:write(",")
|
||||
exportFile:write(room.from.y)
|
||||
exportFile:write("},{")
|
||||
exportFile:write(room.to.x)
|
||||
exportFile:write(",")
|
||||
exportFile:write(room.to.y)
|
||||
exportFile:write("}}")
|
||||
end
|
||||
exportFile:write("\n },")
|
||||
exportFile:write("\n },")
|
||||
logPrint("Exporting complete.")
|
||||
exportFile:write("\n}")
|
||||
exportFile:close()
|
||||
logPrint("Exporting level \"".. levelname .. "\"...")
|
||||
local exportTable = {}
|
||||
exportTable.name = levelname
|
||||
exportTable.tileset = "library"
|
||||
exportTable.properties = LevelData.properties
|
||||
--exportTable.tiles = LevelTiles
|
||||
--logPrint("- objects")
|
||||
--exportTable.objects = { spawns = {}, rooms = {} }
|
||||
--logPrint(" - spawns")
|
||||
--for i, v in ipairs(LoadedObjects.Spawns) do
|
||||
--exportTable.objects.spawns = {v.archetype.name,{},v.args}
|
||||
--end
|
||||
|
||||
--logPrint(" - rooms")
|
||||
|
||||
--for i, room in ipairs(LoadedObjects.Rooms) do
|
||||
--- table.insert(exportTable.objects.rooms,{room:asRect():getCoords()})
|
||||
--end
|
||||
exportTable.chunks = Chunk:getExportList()
|
||||
logPrint("Writing to file...")
|
||||
local ok, err = love.filesystem.write(dirname.."/level.lua", "return "..serialize_lua_value(exportTable))
|
||||
|
||||
if ok then
|
||||
logPrint("Saving chunks...")
|
||||
local chunkdir = dirname.."/chunks"
|
||||
love.filesystem.createDirectory(chunkdir)
|
||||
for chunk in pairs(Chunk.all) do
|
||||
local ok, err = chunk:save(chunkdir)
|
||||
if not ok then error(err) end
|
||||
end
|
||||
logPrint("Exporting complete.")
|
||||
else
|
||||
-- TODO: clean up created files
|
||||
logPrint("Exporting failed: "..err)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -17,6 +17,10 @@ Keybind.debug = {}
|
||||
Keybind.editor = {}
|
||||
Keybind.generic = {}
|
||||
|
||||
function Keybind:isAvailable(action)
|
||||
return not action.occupied
|
||||
end
|
||||
|
||||
function Keybind:checkDown(action)
|
||||
if DemoPlayback then
|
||||
for _, demo_action in pairs(DemoAction[CurrentDemoFrame]) do
|
||||
@@ -37,9 +41,11 @@ function Keybind:checkDown(action)
|
||||
if action.demo ~= nil then
|
||||
Demo:recordAction(action.demo)
|
||||
end
|
||||
action.occupied = true
|
||||
return true
|
||||
end
|
||||
end
|
||||
action.occupied = false
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
104
code/level.lua
104
code/level.lua
@@ -1,7 +1,25 @@
|
||||
function loadLevelTiles()
|
||||
math.randomseed(3)
|
||||
LevelData = dofile("data/levels/"..level_current)
|
||||
level_current = "data/levels/level1"
|
||||
LevelData = dofile(level_current.."/level.lua")
|
||||
LoadedObjects.Collisions = {}
|
||||
LoadedObjects.Platforms = {}
|
||||
LoadedObjects.Ladders = {}
|
||||
LoadedObjects.Hazards = {}
|
||||
if type(LevelData.tileset) == "string" then
|
||||
LevelData.tileset_name = LevelData.tileset
|
||||
end
|
||||
LevelData.tileset = tileset[LevelData.tileset_name]
|
||||
|
||||
getLevelTileData()
|
||||
|
||||
for _, v in ipairs(LevelData.chunks) do
|
||||
Chunk:new(v[1], v[2])
|
||||
end
|
||||
local global_chunk = next(Chunk.all)
|
||||
global_chunk:load()
|
||||
LoadedObjects.Collisions = global_chunk.loaded.collisions
|
||||
LevelTiles = global_chunk.data.tiles
|
||||
--[[
|
||||
on level format:
|
||||
|
||||
@@ -12,26 +30,26 @@ function loadLevelTiles()
|
||||
overlay_depth = foreground/background overlay depth
|
||||
type = collision type
|
||||
]]
|
||||
getLevelTileData()
|
||||
LevelTiles = LevelData.tiles
|
||||
|
||||
|
||||
updateLevelDimensions()
|
||||
indexLevelTiles()
|
||||
createTileObjects()
|
||||
createRoomObjects()
|
||||
getSpawns()
|
||||
--
|
||||
--createTileObjects()
|
||||
--createRoomObjects()
|
||||
--getSpawns()
|
||||
end
|
||||
|
||||
function createRoomObjects()
|
||||
LoadedObjects.Rooms = {}
|
||||
for _, v in pairs(LevelData.objects.rooms) do
|
||||
table.insert(LoadedObjects.Rooms, Collision:new(v[1][1],v[1][2],v[2][1],v[2][2]))
|
||||
table.insert(LoadedObjects.Rooms, Collision:new(v[1],v[2],v[3],v[4]))
|
||||
end
|
||||
end
|
||||
|
||||
function getSpawns()
|
||||
LoadedObjects.Spawns = {}
|
||||
for _, v in pairs(LevelData.objects.spawns) do
|
||||
addSpawn(v[1],unpack(v[2]))
|
||||
--addSpawn(v[1],unpack(v[2]))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -121,11 +139,8 @@ function reduceLevelCanvas(horizontal,vertical)
|
||||
end
|
||||
|
||||
function getLevelTileData()
|
||||
for k, v in pairs(tileset) do
|
||||
if v == LevelData.tileset then
|
||||
TileData = dofile("data/tileset/"..k..".lua")
|
||||
end
|
||||
end
|
||||
TileData = dofile("data/tileset/"..LevelData.tileset_name..".lua")
|
||||
|
||||
end
|
||||
|
||||
function reloadLevelTiles()
|
||||
@@ -159,10 +174,10 @@ end
|
||||
|
||||
function indexLevelTiles()
|
||||
TileIndex = {}
|
||||
|
||||
local this_tileset = LevelData.tileset
|
||||
-- index from tileset
|
||||
local width = LevelData.tileset:getPixelWidth()/tile_properties.width
|
||||
local height = LevelData.tileset:getPixelHeight()/tile_properties.height
|
||||
local width = this_tileset:getPixelWidth()/tile_properties.width
|
||||
local height = this_tileset:getPixelHeight()/tile_properties.height
|
||||
for i = 0, height do
|
||||
for j = 0, width do
|
||||
TileIndex[i*width+j+1] = love.graphics.newQuad(
|
||||
@@ -170,7 +185,7 @@ function indexLevelTiles()
|
||||
i*tile_properties.height,
|
||||
tile_properties.width,
|
||||
tile_properties.height,
|
||||
LevelData.tileset:getDimensions()
|
||||
this_tileset:getDimensions()
|
||||
)
|
||||
end
|
||||
end
|
||||
@@ -220,6 +235,9 @@ end
|
||||
function instanceTile(id)
|
||||
local tile = {}
|
||||
|
||||
if type(id) == "table" then
|
||||
id = id.id
|
||||
end
|
||||
tile.id = id
|
||||
local Properties = TileData[tile.id]
|
||||
|
||||
@@ -258,7 +276,7 @@ function drawGridDisplay()
|
||||
end
|
||||
end
|
||||
|
||||
function optimizeTileObjects()
|
||||
function optimizeTileObjects(dest)
|
||||
logPrint("Optimizing Objects...")
|
||||
local unoptimized = 0
|
||||
local isTileOptimized = {}
|
||||
@@ -270,8 +288,9 @@ function optimizeTileObjects()
|
||||
end
|
||||
for i = 1, #LevelTiles do
|
||||
for j = 1, #LevelTiles[i] do
|
||||
if LevelTiles[i][j].id ~= 0 then
|
||||
local type = TileData[LevelTiles[i][j].id].type
|
||||
if LevelTiles[i][j].id ~= 0 and TileData[LevelTiles[i][j].id] then
|
||||
local tile_dat = TileData[LevelTiles[i][j].id]
|
||||
local type = tile_dat.type
|
||||
if type == "whole" and not isTileOptimized[i][j] then
|
||||
isTileOptimized[i][j] = true
|
||||
local n = 1
|
||||
@@ -337,29 +356,27 @@ function optimizeTileObjects()
|
||||
base_x + tile_properties.width * tile_properties.scale * n,
|
||||
base_y + tile_properties.height * tile_properties.scale * m
|
||||
)
|
||||
table.insert(LoadedObjects.Collisions,col)
|
||||
table.insert(dest,col)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
logPrint("collisions optimized from " .. unoptimized .. " to " .. #LoadedObjects.Collisions)
|
||||
--logPrint("collisions optimized from " .. unoptimized .. " to " .. #LoadedObjects.Collisions)
|
||||
end
|
||||
|
||||
function createTileObjects()
|
||||
LoadedObjects.Collisions = {}
|
||||
LoadedObjects.Platforms = {}
|
||||
LoadedObjects.Ladders = {}
|
||||
LoadedObjects.Hazards = {}
|
||||
-- currently broken
|
||||
function createTileObjects(dest)
|
||||
|
||||
optimizeTileObjects()
|
||||
|
||||
optimizeTileObjects(dest.collisions)
|
||||
|
||||
for i = 1, #LevelTiles do
|
||||
for j = 1, #LevelTiles[i] do
|
||||
if LevelTiles[i][j].id ~= 0 then
|
||||
|
||||
local type = TileData[LevelTiles[i][j].id].type
|
||||
local light = TileData[LevelTiles[i][j].id].light
|
||||
local tile_dat = TileData[LevelTiles[i][j].id] or {}
|
||||
local type = tile_dat.type
|
||||
local light = tile_dat.light
|
||||
local base_x = tile_properties.scale * j * tile_properties.width + tile_properties.scale * (level_properties.offset.x - tile_properties.height)
|
||||
local base_y = tile_properties.scale * i * tile_properties.height + tile_properties.scale * (level_properties.offset.y - tile_properties.height)
|
||||
|
||||
@@ -372,6 +389,9 @@ function createTileObjects()
|
||||
)
|
||||
end
|
||||
|
||||
local col
|
||||
local list = dest.collisions
|
||||
|
||||
-- wholes are handled in optimization now
|
||||
--[[if type == "whole" then
|
||||
local col = Collision:new(
|
||||
@@ -383,33 +403,33 @@ function createTileObjects()
|
||||
table.insert(LoadedObjects.Collisions,col)
|
||||
else]]if type == "half_bottom" then
|
||||
|
||||
local col = Collision:new(
|
||||
col = Collision:new(
|
||||
base_x,
|
||||
base_y + tile_properties.height/2 * tile_properties.scale,
|
||||
base_x + tile_properties.width * tile_properties.scale,
|
||||
base_y + tile_properties.height * tile_properties.scale
|
||||
)
|
||||
table.insert(LoadedObjects.Collisions,col)
|
||||
|
||||
|
||||
elseif type == "half_top" then
|
||||
|
||||
local col = Collision:new(
|
||||
col = Collision:new(
|
||||
base_x,
|
||||
base_y ,
|
||||
base_x + tile_properties.width * tile_properties.scale,
|
||||
base_y + tile_properties.height/2 * tile_properties.scale
|
||||
)
|
||||
table.insert(LoadedObjects.Collisions,col)
|
||||
|
||||
|
||||
elseif type == "half_right" then
|
||||
|
||||
local col = Collision:new(
|
||||
col = Collision:new(
|
||||
base_x + tile_properties.height/2 * tile_properties.scale,
|
||||
base_y,
|
||||
base_x + tile_properties.width * tile_properties.scale,
|
||||
base_y + tile_properties.height * tile_properties.scale
|
||||
)
|
||||
table.insert(LoadedObjects.Collisions,col)
|
||||
|
||||
|
||||
elseif type == "half_left" then
|
||||
|
||||
@@ -580,7 +600,8 @@ function createTileObjects()
|
||||
|
||||
end
|
||||
|
||||
elseif type == "ladder_right" then
|
||||
-- TODO: fix ladders
|
||||
--[[elseif type == "ladder_right" then
|
||||
|
||||
local ladder = Collision:new(
|
||||
base_x + (tile_properties.width-4)* tile_properties.scale,
|
||||
@@ -638,7 +659,7 @@ function createTileObjects()
|
||||
)
|
||||
table.insert(LoadedObjects.Platforms,plat)
|
||||
|
||||
elseif type == "bottom_hazard" then
|
||||
]]elseif type == "bottom_hazard" then
|
||||
|
||||
|
||||
local hazard = Collision:new(
|
||||
@@ -647,9 +668,10 @@ function createTileObjects()
|
||||
base_x + tile_properties.width * tile_properties.scale,
|
||||
base_y + tile_properties.height * tile_properties.scale
|
||||
)
|
||||
table.insert(LoadedObjects.Hazards,hazard)
|
||||
list = dest.hazards
|
||||
|
||||
end
|
||||
table.insert(list, col)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,20 +8,22 @@ function math.sign(x)
|
||||
end
|
||||
end
|
||||
|
||||
function vector(init_x, init_y, final_x, final_y)
|
||||
local distance_x = final_x - init_x
|
||||
local distance_y = final_y - init_y
|
||||
return {distance_x, distance_y}
|
||||
function math.round(x)
|
||||
return math.floor(x+0.5)
|
||||
end
|
||||
|
||||
function vector(x, y)
|
||||
return {x = x, y = y}
|
||||
end
|
||||
|
||||
function getVectorValue(vector)
|
||||
return math.sqrt(vector[1] ^ 2 + vector[2] ^ 2)
|
||||
return math.sqrt(vector.x ^ 2 + vector.y ^ 2)
|
||||
end
|
||||
|
||||
function getAngleFromVector(x,y)
|
||||
function getAngleFromVector(vector)
|
||||
local reduce = 0
|
||||
if x < 0 then
|
||||
if vector.x < 0 then
|
||||
reduce = math.rad(180)
|
||||
end
|
||||
return math.atan(y/x) - reduce
|
||||
return math.atan(vector.y/vector.x) - reduce
|
||||
end
|
||||
|
||||
@@ -25,10 +25,7 @@ function isThereObjectAt(x,y,objectType)
|
||||
for _, object in pairs(objectType) do
|
||||
if object.is_disabled then
|
||||
-- Dont calculate if dissabled
|
||||
elseif x >= object.from.x
|
||||
and x <= object.to.x
|
||||
and y >= object.from.y
|
||||
and y <= object.to.y then
|
||||
elseif object:asRect():containsPoint(Point:new(x, y)) then
|
||||
object.is_colliding = true
|
||||
return true
|
||||
end
|
||||
@@ -36,14 +33,6 @@ function isThereObjectAt(x,y,objectType)
|
||||
return false
|
||||
end
|
||||
|
||||
function isThereCollisionAt(x,y)
|
||||
if x >= 0 and x < #CollisionTable
|
||||
and y >= 0 and y < #CollisionTable[0] then
|
||||
return CollisionTable[math.floor(y)][math.floor(x)]
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- flags
|
||||
function setCollisionFlags()
|
||||
local Check = {
|
||||
|
||||
86
code/rect.lua
Normal file
86
code/rect.lua
Normal file
@@ -0,0 +1,86 @@
|
||||
-- based of of plan9's Rectangle struct
|
||||
-- rect.max is not counted as "in" the rectangle
|
||||
Rect = {}
|
||||
Rect.__index = Rect
|
||||
|
||||
function Rect:fromPoints(pt1, pt2)
|
||||
local o = { min = pt1, max = pt2 }
|
||||
setmetatable(o, self)
|
||||
return o
|
||||
end
|
||||
|
||||
function Rect:getPoints()
|
||||
return self.min, self.max
|
||||
end
|
||||
|
||||
|
||||
function Rect:fromCoords(x1, y1, x2, y2)
|
||||
return Rect:fromPoints(Point:new(x1, y1), Point:new(x2, y2))
|
||||
end
|
||||
|
||||
function Rect:getCoords()
|
||||
return self.min.x, self.min.y, self.max.x, self.max.y
|
||||
end
|
||||
|
||||
-- clone refers to a deep copy
|
||||
function Rect:clone()
|
||||
return Rect:fromCoords(self.min.x, self.min.y, self.max.x, self.max.y)
|
||||
end
|
||||
|
||||
-- make sure min and max refer to the correct corners
|
||||
-- acts in place, returns self
|
||||
function Rect:fix()
|
||||
if self.min.x > self.max.x then
|
||||
self.min.x, self.max.x = self.max.x, self.min.x
|
||||
end
|
||||
if self.min.y > self.max.y then
|
||||
self.min.y, self.max.y = self.max.y, self.min.y
|
||||
end
|
||||
end
|
||||
|
||||
function Rect:width()
|
||||
return self.max.x - self.min.x
|
||||
end
|
||||
|
||||
function Rect:height()
|
||||
return self.max.y - self.min.y
|
||||
end
|
||||
|
||||
function Rect:size()
|
||||
return Point:new(self:width(), self:height())
|
||||
end
|
||||
|
||||
function Rect:__add(pt)
|
||||
return Rect:fromPoints(self.min + pt, self.max + pt)
|
||||
end
|
||||
|
||||
function Rect:corners()
|
||||
return {
|
||||
self.min:copy(), -- top left
|
||||
Point:new(self.max.x, self.min.y), -- top right
|
||||
Point:new(self.min.x, self.max.y), -- bottom left
|
||||
self.max:copy(), -- bottom right
|
||||
}
|
||||
end
|
||||
|
||||
function Rect:containsPoint(pt)
|
||||
return pt.x >= self.min.x
|
||||
and pt.y >= self.min.y
|
||||
and pt.x <= self.max.x
|
||||
and pt.y <= self.max.y
|
||||
end
|
||||
|
||||
function Rect:overlapsRect(other)
|
||||
return self.min.x < other.max.x
|
||||
and self.max.x > other.min.x
|
||||
and self.min.y < other.max.y
|
||||
and self.max.y > other.min.y
|
||||
end
|
||||
|
||||
function Rect:draw(style)
|
||||
love.graphics.rectangle(style, self.min.x - Camera.pos.x, self.min.y - Camera.pos.y, self:width(), self:height())
|
||||
end
|
||||
|
||||
function Rect:__tostring()
|
||||
return "Rect["..tostring(self.min).." "..tostring(self.max).."]"
|
||||
end
|
||||
@@ -7,6 +7,7 @@ require "data/sfx"
|
||||
require "code/locale"
|
||||
|
||||
-- support functions
|
||||
require "code/serialize"
|
||||
require "code/math"
|
||||
require "code/draw"
|
||||
require "code/hex"
|
||||
@@ -14,6 +15,8 @@ require "code/in_out"
|
||||
|
||||
-- classes
|
||||
require "code/point"
|
||||
require "code/rect"
|
||||
require "code/chunk"
|
||||
require "code/objects"
|
||||
require "code/level"
|
||||
require "code/camera"
|
||||
|
||||
31
code/serialize.lua
Normal file
31
code/serialize.lua
Normal file
@@ -0,0 +1,31 @@
|
||||
local function quote(str, lvl)
|
||||
--lvl = lvl or
|
||||
local rp = "]"..(lvl or "").."]"
|
||||
if string.match(str, rp) then
|
||||
return quote(str, (lvl or "") .. "=")
|
||||
end
|
||||
|
||||
return "["..(lvl or "").."["..str..rp
|
||||
end
|
||||
|
||||
function serialize_lua_value(val)
|
||||
if type(val) == "number" then
|
||||
return tostring(val)
|
||||
elseif type(val) == "string" then
|
||||
-- TODO: use different quotes if ']]' appears in the value
|
||||
return quote(val)
|
||||
elseif type(val) == "table" then
|
||||
local r = "{"
|
||||
for k, v in pairs(val) do
|
||||
r = r .. "[ "..serialize_lua_value(k).." ]="..serialize_lua_value(v)..","
|
||||
end
|
||||
return r .. "}"
|
||||
elseif val == nil then
|
||||
return "nil"
|
||||
elseif val == false then
|
||||
return "false"
|
||||
elseif val == true then
|
||||
return "true"
|
||||
end
|
||||
error("serialization failed")
|
||||
end
|
||||
@@ -20,7 +20,11 @@ function deselectSpawns()
|
||||
end
|
||||
end
|
||||
|
||||
function selectSpawns(x,y)
|
||||
function selectSpawns(rect)
|
||||
local x, y = rect:getPoints()
|
||||
local select_rect = Rect:fromPoints(x-{x=Camera.pos.x,y=Camera.pos.y},y-{x=Camera.pos.x,y=Camera.pos.y})
|
||||
select_rect:fix()
|
||||
|
||||
for _, spawn in pairs(LoadedObjects.Spawns) do
|
||||
|
||||
local offset_x, offset_y = spawn.archetype.display:getCenteredOffset()
|
||||
@@ -28,9 +32,9 @@ function selectSpawns(x,y)
|
||||
local top = spawn.args[2] - Camera.pos.y - offset_y
|
||||
local right = spawn.args[1] - Camera.pos.x + offset_x
|
||||
local bottom = spawn.args[2] - Camera.pos.y + offset_y
|
||||
local x = (x / game.scale)
|
||||
local y = (y / game.scale)
|
||||
if x >= left and y >= top and x <= right and y <= bottom then
|
||||
|
||||
local spawn_rect = Rect:fromCoords(left, top, right, bottom)
|
||||
if spawn_rect:overlapsRect(select_rect) then
|
||||
spawn.selected = true
|
||||
end
|
||||
|
||||
@@ -47,10 +51,22 @@ function selectSpawns(x,y)
|
||||
end
|
||||
|
||||
function moveSpawns(x,y)
|
||||
local move_x = nil
|
||||
local move_y = nil
|
||||
for _, spawn in pairs(LoadedObjects.Spawns) do
|
||||
if spawn.selected then
|
||||
spawn.args[1] = math.floor((x/game.scale)+Camera.pos.x)
|
||||
spawn.args[2] = math.floor((y/game.scale)+Camera.pos.y)
|
||||
local difference_x = math.floor((x/game.scale)+Camera.pos.x) - spawn.args[1]
|
||||
local difference_y = math.floor((y/game.scale)+Camera.pos.y) - spawn.args[2]
|
||||
if move_x == nil or Point.abs({x=difference_x,y=difference_y}) < Point.abs({x=move_x,y=move_y}) then
|
||||
move_x = difference_x
|
||||
move_y = difference_y
|
||||
end
|
||||
end
|
||||
end
|
||||
for _, spawn in pairs(LoadedObjects.Spawns) do
|
||||
if spawn.selected then
|
||||
spawn.args[1] = spawn.args[1] + move_x
|
||||
spawn.args[2] = spawn.args[2] + move_y
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -14,13 +14,10 @@ function drawTextBox(text,x,y,style)
|
||||
local color = style.color or {1,1,1,1}
|
||||
local background_color = style.background_color or {0,0,0,1}
|
||||
local margin = style.margin or 5
|
||||
local rotation = style.rotation or 0
|
||||
local sx = style.sx or 1
|
||||
local sy = style.sy or style.sx
|
||||
|
||||
local lines = 1
|
||||
for i in text:gmatch("\n") do
|
||||
lines = lines + 1
|
||||
lines = lines + 1
|
||||
end
|
||||
|
||||
love.graphics.setColor(unpack(color))
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
return {
|
||||
name = "Dev Level",
|
||||
tileset = tileset.library,
|
||||
properties = {
|
||||
darkness = false
|
||||
},
|
||||
tiles = {
|
||||
{ 1, 4, 0, 0, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
||||
{ 1, 4, 0, 0, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
||||
{ 1, 4, 0, 0, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
||||
{ 1, 4, 0, 0, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
||||
{ 1, 4, 0, 0, 0, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14},
|
||||
{ 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 1, 13, 13, 13, 13, 13, 13, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 1, 1, 1, 1, 1, 1, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 1, 1, 1, 1, 1, 1, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 1, 1, 1, 1, 1, 1, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 1, 1, 1, 1, 1, 1, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 1, 1, 1, 1, 1, 1, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 1, 1, 1, 1, 1, 1, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 1, 1, 1, 1, 1, 1, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 1, 1, 1, 1, 1, 1, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 1, 1, 1, 1, 1, 1, 1, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13},
|
||||
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
||||
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
|
||||
},
|
||||
objects = {
|
||||
spawns = {
|
||||
{Fairy,{100,88}},
|
||||
{HookAnchor,{200,89,100}},
|
||||
{HookAnchor,{400,89,120}}
|
||||
},
|
||||
rooms = {
|
||||
{{96,64},{544,320}},
|
||||
{{0,0},{112,176}}
|
||||
},
|
||||
},
|
||||
}
|
||||
1
data/levels/level1/chunks/global.lua
Normal file
1
data/levels/level1/chunks/global.lua
Normal file
File diff suppressed because one or more lines are too long
1
data/levels/level1/level.lua
Normal file
1
data/levels/level1/level.lua
Normal file
@@ -0,0 +1 @@
|
||||
return {[ [[tileset]] ]=[[library]],[ [[chunks]] ]={[ 1 ]={[ 1 ]=[[global.lua]],},},[ [[name]] ]=[[unnamed]],[ [[properties]] ]={[ [[darkness]] ]=false,},}
|
||||
18
main.lua
18
main.lua
@@ -6,9 +6,10 @@ function love.load()
|
||||
secs = 0
|
||||
|
||||
menu_type = "no"
|
||||
-- FIXME: this overrides a standard library!
|
||||
debug = false
|
||||
debug_collision = false
|
||||
editor_mode = false
|
||||
--editor_mode = false
|
||||
|
||||
text_size = 1
|
||||
|
||||
@@ -103,6 +104,15 @@ function love.update(dt)
|
||||
return
|
||||
end
|
||||
|
||||
if Keybind:checkPressed(Keybind.debug.editor) then
|
||||
if editor.active then
|
||||
deselectSpawns()
|
||||
createTileObjects()
|
||||
restartGame()
|
||||
end
|
||||
editor.active = not editor.active
|
||||
end
|
||||
|
||||
if love.keyboard.isDown("f7") then
|
||||
local test_prompt = Prompt:new({
|
||||
name = "test prompt",
|
||||
@@ -127,7 +137,7 @@ function love.update(dt)
|
||||
if menu_type ~= nil then stepMenu(menu_type) end
|
||||
|
||||
--editor
|
||||
if editor_mode then
|
||||
if editor.active then
|
||||
stepEditor()
|
||||
else
|
||||
stepGame()
|
||||
@@ -136,7 +146,7 @@ end
|
||||
|
||||
|
||||
function love.wheelmoved(_, y)
|
||||
if editor_mode then
|
||||
if editor.active then
|
||||
scrollEditor(y)
|
||||
end
|
||||
end
|
||||
@@ -150,7 +160,7 @@ function love.draw()
|
||||
game_resize = false
|
||||
end
|
||||
|
||||
if editor_mode then
|
||||
if editor.active then
|
||||
drawEditor()
|
||||
else
|
||||
drawGame()
|
||||
|
||||
Reference in New Issue
Block a user