1
0

improve main menu

This commit is contained in:
Rokas Puzonas 2022-08-21 22:53:40 +00:00
parent 6ab0b2eb4a
commit 0066f8ba0a
18 changed files with 403 additions and 51 deletions

View File

@ -4,6 +4,9 @@
"param-type-mismatch", "param-type-mismatch",
"cast-local-type" "cast-local-type"
], ],
"Lua.diagnostics.globals": [
"pprint"
],
"Lua.runtime.version": "LuaJIT", "Lua.runtime.version": "LuaJIT",
"Lua.workspace.checkThirdParty": false, "Lua.workspace.checkThirdParty": false,
"Lua.workspace.library": [ "Lua.workspace.library": [

View File

@ -9,26 +9,31 @@ love.graphics.setDefaultFilter("nearest", "nearest")
-- TODO: Maybe add a texture atlas library for packing frame data -- TODO: Maybe add a texture atlas library for packing frame data
-- TODO: For production maybe use another type of loader? (https://github.com/elloramir/packer, https://github.com/EngineerSmith/Runtime-TextureAtlas) -- TODO: For production maybe use another type of loader? (https://github.com/elloramir/packer, https://github.com/EngineerSmith/Runtime-TextureAtlas)
local function loadAsepriteSprite(filename) local function loadAsepriteSprite(filename)
local sprite = {}
local ase = aseLoader(filename) local ase = aseLoader(filename)
sprite.width = ase.header.width
sprite.height = ase.header.height
sprite.variants = {}
local LAYER_CHUNK = 0x2004 local LAYER_CHUNK = 0x2004
local CEL_CHUNK = 0x2005 local CEL_CHUNK = 0x2005
local TAG_CHUNK = 0x2018 local TAG_CHUNK = 0x2018
local SLICE_CHUNK = 0x2022
local USER_CHUNK = 0x2020
local frames = {} local frames = {}
local tags = {} local tags = {}
local layers = {} local layers = {}
local slices = {}
love.graphics.push("transform") love.graphics.push("transform")
love.graphics.origin() love.graphics.origin()
local width = ase.header.width
local height = ase.header.height
for i, ase_frame in ipairs(ase.header.frames) do for i, ase_frame in ipairs(ase.header.frames) do
for _, chunk in ipairs(ase_frame.chunks) do for chunk_i, chunk in ipairs(ase_frame.chunks) do
local user_data = ase_frame.chunks[chunk_i+1]
if user_data and user_data.type ~= USER_CHUNK then
user_data = nil
end
if chunk.type == CEL_CHUNK then if chunk.type == CEL_CHUNK then
local cel = chunk.data local cel = chunk.data
local buffer = love.data.decompress("data", "zlib", cel.data) local buffer = love.data.decompress("data", "zlib", cel.data)
@ -37,7 +42,7 @@ local function loadAsepriteSprite(filename)
local frame = frames[i] local frame = frames[i]
if not frame then if not frame then
frame = { frame = {
image = love.graphics.newCanvas(sprite.width, sprite.height), image = love.graphics.newCanvas(width, height),
duration = ase_frame.frame_duration / 1000 duration = ase_frame.frame_duration / 1000
} }
frame.image:setFilter("nearest", "nearest") frame.image:setFilter("nearest", "nearest")
@ -61,12 +66,29 @@ local function loadAsepriteSprite(filename)
end end
elseif chunk.type == LAYER_CHUNK then elseif chunk.type == LAYER_CHUNK then
table.insert(layers, chunk.data) table.insert(layers, chunk.data)
elseif chunk.type == SLICE_CHUNK then
local slice_key = chunk.data.keys[1]
table.insert(slices, {
name = chunk.data.name,
x = slice_key.x,
y = slice_key.y,
width = slice_key.width,
height = slice_key.height,
user_data = user_data and user_data.data.text
})
end end
end end
end end
love.graphics.push() love.graphics.push()
local sprite = {
width = width,
height = height,
slices = slices,
variants = {}
}
for _, tag in pairs(tags) do for _, tag in pairs(tags) do
local variant = {} local variant = {}
sprite.variants[tag.name] = variant sprite.variants[tag.name] = variant
@ -76,7 +98,7 @@ local function loadAsepriteSprite(filename)
end end
if not sprite.variants.default then if not sprite.variants.default then
sprite.variants.default = {frames[1]} sprite.variants.default = frames
end end
return sprite return sprite

179
src/data/maps/main-menu.lua Normal file
View File

@ -0,0 +1,179 @@
return {
version = "1.9",
luaversion = "5.1",
tiledversion = "1.9.0",
class = "",
orientation = "orthogonal",
renderorder = "right-down",
width = 16,
height = 9,
tilewidth = 16,
tileheight = 16,
nextlayerid = 5,
nextobjectid = 13,
properties = {},
tilesets = {
{
name = "roguelike-dungeon",
firstgid = 1,
filename = "../tilesets/roguelike-dungeon.tsx",
exportfilename = "../tilesets/roguelike-dungeon.lua"
}
},
layers = {
{
type = "tilelayer",
x = 0,
y = 0,
width = 16,
height = 9,
id = 1,
name = "ground",
class = "",
visible = true,
opacity = 1,
offsetx = 0,
offsety = 0,
parallaxx = 1,
parallaxy = 1,
properties = {},
encoding = "lua",
data = {
68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68
}
},
{
type = "tilelayer",
x = 0,
y = 0,
width = 16,
height = 9,
id = 3,
name = "decorations",
class = "",
visible = true,
opacity = 1,
offsetx = 0,
offsety = 0,
parallaxx = 1,
parallaxy = 1,
properties = {},
encoding = "lua",
data = {
0, 0, 66, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 0,
0, 0, 66, 66, 66, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 66, 66, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 66, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 66, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 66, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 119, 119, 119, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0
}
},
{
type = "objectgroup",
draworder = "topdown",
id = 2,
name = "metadata",
class = "",
visible = true,
opacity = 1,
offsetx = 0,
offsety = 0,
parallaxx = 1,
parallaxy = 1,
properties = {},
objects = {
{
id = 2,
name = "Spawnpoint",
class = "",
shape = "point",
x = 140.167,
y = 90.1667,
width = 0,
height = 0,
rotation = 0,
visible = true,
properties = {}
},
{
id = 6,
name = "title",
class = "",
shape = "rectangle",
x = 128,
y = 16,
width = 96,
height = 48,
rotation = 0,
visible = true,
properties = {
["sprite"] = "title"
}
},
{
id = 7,
name = "Host",
class = "button",
shape = "rectangle",
x = 16,
y = 16,
width = 96,
height = 32,
rotation = 0,
visible = true,
properties = {}
},
{
id = 8,
name = "Join",
class = "button",
shape = "rectangle",
x = 16,
y = 56,
width = 96,
height = 32,
rotation = 0,
visible = true,
properties = {}
},
{
id = 9,
name = "Quit",
class = "button",
shape = "rectangle",
x = 16,
y = 96,
width = 96,
height = 32,
rotation = 0,
visible = true,
properties = {}
},
{
id = 12,
name = "controls",
class = "",
shape = "point",
x = 225,
y = 111.667,
width = 0,
height = 0,
rotation = 0,
visible = true,
properties = {}
}
}
}
}
}

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.9" tiledversion="1.9.0" orientation="orthogonal" renderorder="right-down" width="16" height="9" tilewidth="16" tileheight="16" infinite="0" nextlayerid="5" nextobjectid="13">
<editorsettings>
<export target="main-menu.lua" format="lua"/>
</editorsettings>
<tileset firstgid="1" source="../tilesets/roguelike-dungeon.tsx"/>
<layer id="1" name="ground" width="16" height="9">
<data encoding="csv">
68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68
</data>
</layer>
<layer id="3" name="decorations" width="16" height="9">
<data encoding="csv">
0,0,66,0,66,0,0,0,0,0,0,0,0,96,0,0,
0,0,66,66,66,66,0,0,0,0,0,0,0,0,0,0,
0,0,0,66,66,66,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,66,66,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,66,66,0,
0,0,0,0,0,0,0,0,0,0,0,0,96,0,66,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,119,119,119,0,0,0,0,0,0,
0,0,0,0,0,0,0,119,0,0,0,0,0,0,0,0
</data>
</layer>
<objectgroup id="2" name="metadata">
<object id="2" name="Spawnpoint" x="140.167" y="90.1667">
<point/>
</object>
<object id="6" name="title" x="128" y="16" width="96" height="48">
<properties>
<property name="sprite" value="title"/>
</properties>
</object>
<object id="7" name="Host" class="button" x="16" y="16" width="96" height="32"/>
<object id="8" name="Join" class="button" x="16" y="56" width="96" height="32"/>
<object id="9" name="Quit" class="button" x="16" y="96" width="96" height="32"/>
<object id="12" name="controls" x="225" y="111.667">
<point/>
</object>
</objectgroup>
</map>

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 657 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 B

View File

@ -7,6 +7,7 @@ return {
}}, }},
controllable_player = {filter = {"controllable"}}, controllable_player = {filter = {"controllable"}},
sprite = {filter = {"pos", "sprite"}}, sprite = {filter = {"pos", "sprite"}},
image = {filter = {"pos", "image"}},
bolt = {filter={"pos", "vel", "bolt"}}, bolt = {filter={"pos", "vel", "bolt"}},
collider = {filter={"collider"}}, collider = {filter={"collider"}},
ui_button = {filter={"pos", "size", "text"}} ui_button = {filter={"pos", "size", "text"}}

