Compare commits
49 Commits
9ada88f4f5
...
Chunk
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
577b7576cf | ||
|
|
fa4b2c86b5 | ||
|
|
e8cef497d4 | ||
|
|
b3a12305da | ||
|
|
236e23177d | ||
|
|
4d94cc805d | ||
|
|
9c4b5431ee | ||
|
|
ba1c0f0c89 | ||
|
|
ef632d50ee | ||
|
|
5bcf25a461 | ||
|
|
1039479c47 | ||
|
|
62555b4526 | ||
|
|
a4af57ca6c | ||
|
|
5189bef537 | ||
|
|
eab4cbbcdc | ||
|
|
829963e080 | ||
|
|
82246dc0c6 | ||
|
|
3a5e0b395b | ||
|
|
feed65cf6d | ||
|
|
1883bcd78b | ||
|
|
3c1746d914 | ||
|
|
f091fba9f7 | ||
|
|
27f1dc71c0 | ||
|
|
97de68e34b | ||
|
|
719c6cc5af | ||
|
|
5f48756e2e | ||
|
|
9c070e161f | ||
|
|
4ae674f0a7 | ||
|
|
362c7ea52d | ||
|
|
644b1a4828 | ||
|
|
c0af34fd76 | ||
|
|
e648705e5b | ||
|
|
61b8aa883b | ||
|
|
3d41699d8f | ||
|
|
f7947af505 | ||
|
|
222f4478ca | ||
|
|
f62ec3ea32 | ||
|
|
266bf10d13 | ||
|
|
96b1e750e4 | ||
|
|
8c8e4808ad | ||
|
|
cb6623f29a | ||
|
|
68fb258d26 | ||
|
|
ce66ab73d3 | ||
|
|
e575cb5725 | ||
|
|
6dd970c1d4 | ||
|
|
dbfae2f74e | ||
|
|
93bfe0bda4 | ||
|
|
39b65571a0 | ||
|
|
6e76607030 |
BIN
assets/entities/nancy/moth_mask/slide1.png
Normal file
BIN
assets/entities/nancy/moth_mask/slide1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 154 B |
BIN
assets/entities/nancy/moth_mask/slide2.png
Normal file
BIN
assets/entities/nancy/moth_mask/slide2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 154 B |
BIN
assets/entities/nancy/moth_mask/slide3.png
Normal file
BIN
assets/entities/nancy/moth_mask/slide3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 154 B |
BIN
assets/entities/nancy/slide1.png
Normal file
BIN
assets/entities/nancy/slide1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
BIN
assets/entities/nancy/slide2.png
Normal file
BIN
assets/entities/nancy/slide2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
BIN
assets/entities/nancy/slide3.png
Normal file
BIN
assets/entities/nancy/slide3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
@@ -15,6 +15,10 @@ function Animation:new(anim_data,speed)
|
||||
return o
|
||||
end
|
||||
|
||||
function Animation:getCenteredOffset()
|
||||
return self.imgs[1]:getWidth()/2, self.imgs[1]:getHeight()/2
|
||||
end
|
||||
|
||||
function Animation:change(anim_data)
|
||||
if anim_data.path == self.path
|
||||
then
|
||||
|
||||
@@ -1,36 +1,38 @@
|
||||
Camera = {
|
||||
pos = {x = 0, y = 0},
|
||||
width = 0,
|
||||
height = 0
|
||||
pos = Point:new(0, 0),
|
||||
width = 0,
|
||||
height = 0,
|
||||
speed = 4,
|
||||
}
|
||||
|
||||
function Camera:followPlayer(player)
|
||||
local pos = player.pos
|
||||
-- make sure we have the Point metatable self:moveTowards(pos)
|
||||
local pos = Point.copy(player.pos)
|
||||
local room = player:getCollidingAt(pos.x,pos.y,LoadedObjects.Rooms)
|
||||
|
||||
self:positionCenterAt(pos.x, pos.y)
|
||||
|
||||
self:confineTo(room)
|
||||
self:moveTowards(self:confineTo(room, pos))
|
||||
end
|
||||
|
||||
function Camera:confineTo(box)
|
||||
function Camera:confineTo(box, pos)
|
||||
if box == nil then
|
||||
--frameDebug("not in a room")
|
||||
return
|
||||
return pos
|
||||
end
|
||||
--frameDebug("in a room")
|
||||
|
||||
local w = self.width/game.scale
|
||||
local h = self.height/game.scale
|
||||
local npos = pos - self:centerOffset()
|
||||
|
||||
-- bottom edge
|
||||
self.pos.y = math.min(self.pos.y+h, box.to.y)-h
|
||||
npos.y = math.min(npos.y+h, box.to.y)-h
|
||||
-- right edge
|
||||
self.pos.x = math.min(self.pos.x+w, box.to.x)-w
|
||||
npos.x = math.min(npos.x+w, box.to.x)-w
|
||||
-- top edge
|
||||
self.pos.y = math.max(self.pos.y, box.from.y)
|
||||
npos.y = math.max(npos.y, box.from.y)
|
||||
-- left edge
|
||||
self.pos.x = math.max(self.pos.x, box.from.x)
|
||||
npos.x = math.max(npos.x, box.from.x)
|
||||
return npos + self:centerOffset()
|
||||
end
|
||||
|
||||
function Camera:confineToLevel()
|
||||
@@ -38,6 +40,32 @@ function Camera:confineToLevel()
|
||||
self.pos.y = math.max(0,math.min(self.pos.y,LevelData.Height-self.height/game.scale))
|
||||
end
|
||||
|
||||
function Camera:moveTowards(pt)
|
||||
--local pt = Point:new(x,y)
|
||||
local diff = pt - self:center()
|
||||
local dist = diff:abs()
|
||||
local npos
|
||||
if dist < self.speed then
|
||||
npos = pt
|
||||
else
|
||||
frameDebug("camera at speed limit")
|
||||
npos = self:center() + diff * (self.speed/dist)
|
||||
frameDebug("dist = "..dist..", npos = "..tostring(npos))
|
||||
end
|
||||
self:positionCenterAt(npos.x, npos.y)
|
||||
end
|
||||
|
||||
function Camera:size()
|
||||
return Point:new(self.width, self.height)
|
||||
end
|
||||
|
||||
function Camera:centerOffset()
|
||||
return self:size()/game.scale/2
|
||||
end
|
||||
|
||||
function Camera:center()
|
||||
return self.pos + self:centerOffset()
|
||||
end
|
||||
function Camera:positionCenterAt(x,y)
|
||||
self.pos.x = x-self.width/game.scale/2
|
||||
self.pos.y = y-self.height/game.scale/2
|
||||
@@ -48,3 +76,17 @@ function Camera:positionAt(x,y)
|
||||
self.pos.x = math.floor((x/self.width)*self.width)
|
||||
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
|
||||
|
||||
266
code/editor.lua
266
code/editor.lua
@@ -1,12 +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()
|
||||
editor.palette_mode = editor.palette_mode or false
|
||||
|
||||
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"
|
||||
@@ -15,61 +40,33 @@ function stepEditor()
|
||||
end
|
||||
editor.room_points = {}
|
||||
end
|
||||
|
||||
if Keybind:checkPressed(Keybind.editor.palette_mode) then
|
||||
if editor.palette_mode then
|
||||
editor.palette_mode = false
|
||||
palette_scroll_x = nil
|
||||
palette_scroll_y = nil
|
||||
else
|
||||
editor.palette_mode = true
|
||||
palette_scroll_x = 0
|
||||
palette_scroll_y = 0
|
||||
end
|
||||
end
|
||||
|
||||
if Keybind:checkPressed(Keybind.editor.palette_mode) then
|
||||
if editor.palette_mode then
|
||||
editor.palette_mode = false
|
||||
palette_scroll_x = nil
|
||||
palette_scroll_y = nil
|
||||
else
|
||||
editor.palette_mode = true
|
||||
palette_scroll_x = 0
|
||||
palette_scroll_y = 0
|
||||
end
|
||||
editor.palette.active = not editor.palette.active
|
||||
end
|
||||
|
||||
|
||||
if Keybind:checkPressed(Keybind.editor.palette_mode) then
|
||||
if editor.palette_mode then
|
||||
editor.palette_mode = false
|
||||
palette_scroll_x = nil
|
||||
palette_scroll_y = nil
|
||||
else
|
||||
editor.palette_mode = true
|
||||
palette_scroll_x = 0
|
||||
palette_scroll_y = 0
|
||||
end
|
||||
end
|
||||
|
||||
-- TODO:
|
||||
-- i changed this but i dont know what was to do here.
|
||||
-- - made specific action keybinds
|
||||
local cvel = Point:new(0, 0)
|
||||
if Keybind:checkDown(Keybind.editor.left) then
|
||||
Camera.pos.x = Camera.pos.x - 3
|
||||
cvel.x = -1
|
||||
end
|
||||
if Keybind:checkDown(Keybind.editor.right) then
|
||||
Camera.pos.x = Camera.pos.x + 3
|
||||
cvel.x = 1
|
||||
end
|
||||
if Keybind:checkDown(Keybind.editor.up) then
|
||||
Camera.pos.y = Camera.pos.y - 3
|
||||
cvel.y = -1
|
||||
end
|
||||
if Keybind:checkDown(Keybind.editor.down) then
|
||||
Camera.pos.y = Camera.pos.y + 3
|
||||
cvel.y = 1
|
||||
end
|
||||
|
||||
if editor.palette_mode then
|
||||
cvel = cvel * editor.pan.speed
|
||||
if not editor.pan.fixed then
|
||||
cvel = cvel / game.scale
|
||||
end
|
||||
|
||||
Camera.pos = Camera.pos + cvel
|
||||
|
||||
if editor.palette.active then
|
||||
if Keybind:checkPressed(Keybind.editor.palette_change) then
|
||||
local next = false
|
||||
local export = nil
|
||||
@@ -97,37 +94,32 @@ function stepEditor()
|
||||
|
||||
if Keybind:checkPressed(Keybind.editor.save) then
|
||||
Prompt:new({
|
||||
name = "level name",
|
||||
input = "unnamed",
|
||||
func = function(name_prompt)
|
||||
if name_prompt.canceled then return end
|
||||
Prompt:new({
|
||||
name = "filename",
|
||||
input = "level.lua",
|
||||
func = function(file_prompt)
|
||||
if file_prompt.canceled then return end
|
||||
exportLevel(name_prompt.input, file_prompt.input)
|
||||
end,
|
||||
}):activate()
|
||||
end,
|
||||
name = "level name",
|
||||
input = "unnamed",
|
||||
func = function(name_prompt)
|
||||
if name_prompt.canceled then return end
|
||||
Prompt:new({
|
||||
name = "filename",
|
||||
input = "unnamed_level",
|
||||
func = function(file_prompt)
|
||||
if file_prompt.canceled then return end
|
||||
exportLevel(name_prompt.input, file_prompt.input)
|
||||
end,
|
||||
}):activate()
|
||||
end,
|
||||
}):activate()
|
||||
end
|
||||
|
||||
if Keybind:checkPressed(Keybind.debug.editor) then
|
||||
editor_mode = not editor_mode
|
||||
createTileObjects()
|
||||
end
|
||||
end
|
||||
|
||||
function scrollEditor(y)
|
||||
if editor.palette_mode then
|
||||
if editor.palette.active then
|
||||
local scr = editor.palette.scroll
|
||||
if love.keyboard.isDown("lshift") then
|
||||
palette_scroll_y = palette_scroll_y + y
|
||||
scr.y = scr.y + y
|
||||
else
|
||||
palette_scroll_x = palette_scroll_x + y
|
||||
scr.x = scr.x + y
|
||||
end
|
||||
else
|
||||
local oscale = game.scale
|
||||
game.scale = math.max(0.1,game.scale + y/16)
|
||||
end
|
||||
end
|
||||
@@ -138,14 +130,21 @@ function drawEditor()
|
||||
drawGridDisplay()
|
||||
drawGameworldForeground()
|
||||
endGameworldDraw()
|
||||
doEditorEdit()
|
||||
|
||||
drawEditorRooms()
|
||||
drawSpawns()
|
||||
|
||||
doEditorEdit()
|
||||
|
||||
drawSelectingPaletteTile()
|
||||
|
||||
if editor.palette_mode then
|
||||
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()
|
||||
@@ -169,8 +168,14 @@ function doEditorEdit()
|
||||
expand_v = vertical
|
||||
end
|
||||
love.graphics.setColor(100, 100, 100, 0.8)
|
||||
love.graphics.print("> " .. horizontal .. ", " .. vertical .. "; " .. math.floor(mouse_x / game.scale + Camera.pos.x) .. ", " .. math.floor(mouse_y / game.scale + Camera.pos.y))
|
||||
love.graphics.print("> " .. level_width .. "(" .. expand_h .. "), " .. level_height .. "(".. expand_v .. ")", 0, 10)
|
||||
drawTextBox(
|
||||
"Coords: [" ..
|
||||
horizontal .. "," .. vertical .. "] (tile)\t[" ..
|
||||
math.floor(mouse_x / game.scale + Camera.pos.x) .. "," .. math.floor(mouse_y / game.scale + Camera.pos.y).."] (pixel)\n" ..
|
||||
"Level size: [" .. level_width .. ", " .. level_height .. "] +(" .. expand_h .. "," .. expand_v .. ")",
|
||||
0,
|
||||
0
|
||||
)
|
||||
|
||||
if editor.room_mode then
|
||||
local rx = horizontal * tile_properties.width
|
||||
@@ -194,27 +199,47 @@ function doEditorEdit()
|
||||
editor.room_points = {}
|
||||
end
|
||||
if editor.room_mode == "delete" then
|
||||
love.graphics.print("Select room to delete", 0, 20)
|
||||
drawTextBox("Select room to delete", 0, 20)
|
||||
elseif #editor.room_points == 0 then
|
||||
love.graphics.print("Select top left of new room", 0, 20)
|
||||
drawTextBox("Select top left of new room", 0, 20)
|
||||
else
|
||||
love.graphics.print("Select bottom right of new room", 0, 20)
|
||||
drawTextBox("Select bottom right of new room", 0, 20)
|
||||
end
|
||||
elseif not editor.palette_mode then
|
||||
elseif not editor.palette.active then
|
||||
if LevelTiles[vertical] ~= nil
|
||||
and LevelTiles[vertical][horizontal] ~= nil
|
||||
and love.keyboard.isDown("lshift") ~= true
|
||||
and love.keyboard.isDown("lctrl") ~= true
|
||||
then
|
||||
if Keybind:checkDown(Keybind.generic.lclick)
|
||||
and selecting_tile ~= nil
|
||||
then
|
||||
setTile(vertical,horizontal,selecting_tile)
|
||||
elseif Keybind:checkDown(Keybind.generic.rclick) then
|
||||
setTile(vertical,horizontal,0)
|
||||
if selecting_tile ~= nil then
|
||||
if Keybind:checkDown(Keybind.editor.tile_set) then
|
||||
setTile(vertical,horizontal,selecting_tile)
|
||||
elseif Keybind:checkDown(Keybind.editor.tile_remove) then
|
||||
setTile(vertical,horizontal,0)
|
||||
end
|
||||
reloadLevelTiles()
|
||||
else
|
||||
if Keybind:checkDown(Keybind.editor.entity_select) then
|
||||
deselectSpawns()
|
||||
if editor.multiselect.box then
|
||||
selectSpawns(editor.multiselect.box)
|
||||
end
|
||||
end
|
||||
if Keybind:checkDown(Keybind.editor.entity_move) then
|
||||
moveSpawns(mouse_x,mouse_y)
|
||||
end
|
||||
if Prompt.active_prompt == nil then
|
||||
if Keybind:checkDown(Keybind.editor.entity_modify_archetype) then
|
||||
promptSpawnArchetype()
|
||||
elseif Keybind:checkDown(Keybind.editor.entity_modify_data) then
|
||||
promptSpawnArgs()
|
||||
elseif Keybind:checkDown(Keybind.editor.entity_remove) then
|
||||
deleteSpawn()
|
||||
elseif Keybind:checkDown(Keybind.editor.entity_new) then
|
||||
promptSpawnNew()
|
||||
end
|
||||
end
|
||||
end
|
||||
reloadLevelTiles()
|
||||
|
||||
elseif Keybind:checkPressed(Keybind.generic.lshift) then
|
||||
expandLevelCanvas(math.sign(expand_h),math.sign(expand_v))
|
||||
reloadLevelTiles()
|
||||
@@ -245,27 +270,31 @@ function drawSelectingPaletteTile()
|
||||
end
|
||||
|
||||
function doEditorPalette()
|
||||
|
||||
local width = LevelData.tileset:getPixelWidth()/tile_properties.width
|
||||
local height = LevelData.tileset:getPixelHeight()/tile_properties.height
|
||||
local mouse_x = love.mouse.getX()
|
||||
local mouse_y = love.mouse.getY()
|
||||
local hovering = nil
|
||||
local hov_x = nil
|
||||
local hov_y = nil
|
||||
local output = ""
|
||||
|
||||
love.graphics.setColor(0,0,0,1)
|
||||
love.graphics.rectangle(
|
||||
"fill",
|
||||
(palette_scroll_x + 1) * (tile_properties.width+1),
|
||||
(palette_scroll_y + 1) * (tile_properties.height+1),
|
||||
(editor.palette.scroll.x + 1) * (tile_properties.width+1),
|
||||
(editor.palette.scroll.y + 1) * (tile_properties.height+1),
|
||||
1 + LevelData.tileset:getPixelWidth() * ((tile_properties.width+1) / tile_properties.width),
|
||||
1 + LevelData.tileset:getPixelHeight()* ((tile_properties.height+1) / tile_properties.height)
|
||||
)
|
||||
|
||||
|
||||
love.graphics.setColor(1,1,1,1)
|
||||
|
||||
local position_x = 1
|
||||
local position_y = 1
|
||||
for i = 1, #TileIndex-width-1 do
|
||||
|
||||
local tile_x = (palette_scroll_x + position_x) * (tile_properties.width+1)
|
||||
local tile_y = (palette_scroll_y + position_y) * (tile_properties.height+1)
|
||||
local tile_x = (editor.palette.scroll.x + position_x) * (tile_properties.width+1)
|
||||
local tile_y = (editor.palette.scroll.y + position_y) * (tile_properties.height+1)
|
||||
|
||||
love.graphics.draw(
|
||||
LevelData.tileset,
|
||||
@@ -276,18 +305,17 @@ function doEditorPalette()
|
||||
1,
|
||||
1
|
||||
)
|
||||
if Keybind:checkDown(Keybind.generic.lclick) then
|
||||
local mouse_x = love.mouse.getX()
|
||||
local mouse_y = love.mouse.getY()
|
||||
|
||||
if mouse_x > (tile_x) * game.scale
|
||||
and mouse_x < (tile_x + tile_properties.width) * game.scale
|
||||
and mouse_y > (tile_y) * game.scale
|
||||
and mouse_y < (tile_y + tile_properties.height) * game.scale
|
||||
then
|
||||
selecting_tile = position_x + ((position_y-1) * width)
|
||||
|
||||
love.graphics.print(selecting_tile .. " | " .. tile_x .. ", " .. tile_y, 0, 20)
|
||||
if mouse_x > (tile_x) * game.scale
|
||||
and mouse_x < (tile_x + tile_properties.width) * game.scale
|
||||
and mouse_y > (tile_y) * game.scale
|
||||
and mouse_y < (tile_y + tile_properties.height) * game.scale
|
||||
then
|
||||
hovering = position_x + ((position_y-1) * width)
|
||||
hov_x = tile_x
|
||||
hov_y = tile_y
|
||||
if Keybind:checkDown(Keybind.generic.lclick) then
|
||||
selecting_tile = hovering
|
||||
end
|
||||
end
|
||||
|
||||
@@ -318,17 +346,47 @@ function doEditorPalette()
|
||||
|
||||
love.graphics.rectangle(
|
||||
"line",
|
||||
(palette_scroll_x + 1) * (tile_properties.width+1),
|
||||
(palette_scroll_y + 1) * (tile_properties.height+1),
|
||||
(editor.palette.scroll.x + 1) * (tile_properties.width+1),
|
||||
(editor.palette.scroll.y + 1) * (tile_properties.height+1),
|
||||
1 + LevelData.tileset:getPixelWidth() * ((tile_properties.width+1) / tile_properties.width),
|
||||
1 + LevelData.tileset:getPixelHeight()* ((tile_properties.height+1) / tile_properties.height)
|
||||
)
|
||||
|
||||
local tile = "none"
|
||||
if selecting_tile ~= nil then
|
||||
tile = "#"..selecting_tile
|
||||
end
|
||||
output = output .. "Selected: " .. tile
|
||||
|
||||
if hovering ~= nil then
|
||||
output = output .. " \nHovering: #".. hovering .. "\nImage coords: " .. hov_x .. ", " .. hov_y
|
||||
end
|
||||
|
||||
drawTextBox(
|
||||
output,
|
||||
(editor.palette.scroll.x + 1+width) * (tile_properties.width+1),
|
||||
(editor.palette.scroll.y + 1) * (tile_properties.height+1)
|
||||
)
|
||||
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
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
CursedBook = Entity:new()
|
||||
CursedBook.type = "CursedBook"
|
||||
CursedBook.display = Animation:new(animation.cursed_book.flying)
|
||||
|
||||
function CursedBook:new(x,y)
|
||||
local o = Entity:new(x,y)
|
||||
@@ -21,13 +22,14 @@ function CursedBook:new(x,y)
|
||||
|
||||
-- animations
|
||||
o.body = Animation:new(animation.cursed_book.spawn)
|
||||
o.body.speed = 0
|
||||
o.sprite_tint = {0.7,0.7,0.7}
|
||||
o:centerOffset(o.body)
|
||||
o:createBox(o.body)
|
||||
|
||||
-- light
|
||||
o.light_range = 500
|
||||
o.light = Light:new(o.pos.x,o.pos.y,o.light_range,2,HEX2RGB("#fe00d1"))
|
||||
--o.light = Light:new(o.pos.x,o.pos.y,o.light_range,2,hex2rgb("#fe00d1"))
|
||||
|
||||
o:id()
|
||||
|
||||
@@ -37,18 +39,20 @@ function CursedBook:new(x,y)
|
||||
end
|
||||
|
||||
function CursedBook:doLogic()
|
||||
print(self.status)
|
||||
self.target.x = main_player.pos.x - main_player.target_offset.x
|
||||
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 angle = GetAngleFromVector(distance_x,distance_y)
|
||||
local angle = getAngleFromVector(distance_x,distance_y)
|
||||
local distance = math.sqrt(distance_x ^ 2 + distance_y ^ 2)
|
||||
|
||||
if self.status == 0 then
|
||||
if distance < self.spawn_range then
|
||||
self.status = 1
|
||||
end
|
||||
elseif self.status == -1 then
|
||||
elseif self.status == 2 then
|
||||
if distance < self.range then
|
||||
self.vel.x = 0
|
||||
self.vel.y = 0
|
||||
@@ -58,21 +62,29 @@ function CursedBook:doLogic()
|
||||
end
|
||||
elseif self.status == 2 then
|
||||
if distance < self.attack_range then
|
||||
self.status = 3
|
||||
--self.status = 3
|
||||
end
|
||||
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()
|
||||
if self.status == 1 then
|
||||
if self.body.path == "assets/entities/cursed_book/spawn" then
|
||||
self.body.speed = 1/3
|
||||
local tint = 0.7 + 0.3 * (self.body.frame-1)/self.body.frames
|
||||
self.body.speed = 1
|
||||
local tint = 0.7 + 0.3 * (self.body.frame-1)/#self.body.frames
|
||||
self.sprite_tint = {tint,tint,tint}
|
||||
if self.body.frame == self.body.frames then
|
||||
if self.body.frame == #self.body.frames then
|
||||
self.status = 2
|
||||
self.isFlying = true
|
||||
self.body = self.body:change(animation.cursed_book.flying)
|
||||
self.sprite_tint = {1,1,1}
|
||||
--self:getBoundingBox(self.body,2,2,-2,-2)
|
||||
@@ -82,9 +94,9 @@ function CursedBook:handleAnimation()
|
||||
elseif self.status == 3 then
|
||||
if self.body.path == "assets/entities/cursed_book/flying" then
|
||||
self.body = self.body:change(animation.cursed_book.attack_transition)
|
||||
self.body.speed = 1/3
|
||||
self:centerOffset(self.body)
|
||||
if self.body.frame == self.body.frames then
|
||||
self.body.speed = 1
|
||||
--self:centerOffset(self.body)
|
||||
if self.body.frame == #self.body.frames then
|
||||
self.status = 4
|
||||
self.body = self.body:change(animation.cursed_book.attack_loop)
|
||||
self:centerOffset(self.body)
|
||||
@@ -96,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
|
||||
|
||||
@@ -114,5 +132,5 @@ function CursedBook:debug()
|
||||
love.graphics.circle("line", -Camera.pos.x + self.pos.x, -Camera.pos.y + self.pos.y, self.spawn_range)
|
||||
love.graphics.setColor(1,0,0)
|
||||
love.graphics.circle("line", -Camera.pos.x + self.pos.x, -Camera.pos.y + self.pos.y, self.attack_range)
|
||||
Entity.Debug(self)
|
||||
Entity.debug(self)
|
||||
end
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
Decoration = Entity:new()
|
||||
Decoration.type = "Decoration"
|
||||
Decoration.display = nil
|
||||
|
||||
function Decoration:new(x,y,animation,light_radius)
|
||||
local o = Entity:new(x,y)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
Fairy = Entity:new()
|
||||
Fairy.type = "Fairy"
|
||||
Fairy.display = Animation:new(animation.fairy.flying)
|
||||
|
||||
function Fairy:new(x,y)
|
||||
local o = Entity:new(x,y)
|
||||
@@ -10,7 +11,7 @@ function Fairy:new(x,y)
|
||||
o.range = 20
|
||||
o.vision_range = 120
|
||||
o.target = {x = x, y = y}
|
||||
o.hover_distance = 60
|
||||
o.hover_distance = 40
|
||||
|
||||
-- animations
|
||||
o.body = Animation:new(animation.fairy.flying)
|
||||
@@ -33,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
|
||||
@@ -41,8 +41,8 @@ function Fairy:doLogic()
|
||||
|
||||
local below = 1
|
||||
while not isThereObjectAt(
|
||||
self.target.x,
|
||||
self.target.y + below * game.scale,
|
||||
self.pos.x,
|
||||
self.pos.y + below * game.scale,
|
||||
LoadedObjects.Collisions
|
||||
) do
|
||||
below = below + 1
|
||||
@@ -50,8 +50,8 @@ function Fairy:doLogic()
|
||||
end
|
||||
local top = 1
|
||||
while not isThereObjectAt(
|
||||
self.target.x,
|
||||
self.target.y - top * game.scale,
|
||||
self.pos.x,
|
||||
self.pos.y - top * game.scale,
|
||||
LoadedObjects.Collisions
|
||||
) do
|
||||
top = top + 1
|
||||
@@ -62,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
|
||||
|
||||
@@ -94,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
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
HookAnchor = Entity:new()
|
||||
HookAnchor.type = "HookAnchor"
|
||||
HookAnchor.display = Animation:new(animation.fairy.flying)
|
||||
|
||||
function HookAnchor:new(x,y,hook_distance)
|
||||
local o = Entity:new(x,y)
|
||||
@@ -35,10 +36,6 @@ function HookAnchor:drawBackground()
|
||||
)
|
||||
end
|
||||
|
||||
function HookAnchor:doPhysics()
|
||||
end
|
||||
|
||||
|
||||
function Fairy:debug()
|
||||
Entity.debug(self)
|
||||
end
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
Kupo = Entity:new()
|
||||
Kupo.type = "Kupo"
|
||||
Kupo.display = Animation:new(animation.kupo.body)
|
||||
|
||||
function Kupo:new(x,y)
|
||||
local o = Entity:new(x,y)
|
||||
@@ -43,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
|
||||
@@ -152,7 +154,3 @@ function Kupo:handleAnimation()
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
function Kupo:doPhysics()
|
||||
self:moveWithCollision()
|
||||
end
|
||||
|
||||
@@ -2,6 +2,7 @@ LoadedObjects.Particles = {}
|
||||
|
||||
Particle = Entity:new()
|
||||
Particle.type = "Particle"
|
||||
Particle.display = Animation:new(animation.particle.simple)
|
||||
|
||||
function Particle:new(x,y,particle_data)
|
||||
local o = Entity:new(x,y)
|
||||
@@ -20,8 +21,14 @@ function Particle:new(x,y,particle_data)
|
||||
o.sprite_flip = particle_data.sprite_flip or o.sprite_flip
|
||||
|
||||
o.time = particle_data.time or nil
|
||||
if o.time ~= nil then o.time = o.time * game.framerate end
|
||||
|
||||
if o.time ~= nil then
|
||||
if particle_data.time_unit ~= nil
|
||||
and particle_data.time_unit == "frames" then
|
||||
o.time = o.time
|
||||
else
|
||||
o.time = o.time * game.framerate
|
||||
end
|
||||
end
|
||||
o.timer = 0
|
||||
|
||||
o.vel = {
|
||||
@@ -82,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)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
Player = Entity:new()
|
||||
Player.type = "Player"
|
||||
Player.display = Animation:new(animation.nancy.idle)
|
||||
|
||||
function Player:new(x,y)
|
||||
local o = Entity:new(x,y)
|
||||
@@ -71,7 +72,7 @@ function Player:new(x,y)
|
||||
o.mask = Animation:new(animation.moth_mask.idle)
|
||||
|
||||
o:centerOffset(o.body)
|
||||
o:createBox(o.body,0,3,-1,-3)
|
||||
o:createBox(o.body,0,4,-1,-5)
|
||||
|
||||
-- lights
|
||||
o.light = Light:new(o.pos.x,o.pos.y,o.light_radius)
|
||||
@@ -131,10 +132,13 @@ function Player:doLogic()
|
||||
if self.dash_cooldown_timer == 0
|
||||
and not self.is_dashing
|
||||
and self.dash_count > 0 then
|
||||
|
||||
self:unhook()
|
||||
self.nodrift_frames = 0
|
||||
|
||||
-- state player
|
||||
self.is_dashing = true
|
||||
self.is_sliding = false
|
||||
self.dash_count = self.dash_count - 1
|
||||
|
||||
-- get dash direction
|
||||
@@ -151,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
|
||||
@@ -228,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
|
||||
@@ -247,7 +251,8 @@ function Player:doPhysics()
|
||||
animation_speed = 0,
|
||||
sprite_tint = hex2rgb("#fed100"),
|
||||
sprite_alpha = 0.5,
|
||||
time = 0.05,
|
||||
time = 4,
|
||||
time_unit = "frames",
|
||||
sprite_flip = {
|
||||
x = self.sprite_flip.x,
|
||||
y = self.sprite_flip.y
|
||||
@@ -259,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
|
||||
|
||||
|
||||
@@ -271,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
|
||||
@@ -312,18 +324,20 @@ function Player:handleAnimation()
|
||||
elseif self.move_x ~= 0 then
|
||||
self.sprite_flip.x = math.sign(self.move_x)
|
||||
end
|
||||
|
||||
-- animation priority
|
||||
if self.vel.y > 1.25 or self.is_sliding then
|
||||
if self.is_sliding then
|
||||
self.body = self.body:change(animation.nancy.slide)
|
||||
self.mask = self.mask:change(self.mask_type.slide)
|
||||
elseif self.vel.y > 1.25 then
|
||||
self.body = self.body:change(animation.nancy.fall)
|
||||
self.mask = self.mask:change(self.mask_type.fall)
|
||||
elseif self.vel.y < 0 then
|
||||
self.body = self.body:change(animation.nancy.jump)
|
||||
self.mask = self.mask:change(self.mask_type.jump)
|
||||
elseif self.vel.x + self.move_x ~= 0 then
|
||||
elseif self.vel.x + self.move_x ~= 0 and not self.is_hooked then
|
||||
self.body = self.body:change(animation.nancy.run)
|
||||
self.mask = self.mask:change(self.mask_type.run)
|
||||
else
|
||||
elseif not self.is_hooked then
|
||||
self.body = self.body:change(animation.nancy.idle)
|
||||
self.mask = self.mask:change(self.mask_type.idle)
|
||||
end
|
||||
|
||||
@@ -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
|
||||
@@ -38,21 +39,29 @@ end
|
||||
function Entity:checkNearest(type,maxdistance)
|
||||
local return_entity = nil
|
||||
local shortest = -1
|
||||
local flag_variable_distance = false
|
||||
|
||||
if maxdistance == "hook_specific" then
|
||||
flag_variable_distance = true
|
||||
end
|
||||
|
||||
for _, entity in pairs(LoadedObjects.Entities) do
|
||||
if not type or entity.type == type then
|
||||
local distance_x = entity.pos.x - self.pos.x
|
||||
local distance_y = entity.pos.y - self.pos.y
|
||||
local distance = math.sqrt(distance_x ^ 2 + distance_y ^ 2)
|
||||
|
||||
if maxdistance == "hook_specific" then maxdistance = entity.hook_distance end
|
||||
if flag_variable_distance then
|
||||
maxdistance = entity.hook_distance
|
||||
end
|
||||
|
||||
if not maxdistance or distance < maxdistance then
|
||||
if shortest == -1 or distance < shortest then
|
||||
shortest = distance
|
||||
return_entity = entity
|
||||
end
|
||||
print(shortest,maxdistance,distance)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
return return_entity
|
||||
@@ -61,26 +70,54 @@ 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()
|
||||
local r = false
|
||||
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
|
||||
r = true
|
||||
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
|
||||
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
|
||||
r = true
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
function Entity:adjustLight(x,y)
|
||||
@@ -97,12 +134,12 @@ function Entity:kill()
|
||||
self.light:kill()
|
||||
end
|
||||
if self.id ~= nil then
|
||||
table.remove(LoadedObjects.Entities,self.id)
|
||||
for _, e in pairs(LoadedObjects.Entities) do
|
||||
if e.id > self.id then
|
||||
e.id = e.id - 1
|
||||
end
|
||||
end
|
||||
table.remove(LoadedObjects.Entities,self.id)
|
||||
end
|
||||
self = nil
|
||||
end
|
||||
@@ -113,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
|
||||
@@ -136,6 +174,7 @@ function Entity:checkVisionLine(entity,range)
|
||||
end
|
||||
|
||||
function Entity:draw(animation)
|
||||
if animation == nil then return end
|
||||
local c1, c2, c3, a = love.graphics.getColor()
|
||||
love.graphics.setColor(self.sprite_tint[1],self.sprite_tint[2],self.sprite_tint[3],self.sprite_alpha)
|
||||
animation:draw(
|
||||
@@ -149,6 +188,7 @@ function Entity:draw(animation)
|
||||
end
|
||||
|
||||
function Entity:centerOffset(animation,x,y)
|
||||
if animation == nil then return end
|
||||
local x = x or 0
|
||||
local y = y or 0
|
||||
self.sprite_offset.x = animation.imgs[1]:getWidth()/2 + x
|
||||
@@ -156,6 +196,7 @@ function Entity:centerOffset(animation,x,y)
|
||||
end
|
||||
|
||||
function Entity:createBox(animation,top,left,bottom,right)
|
||||
if animation == nil then return end
|
||||
local left = left or 0
|
||||
local right = right or 0
|
||||
local top = top or 0
|
||||
@@ -217,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
|
||||
@@ -267,6 +309,9 @@ function Entity:debug()
|
||||
end
|
||||
end
|
||||
|
||||
function Entity:doPhysics()
|
||||
end
|
||||
|
||||
function Entity:handleAnimation()
|
||||
end
|
||||
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
function restartGame()
|
||||
for _, entity in ipairs(LoadedObjects.Entities) do
|
||||
if entity.light ~= nil then entity.light:kill() end
|
||||
entity = nil
|
||||
end
|
||||
LoadedObjects.Entities = {}
|
||||
LoadedObjects.Particles = {}
|
||||
main_player = Player:new(75,50)
|
||||
activateSpawns()
|
||||
end
|
||||
|
||||
function stepGame()
|
||||
setCollisionFlags()
|
||||
if menu_type == "no" then
|
||||
@@ -33,13 +44,7 @@ function stepGame()
|
||||
end
|
||||
|
||||
if Keybind:checkPressed(Keybind.debug.reposition) then
|
||||
if not editor_mode then
|
||||
main_player.pos.x, main_player.pos.y = 75,50
|
||||
end
|
||||
for _, entity in pairs(LoadedObjects.Entities) do
|
||||
if entity.id ~= main_player.id then entity:kill() end
|
||||
end
|
||||
activateSpawns()
|
||||
restartGame()
|
||||
end
|
||||
|
||||
if Keybind:checkPressed(Keybind.debug.reload) then
|
||||
@@ -48,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
|
||||
@@ -123,11 +129,19 @@ function Keybind:default()
|
||||
Keybind.editor.down = { keys = {"down", "s"}}
|
||||
Keybind.editor.palette_change = { keys = {"f1"}}
|
||||
Keybind.editor.save = { keys = {"f3"}}
|
||||
|
||||
Keybind.editor.tile_set = { keys = {1}}
|
||||
Keybind.editor.tile_remove = { keys = {2}}
|
||||
Keybind.editor.entity_select = { keys = {1}}
|
||||
Keybind.editor.entity_move = { keys = {2}}
|
||||
Keybind.editor.entity_modify_archetype = { keys = {"t"}}
|
||||
Keybind.editor.entity_modify_data = { keys = {"g"}}
|
||||
Keybind.editor.entity_remove = { keys = {"delete"}}
|
||||
Keybind.editor.entity_new = { keys = {"n"}}
|
||||
-- Generic
|
||||
Keybind.generic.lclick = { keys = {1}}
|
||||
Keybind.generic.rclick = { keys = {2}}
|
||||
Keybind.generic.lshift = { keys = {"lshift"}}
|
||||
Keybind.generic.alt = { keys = {"alt"}}
|
||||
Keybind.generic.lctrl = { keys = {"lctrl"}}
|
||||
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
|
||||
|
||||
@@ -26,12 +26,12 @@ end
|
||||
|
||||
function Light:kill()
|
||||
if self.id ~= nil then
|
||||
table.remove(LoadedObjects.Lights,self.id)
|
||||
for _, e in pairs(LoadedObjects.Lights) do
|
||||
if e.id > self.id then
|
||||
e.id = e.id - 1
|
||||
end
|
||||
end
|
||||
table.remove(LoadedObjects.Lights,self.id)
|
||||
end
|
||||
self = nil
|
||||
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 = {
|
||||
|
||||
37
code/point.lua
Normal file
37
code/point.lua
Normal file
@@ -0,0 +1,37 @@
|
||||
Point = {}
|
||||
Point.__index = Point
|
||||
|
||||
function Point:new(x, y)
|
||||
local o = { x = x or 0, y = y or 0 }
|
||||
setmetatable(o, self)
|
||||
return o
|
||||
end
|
||||
|
||||
function Point:__add(other)
|
||||
return Point:new(self.x+other.x, self.y+other.y)
|
||||
end
|
||||
|
||||
function Point:__sub(other)
|
||||
return Point:new(self.x-other.x, self.y-other.y)
|
||||
end
|
||||
|
||||
function Point:__mul(n)
|
||||
return Point:new(self.x*n, self.y*n)
|
||||
end
|
||||
|
||||
function Point:__div(n)
|
||||
return Point:new(self.x/n, self.y/n)
|
||||
end
|
||||
|
||||
-- absolute value, or the distance from the origin
|
||||
function Point:abs()
|
||||
return math.sqrt(self.x ^ 2 + self.y ^ 2)
|
||||
end
|
||||
|
||||
function Point:__tostring()
|
||||
return "("..self.x..","..self.y..")"
|
||||
end
|
||||
|
||||
function Point:copy()
|
||||
return Point:new(self.x, self.y)
|
||||
end
|
||||
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,12 +7,16 @@ require "data/sfx"
|
||||
require "code/locale"
|
||||
|
||||
-- support functions
|
||||
require "code/serialize"
|
||||
require "code/math"
|
||||
require "code/draw"
|
||||
require "code/hex"
|
||||
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
|
||||
249
code/spawn.lua
249
code/spawn.lua
@@ -10,6 +10,253 @@ end
|
||||
|
||||
function activateSpawns()
|
||||
for _, spawn in pairs(LoadedObjects.Spawns) do
|
||||
spawn.archetype:new(unpack(spawn.args))
|
||||
spawn.archetype:new(unpack(spawn.args))
|
||||
end
|
||||
end
|
||||
|
||||
function deselectSpawns()
|
||||
for _, spawn in pairs(LoadedObjects.Spawns) do
|
||||
spawn.selected = nil
|
||||
end
|
||||
end
|
||||
|
||||
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()
|
||||
local left = spawn.args[1] - Camera.pos.x - offset_x
|
||||
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 spawn_rect = Rect:fromCoords(left, top, right, bottom)
|
||||
if spawn_rect:overlapsRect(select_rect) then
|
||||
spawn.selected = true
|
||||
end
|
||||
|
||||
if spawn.selected then
|
||||
love.graphics.setColor(0,1,1,1)
|
||||
else
|
||||
love.graphics.setColor(0,1,0,1)
|
||||
end
|
||||
|
||||
love.graphics.rectangle("fill",left-2,top-2,4,4)
|
||||
love.graphics.rectangle("fill",right-2,bottom-2,4,4)
|
||||
love.graphics.setColor(1,1,1,1)
|
||||
end
|
||||
end
|
||||
|
||||
function moveSpawns(x,y)
|
||||
local move_x = nil
|
||||
local move_y = nil
|
||||
for _, spawn in pairs(LoadedObjects.Spawns) do
|
||||
if spawn.selected then
|
||||
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
|
||||
|
||||
|
||||
function promptSpawnNew()
|
||||
Prompt:cancelActive()
|
||||
local text = ""
|
||||
local prompt = Prompt:new({
|
||||
name = "new spawn",
|
||||
input = text,
|
||||
func = function(prompt)
|
||||
local f = loadstring("return {"..prompt.input.."}")
|
||||
if f ~= nil then
|
||||
local succ, result = pcall(f)
|
||||
local arch = result[1]
|
||||
local args = {}
|
||||
if #result > 1 then
|
||||
for i=2, #result+1 do
|
||||
print("arg #"..i-1)
|
||||
args[i-1] = result[i]
|
||||
if i < 4 then
|
||||
args[i-1] = math.floor(args[i-1])
|
||||
end
|
||||
end
|
||||
else
|
||||
args = {0,0}
|
||||
end
|
||||
|
||||
print("new entity spawn --",succ)
|
||||
if not succ
|
||||
or checkArchetypeInvalid(arch)
|
||||
then
|
||||
print("invalid input for prompt "..prompt.name)
|
||||
else
|
||||
print("archetype: ",arch.type)
|
||||
print("args: ",unpack(args))
|
||||
addSpawn(arch, unpack(args))
|
||||
end
|
||||
else
|
||||
print("invalid input for prompt "..prompt.name)
|
||||
end
|
||||
end,
|
||||
})
|
||||
prompt.pos.x = 0
|
||||
prompt.pos.y = 10
|
||||
prompt:activate()
|
||||
end
|
||||
|
||||
function deleteSpawn()
|
||||
for i=1, #LoadedObjects.Spawns do
|
||||
if LoadedObjects.Spawns[i]
|
||||
and LoadedObjects.Spawns[i].selected then
|
||||
table.remove(LoadedObjects.Spawns,i)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function checkArchetypeInvalid(arch)
|
||||
return type(arch) ~= "table" or type(arch.type) ~= "string"
|
||||
end
|
||||
|
||||
function promptSpawnArchetype()
|
||||
Prompt:cancelActive()
|
||||
for _, spawn in pairs(LoadedObjects.Spawns) do
|
||||
if spawn.selected then
|
||||
local offset_x, offset_y = spawn.archetype.display:getCenteredOffset()
|
||||
local text = ""
|
||||
for i=1, #spawn.args do
|
||||
if i > 1 then text = text .. ", " end
|
||||
text = text .. tostring(spawn.args[i])
|
||||
end
|
||||
local prompt = Prompt:new({
|
||||
name = "archetype",
|
||||
input = spawn.archetype.type,
|
||||
spawn = spawn,
|
||||
func = function(prompt)
|
||||
print("return "..prompt.input)
|
||||
local f = loadstring("return "..prompt.input)
|
||||
if f ~= nil then
|
||||
local succ, arch = pcall(f)
|
||||
print("archetype changed --",succ)
|
||||
print("from: ", spawn.archetype.type)
|
||||
if not succ
|
||||
or checkArchetypeInvalid(arch)
|
||||
then
|
||||
arch = spawn.archetype
|
||||
end
|
||||
print("to: ", arch.type)
|
||||
spawn.archetype = arch
|
||||
else
|
||||
print("invalid input for prompt "..prompt.name)
|
||||
end
|
||||
end,
|
||||
})
|
||||
prompt.pos.x = (spawn.args[1]-4)*game.scale - Camera.pos.x - offset_x
|
||||
prompt.pos.y = (spawn.args[2]-20)*game.scale - Camera.pos.y - offset_y
|
||||
prompt:activate()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function checkArgsInvalid(args)
|
||||
for _, arg in pairs(args) do
|
||||
-- this is checking the args are not nil variables
|
||||
if arg == nil
|
||||
or arg == ""
|
||||
then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function promptSpawnArgs()
|
||||
Prompt:cancelActive()
|
||||
for _, spawn in pairs(LoadedObjects.Spawns) do
|
||||
if spawn.selected then
|
||||
local offset_x, offset_y = spawn.archetype.display:getCenteredOffset()
|
||||
local text = ""
|
||||
for i=1, #spawn.args do
|
||||
if i > 1 then text = text .. ", " end
|
||||
text = text .. tostring(spawn.args[i])
|
||||
end
|
||||
local prompt = Prompt:new({
|
||||
name = "args",
|
||||
input = text,
|
||||
func = function(prompt)
|
||||
local f = loadstring("return {"..prompt.input.."}")
|
||||
if f ~= nil then
|
||||
local succ, args = pcall(f)
|
||||
print("args changed --",succ)
|
||||
print("from: ", unpack(args))
|
||||
if not succ
|
||||
or checkArgsInvalid(args)
|
||||
then
|
||||
args = spawn.args
|
||||
end
|
||||
print("to: ", unpack(args))
|
||||
spawn.args = args
|
||||
else
|
||||
print("invalid input for prompt "..prompt.name)
|
||||
end
|
||||
end,
|
||||
})
|
||||
prompt.pos.x = (spawn.args[1]-4)*game.scale - Camera.pos.x - offset_x
|
||||
prompt.pos.y = (spawn.args[2]-4)*game.scale - Camera.pos.y - offset_y
|
||||
prompt:activate()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function drawSpawns()
|
||||
for _, spawn in pairs(LoadedObjects.Spawns) do
|
||||
local offset_x, offset_y = spawn.archetype.display:getCenteredOffset()
|
||||
love.graphics.setColor(1,1,1,1)
|
||||
spawn.archetype.display:draw(
|
||||
spawn.args[1] - Camera.pos.x - offset_x,
|
||||
spawn.args[2] - Camera.pos.y - offset_y
|
||||
)
|
||||
|
||||
|
||||
if spawn.selected then
|
||||
love.graphics.setColor(0,1,1,1)
|
||||
else
|
||||
love.graphics.setColor(0,1,0,1)
|
||||
end
|
||||
|
||||
love.graphics.rectangle(
|
||||
"line",
|
||||
spawn.args[1] - Camera.pos.x - offset_x,
|
||||
spawn.args[2] - Camera.pos.y - offset_y,
|
||||
spawn.args[1] - Camera.pos.x + offset_x - (spawn.args[1] - Camera.pos.x - offset_x),
|
||||
spawn.args[2] - Camera.pos.y + offset_y - (spawn.args[2] - Camera.pos.y - offset_y)
|
||||
)
|
||||
|
||||
if spawn.selected then
|
||||
local text = spawn.archetype.type.."\n---\nPosition\n["..spawn.args[1]..","..spawn.args[2].."]"
|
||||
if #spawn.args > 2 then
|
||||
text = text .. "\n---\nData:\n"
|
||||
for i=3, #spawn.args do
|
||||
if i > 3 then text = text .. ", " end
|
||||
text = text .. tostring(spawn.args[i])
|
||||
end
|
||||
end
|
||||
drawTextBox(
|
||||
text,
|
||||
spawn.args[1] - Camera.pos.x + 20,
|
||||
spawn.args[2] - Camera.pos.y
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
34
code/ui.lua
34
code/ui.lua
@@ -5,6 +5,40 @@ function addElement(self)
|
||||
self.id = #UIElement
|
||||
end
|
||||
|
||||
function drawTextBox(text,x,y,style)
|
||||
local style = style or {}
|
||||
local c1, c2, c3, a = love.graphics.getColor()
|
||||
local width = locale_font:getWidth(text)
|
||||
local height = locale_font:getHeight(text)
|
||||
|
||||
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 lines = 1
|
||||
for i in text:gmatch("\n") do
|
||||
lines = lines + 1
|
||||
end
|
||||
|
||||
love.graphics.setColor(unpack(color))
|
||||
love.graphics.rectangle("fill",
|
||||
x-1,
|
||||
y-1,
|
||||
width+margin*2+2,
|
||||
height*lines+margin*2+2
|
||||
)
|
||||
love.graphics.setColor(unpack(background_color))
|
||||
love.graphics.rectangle("fill",
|
||||
x,
|
||||
y,
|
||||
width+margin*2,
|
||||
height*lines+margin*2
|
||||
)
|
||||
love.graphics.setColor(unpack(color))
|
||||
love.graphics.print(text, x+margin, y+margin)
|
||||
love.graphics.setColor(c1,c2,c3,a)
|
||||
end
|
||||
|
||||
require "code/ui/button"
|
||||
require "code/ui/dialog"
|
||||
require "code/ui/prompt"
|
||||
|
||||
@@ -4,12 +4,12 @@ local function backspace(text)
|
||||
local byteoffset = utf8.offset(text, -1)
|
||||
|
||||
if byteoffset then
|
||||
-- remove the last UTF-8 character.
|
||||
-- string.sub operates on bytes rather than UTF-8 characters,
|
||||
-- so we couldn't do string.sub(text, 1, -2).
|
||||
return string.sub(text, 1, byteoffset - 1)
|
||||
-- remove the last UTF-8 character.
|
||||
-- string.sub operates on bytes rather than UTF-8 characters,
|
||||
-- so we couldn't do string.sub(text, 1, -2).
|
||||
return string.sub(text, 1, byteoffset - 1)
|
||||
end
|
||||
|
||||
|
||||
return ""
|
||||
end
|
||||
|
||||
@@ -20,9 +20,15 @@ Prompt = {
|
||||
name = "input",
|
||||
canceled = false,
|
||||
closing = false,
|
||||
|
||||
color = {1,1,1,1},
|
||||
background_color = {0,0,0,1},
|
||||
active_prompt = nil,
|
||||
}
|
||||
function Prompt:cancelActive()
|
||||
if Prompt.active_prompt then
|
||||
Prompt.active_prompt.canceled = true
|
||||
end
|
||||
end
|
||||
|
||||
function Prompt:new(o)
|
||||
o = o or {}
|
||||
@@ -44,7 +50,7 @@ function Prompt:keypressed(key, scancode, isrepeat)
|
||||
end
|
||||
|
||||
function Prompt:update()
|
||||
|
||||
|
||||
end
|
||||
|
||||
function Prompt:textinput(text)
|
||||
@@ -52,7 +58,15 @@ function Prompt:textinput(text)
|
||||
end
|
||||
|
||||
function Prompt:draw()
|
||||
love.graphics.print(self.name .. ": " .. self.input, self.pos.x, self.pos.y)
|
||||
drawTextBox(
|
||||
self.name .. ": " .. self.input,
|
||||
self.pos.x,
|
||||
self.pos.y,
|
||||
{
|
||||
color = self.color,
|
||||
background_color = self.background_color
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
function Prompt:activate()
|
||||
@@ -65,4 +79,3 @@ local test_prompt = Prompt:new()
|
||||
assert(test_prompt.name == "input")
|
||||
test_prompt.name = "foobar"
|
||||
assert(Prompt.name == "input")
|
||||
|
||||
|
||||
@@ -35,11 +35,11 @@ animation.cursed_book.flying = {
|
||||
animation.cursed_book.spawn = {
|
||||
path = "assets/entities/cursed_book/spawn",
|
||||
frames = {
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
1/3,
|
||||
1/3,
|
||||
1/3,
|
||||
1/3,
|
||||
1/3
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,6 +140,15 @@ animation.moth_mask.fall = {
|
||||
1/8
|
||||
}
|
||||
}
|
||||
|
||||
animation.moth_mask.slide = {
|
||||
path = "assets/entities/nancy/moth_mask/slide",
|
||||
frames = {
|
||||
1/8,
|
||||
1/8,
|
||||
1/8
|
||||
}
|
||||
}
|
||||
animation.moth_mask.jump = {
|
||||
path = "assets/entities/nancy/moth_mask/jump",
|
||||
frames = {
|
||||
@@ -179,6 +188,14 @@ animation.nancy.fall = {
|
||||
1/8
|
||||
}
|
||||
}
|
||||
animation.nancy.slide = {
|
||||
path = "assets/entities/nancy/slide",
|
||||
frames = {
|
||||
1/8,
|
||||
1/8,
|
||||
1/8
|
||||
}
|
||||
}
|
||||
animation.nancy.jump = {
|
||||
path = "assets/entities/nancy/jump",
|
||||
frames = {
|
||||
|
||||
@@ -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