View File

@ -312,9 +312,10 @@ local function grab_user_data(data)
user_data.flags = read_num(data, DWORD) user_data.flags = read_num(data, DWORD)
if user_data.flags == 1 then if bit.band(user_data.flags, 1) > 0 then
user_data.text = read_string(data) user_data.text = read_string(data)
elseif user_data.flags == 2 then end
if bit.band(user_data.flags, 2) > 0 then
user_data.colors = read_num(data, BYTE * 4) user_data.colors = read_num(data, BYTE * 4)
end end
@ -342,6 +343,8 @@ local function grab_chunk(data)
chunk.data = grab_slice(data) chunk.data = grab_slice(data)
elseif chunk.type == 0x2020 then elseif chunk.type == 0x2020 then
chunk.data = grab_user_data(data) chunk.data = grab_user_data(data)
else
error(("Uknown chunk type: 0x%x"):format(chunk.type))
end end
return chunk return chunk

View File

@ -22,6 +22,8 @@ local lg = require(cwd .. "graphics")
local Map = {} local Map = {}
Map.__index = Map Map.__index = Map
local DRAW_OBJECT_LAYERS = false
local function new(map, plugins, ox, oy) local function new(map, plugins, ox, oy)
local dir = "" local dir = ""
@ -895,6 +897,8 @@ end
--- Default draw function for Object Layers --- Default draw function for Object Layers
-- @param layer The Object Layer to draw -- @param layer The Object Layer to draw
function Map:drawObjectLayer(layer) function Map:drawObjectLayer(layer)
if not DRAW_OBJECT_LAYERS then return end
if type(layer) == "string" or type(layer) == "number" then if type(layer) == "string" or type(layer) == "number" then
layer = self.layers[layer] layer = self.layers[layer]
end end
@ -954,7 +958,7 @@ function Map:drawObjectLayer(layer)
elseif object.shape == "polyline" then elseif object.shape == "polyline" then
drawShape(object.polyline, "polyline") drawShape(object.polyline, "polyline")
elseif object.shape == "point" then elseif object.shape == "point" then
-- lg.points(object.x, object.y) lg.points(object.x, object.y)
end end
end end
end end

View File

@ -1,6 +1,7 @@
local Gamestate = require("lib.hump.gamestate") local Gamestate = require("lib.hump.gamestate")
local binser = require("lib.binser") local binser = require("lib.binser")
local Vec = require("lib.brinevector") local Vec = require("lib.brinevector")
pprint = require("lib.pprint")
binser.registerStruct("brinevector", binser.registerStruct("brinevector",
function(v) return v.x, v.y end, function(v) return v.x, v.y end,

View File

@ -16,10 +16,19 @@ local function splitat(str, char)
return str:sub(1, index-1), str:sub(index+1) return str:sub(1, index-1), str:sub(index+1)
end end
local function findByName(list, name)
for _, o in ipairs(list) do
if o.name:lower() == name:lower() then
return o
end
end
end
function MainMenu:init() function MainMenu:init()
local systems = { local systems = {
require("systems.physics"), require("systems.physics"),
require("systems.bolt"), require("systems.bolt"),
require("systems.map"),
require("systems.ui"), require("systems.ui"),
require("systems.player"), require("systems.player"),
require("systems.sprite"), require("systems.sprite"),
@ -31,7 +40,10 @@ function MainMenu:init()
self.ecs = nata.new{ self.ecs = nata.new{
available_groups = require("groups"), available_groups = require("groups"),
systems = systems systems = systems,
data = {
map = "data/maps/main-menu.lua"
}
} }
self.host_socket = enet.host_create("*:0") self.host_socket = enet.host_create("*:0")
@ -40,18 +52,21 @@ function MainMenu:init()
self.hosting = false self.hosting = false
self.connecting = false self.connecting = false
local map = self.ecs:getSystem(require("systems.map")).map
local pprint = require("lib.pprint")
local metadata_layer = findByName(map.layers, "metadata")
do do
local spawnpoint = findByName(metadata_layer.objects, "spawnpoint")
local PlayerSystem = self.ecs:getSystem(require("systems.player")) local PlayerSystem = self.ecs:getSystem(require("systems.player"))
local player = PlayerSystem:spawnPlayer(Vec(192, 48)) local player = PlayerSystem:spawnPlayer(Vec(spawnpoint.x, spawnpoint.y))
player.sprite.flip = true player.sprite.flip = true
player.controllable = true player.controllable = true
end end
do do
local tileSize = 16 self.screenWidth = map.width * map.tilewidth
local screenW, screenH = love.graphics.getDimensions() self.screenHeight = map.height * map.tileheight
self.screenWidth = 16 * tileSize
self.screenHeight = 16 * screenH/screenW * tileSize
local border = 2.5 local border = 2.5
local w = self.screenWidth local w = self.screenWidth
@ -62,6 +77,38 @@ function MainMenu:init()
self.ecs:queue{ collider = {0, h-border, w, h} } self.ecs:queue{ collider = {0, h-border, w, h} }
end end
do
local controls_obj = findByName(metadata_layer.objects, "controls")
local pos = Vec(controls_obj.x, controls_obj.y)
local prompts = data.ui.prompts.dark
self.ecs:queue{
pos = pos + Vec(0, -16),
image = prompts["w"],
collider = {-8, -8, 8, 8}
}
self.ecs:queue{
pos = pos,
image = prompts["a"],
collider = {-8, -8, 8, 8}
}
self.ecs:queue{
pos = pos + Vec(-16, 0),
image = prompts["s"],
collider = {-8, -8, 8, 8}
}
self.ecs:queue{
pos = pos + Vec(16, 0),
image = prompts["d"],
collider = {-8, -8, 8, 8}
}
self.ecs:queue{
pos = pos + Vec(0, 16),
image = prompts["spacebar"],
collider = {-24, -8, 24, 8}
}
end
do do
local host_btn = self.ecs:queue{ local host_btn = self.ecs:queue{
pos = Vec(16, 16), pos = Vec(16, 16),
@ -113,19 +160,6 @@ function MainMenu:draw()
ScreenScaler:start(self.screenWidth, self.screenHeight) ScreenScaler:start(self.screenWidth, self.screenHeight)
self.ecs:emit("draw") self.ecs:emit("draw")
ScreenScaler:finish() ScreenScaler:finish()
-- self.ui:textbox(self.addr_textbox, w/2-250, h/2-30, 280, 60)
-- if self.ui:button("Copy my address", w/2-50, h/2-100, 300, 60) then
-- local _, port = splitat(self.host_socket:get_socket_address(), ":")
-- local address = getPublicIP() .. ":" .. port
-- love.system.setClipboardText(address)
-- end
-- if self.ui:button("Connect", w/2+50, h/2-30, 200, 60) then
-- self.connecting = true
-- self.host_socket:connect(self.addr_textbox.text)
-- end
-- self.ui:postDraw()
end end
return MainMenu return MainMenu

View File

@ -25,14 +25,15 @@ function MainState:enter(_, host_socket)
available_groups = require("groups"), available_groups = require("groups"),
systems = systems, systems = systems,
data = { data = {
host_socket = host_socket host_socket = host_socket,
map = "data/maps/playground.lua"
} }
} }
self.downscaled_canvas = nil self.downscaled_canvas = nil
self:refreshDownscaledCanvas() self:refreshScaler()
self.ecs:on("onMapSwitch", function(map) self.ecs:on("onMapSwitch", function(map)
self:refreshDownscaledCanvas(map) self:refreshScaler(map)
end) end)
@ -42,14 +43,10 @@ function MainState:enter(_, host_socket)
player.controllable = true player.controllable = true
end end
function MainState:refreshDownscaledCanvas(map) function MainState:refreshScaler(map)
if not map then if not map then
local Map = self.ecs:getSystem(require("systems.map")) local Map = self.ecs:getSystem(require("systems.map"))
map = Map.map map = Map.map
if not map then
self.downscaled_canvas = nil
return
end
end end
self.screenWidth = map.width * map.tilewidth self.screenWidth = map.width * map.tilewidth

View File

@ -1,27 +1,54 @@
local Map = {} local Map = {}
local sti = require("lib.sti") local sti = require("lib.sti")
local Vector = require("lib.brinevector") local Vec = require("lib.brinevector")
function Map:init() function Map:init()
self.map = sti("data/maps/playground.lua", { "bump" }) if self.pool.data.map then
self.pool:emit("onMapSwitch", self.map) self.map = sti(self.pool.data.map, { "bump" })
local spriteSystem = self.pool:getSystem(require("systems.sprite"))
if spriteSystem then
for _, layer in ipairs(self.map.layers) do
if layer.type == "objectgroup" then
for _, obj in ipairs(layer.objects) do
local props = obj.properties
if props.sprite then
local x = obj.x + obj.width/2
local y = obj.y + obj.height/2
self.pool:queue{
sprite = { name = props.sprite },
pos = Vec(x, y)
}
end
end
end
end
end
self.pool:emit("onMapSwitch", self.map)
end
end end
function Map:update(dt) function Map:update(dt)
self.map:update(dt) if self.map then
self.map:update(dt)
end
end end
function Map:listSpawnpoints() function Map:listSpawnpoints()
local points = {} local points = {}
for _, object in ipairs(self.map.layers.spawnpoints.objects) do for _, object in ipairs(self.map.layers.spawnpoints.objects) do
table.insert(points, Vector(object.x, object.y)) table.insert(points, Vec(object.x, object.y))
end end
return points return points
end end
function Map:draw() function Map:draw()
love.graphics.setColor(1, 1, 1) if self.map then
self.map:draw() love.graphics.setColor(1, 1, 1)
self.map:draw()
end
end end
return Map return Map

View File

@ -1,14 +1,31 @@
local data = require("data") local data = require("data")
local pprint = require("lib.pprint") local pprint = require("lib.pprint")
local Vec = require("lib.brinevector")
local Sprite = {} local Sprite = {}
Sprite.required_groups = {"sprite"} Sprite.required_groups = {"sprite", "image"}
function Sprite:addToGroup(group, e) function Sprite:addToGroup(group, e)
if group ~= "sprite" then return end if group == "sprite" then
local sprite = data.sprites[e.sprite.name]
assert(sprite, ("Attempt to draw unknown sprite: %s"):format(e.sprite.name))
local sprite = data.sprites[e.sprite.name] for _, slice in ipairs(sprite.slices) do
assert(sprite, ("Attempt to draw unknown sprite: %s"):format(e.sprite.name)) if slice.user_data and slice.user_data:find("collider") then
self.pool:queue{
pos = e.pos - Vec(sprite.width, sprite.height)/2,
collider = {
slice.x,
slice.y,
slice.x + slice.width,
slice.y + slice.height
}
}
end
end
elseif group == "image" then
assert(e.image:typeOf("Drawable"), ("Expected sprite to be a drawable or aseprite sprite, got: %s"):format(e.image))
end
end end
function Sprite:update(dt) function Sprite:update(dt)
@ -40,9 +57,10 @@ function Sprite:draw()
if not e.hidden then if not e.hidden then
local variant = sprite.variants[e.sprite.variant or "default"] local variant = sprite.variants[e.sprite.variant or "default"]
if variant and e.sprite.frame then local frame_idx = e.sprite.frame or 1
if variant and frame_idx then
local rotation = nil local rotation = nil
local frame = variant[e.sprite.frame] local frame = variant[frame_idx]
if not frame then if not frame then
frame = variant[1] frame = variant[1]
end end
@ -66,6 +84,20 @@ function Sprite:draw()
end end
end end
end end
for _, e in ipairs(self.pool.groups.image.entities) do
if not e.hidden then
local width, height = e.image:getDimensions()
love.graphics.draw(
e.image,
e.pos.x,
e.pos.y,
0,
1, 1,
width/2, height/2
)
end
end
end end
return Sprite return Sprite