add collisions using "bump"
This commit is contained in:
parent
467c450349
commit
6fdb954b36
@ -16,7 +16,8 @@ return {
|
|||||||
{
|
{
|
||||||
name = "test",
|
name = "test",
|
||||||
firstgid = 1,
|
firstgid = 1,
|
||||||
filename = "../tilesets/test.tsx"
|
filename = "../tilesets/test.tsx",
|
||||||
|
exportfilename = "../tilesets/test.lua"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
layers = {
|
layers = {
|
||||||
|
@ -27,5 +27,12 @@ return {
|
|||||||
properties = {},
|
properties = {},
|
||||||
wangsets = {},
|
wangsets = {},
|
||||||
tilecount = 36,
|
tilecount = 36,
|
||||||
tiles = {}
|
tiles = {
|
||||||
|
{
|
||||||
|
id = 0,
|
||||||
|
properties = {
|
||||||
|
["collidable"] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,12 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<tileset version="1.9" tiledversion="1.9.0" name="test" tilewidth="16" tileheight="16" tilecount="36" columns="6">
|
<tileset version="1.9" tiledversion="1.9.0" name="test" tilewidth="16" tileheight="16" tilecount="36" columns="6">
|
||||||
|
<editorsettings>
|
||||||
|
<export target="test.lua" format="lua"/>
|
||||||
|
</editorsettings>
|
||||||
<image source="test.png" width="96" height="96"/>
|
<image source="test.png" width="96" height="96"/>
|
||||||
|
<tile id="0">
|
||||||
|
<properties>
|
||||||
|
<property name="collidable" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
</tileset>
|
</tileset>
|
||||||
|
@ -6,6 +6,30 @@
|
|||||||
|
|
||||||
local lg = require((...):gsub('plugins.bump', 'graphics'))
|
local lg = require((...):gsub('plugins.bump', 'graphics'))
|
||||||
|
|
||||||
|
local function getKeys(t)
|
||||||
|
local keys = {}
|
||||||
|
for k in pairs(t) do
|
||||||
|
table.insert(keys, k)
|
||||||
|
end
|
||||||
|
return keys
|
||||||
|
end
|
||||||
|
|
||||||
|
-- The highest 4 bits in 32bit tile ids are used for marking if that tile is
|
||||||
|
-- flipped, so to get the real id, you first need to remove those bits using
|
||||||
|
-- this mask.
|
||||||
|
local bit = require("bit")
|
||||||
|
local GID_MASK = bit.bnot(bit.lshift(15, 28))
|
||||||
|
|
||||||
|
local function findTileFromTilesets(tilesets, gid)
|
||||||
|
for _, tileset in ipairs(tilesets) do
|
||||||
|
for _, tile in ipairs(tileset.tiles) do
|
||||||
|
if tileset.firstgid + tile.id == gid then
|
||||||
|
return tile
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
bump_LICENSE = "MIT/X11",
|
bump_LICENSE = "MIT/X11",
|
||||||
bump_URL = "https://github.com/karai17/Simple-Tiled-Implementation",
|
bump_URL = "https://github.com/karai17/Simple-Tiled-Implementation",
|
||||||
@ -18,44 +42,24 @@ return {
|
|||||||
bump_init = function(map, world)
|
bump_init = function(map, world)
|
||||||
local collidables = {}
|
local collidables = {}
|
||||||
|
|
||||||
for _, tileset in ipairs(map.tilesets) do
|
for _, gid in ipairs(getKeys(map.tileInstances)) do
|
||||||
for _, tile in ipairs(tileset.tiles) do
|
local id = bit.band(gid, GID_MASK)
|
||||||
local gid = tileset.firstgid + tile.id
|
local tile = findTileFromTilesets(map.tilesets, id)
|
||||||
|
|
||||||
if map.tileInstances[gid] then
|
for _, instance in ipairs(map.tileInstances[gid]) do
|
||||||
for _, instance in ipairs(map.tileInstances[gid]) do
|
-- Every object in every instance of a tile
|
||||||
-- Every object in every instance of a tile
|
if tile.objectGroup then
|
||||||
if tile.objectGroup then
|
for _, object in ipairs(tile.objectGroup.objects) do
|
||||||
for _, object in ipairs(tile.objectGroup.objects) do
|
if object.properties.collidable == true then
|
||||||
if object.properties.collidable == true then
|
|
||||||
local t = {
|
|
||||||
name = object.name,
|
|
||||||
type = object.type,
|
|
||||||
x = instance.x + map.offsetx + object.x,
|
|
||||||
y = instance.y + map.offsety + object.y,
|
|
||||||
width = object.width,
|
|
||||||
height = object.height,
|
|
||||||
layer = instance.layer,
|
|
||||||
properties = object.properties
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
world:add(t, t.x, t.y, t.width, t.height)
|
|
||||||
table.insert(collidables, t)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Every instance of a tile
|
|
||||||
if tile.properties and tile.properties.collidable == true then
|
|
||||||
local t = {
|
local t = {
|
||||||
x = instance.x + map.offsetx,
|
name = object.name,
|
||||||
y = instance.y + map.offsety,
|
type = object.type,
|
||||||
width = map.tilewidth,
|
x = instance.x + map.offsetx + object.x,
|
||||||
height = map.tileheight,
|
y = instance.y + map.offsety + object.y,
|
||||||
|
width = object.width,
|
||||||
|
height = object.height,
|
||||||
layer = instance.layer,
|
layer = instance.layer,
|
||||||
type = tile.type,
|
properties = object.properties
|
||||||
properties = tile.properties
|
|
||||||
}
|
}
|
||||||
|
|
||||||
world:add(t, t.x, t.y, t.width, t.height)
|
world:add(t, t.x, t.y, t.width, t.height)
|
||||||
@ -63,6 +67,39 @@ return {
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Every instance of a tile
|
||||||
|
if tile.properties and tile.properties.collidable == true then
|
||||||
|
local tileProperties = map.tiles[gid]
|
||||||
|
local x = instance.x + map.offsetx
|
||||||
|
local y = instance.y + map.offsety
|
||||||
|
local sx = tileProperties.sx
|
||||||
|
local sy = tileProperties.sy
|
||||||
|
|
||||||
|
-- Width and height can only be positive in bump, to get around this
|
||||||
|
-- For negative scaling just move the position back instead
|
||||||
|
if sx < 1 then
|
||||||
|
sx = -sx
|
||||||
|
x = x - map.tilewidth * sx
|
||||||
|
end
|
||||||
|
if sy < 1 then
|
||||||
|
sy = -sy
|
||||||
|
x = x - map.tileheight * sy
|
||||||
|
end
|
||||||
|
|
||||||
|
local t = {
|
||||||
|
x = x,
|
||||||
|
y = y,
|
||||||
|
width = map.tilewidth * sx,
|
||||||
|
height = map.tileheight * sy,
|
||||||
|
layer = instance.layer,
|
||||||
|
type = tile.type,
|
||||||
|
properties = tile.properties
|
||||||
|
}
|
||||||
|
|
||||||
|
world:add(t, t.x, t.y, t.width, t.height)
|
||||||
|
table.insert(collidables, t)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -13,7 +13,8 @@ function MainState:enter(_, host_socket)
|
|||||||
}},
|
}},
|
||||||
controllable_player = {filter = {"controllable"}},
|
controllable_player = {filter = {"controllable"}},
|
||||||
sprite = {filter = {"sprite"}},
|
sprite = {filter = {"sprite"}},
|
||||||
bolt = {filter={"pos", "vel", "bolt"}}
|
bolt = {filter={"pos", "vel", "bolt"}},
|
||||||
|
collider = {filter={"pos", "collider"}}
|
||||||
}
|
}
|
||||||
|
|
||||||
local systems = {
|
local systems = {
|
||||||
@ -21,9 +22,13 @@ function MainState:enter(_, host_socket)
|
|||||||
require("systems.map"),
|
require("systems.map"),
|
||||||
require("systems.player"),
|
require("systems.player"),
|
||||||
require("systems.sprite"),
|
require("systems.sprite"),
|
||||||
require("systems.screen-scaler"),
|
require("systems.screen-scaler")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if not love.filesystem.isFused() then
|
||||||
|
table.insert(systems, require("systems.debug"))
|
||||||
|
end
|
||||||
|
|
||||||
if host_socket then
|
if host_socket then
|
||||||
table.insert(systems, require("systems.multiplayer"))
|
table.insert(systems, require("systems.multiplayer"))
|
||||||
end
|
end
|
||||||
@ -106,6 +111,7 @@ function MainState:draw()
|
|||||||
-- Draw UI on top
|
-- Draw UI on top
|
||||||
local w, h = self.downscaled_canvas:getDimensions()
|
local w, h = self.downscaled_canvas:getDimensions()
|
||||||
ScreenScaler:start(1000, h/w * 1000)
|
ScreenScaler:start(1000, h/w * 1000)
|
||||||
|
love.graphics.setColor(1, 1, 1)
|
||||||
love.graphics.print("Hello World!")
|
love.graphics.print("Hello World!")
|
||||||
ScreenScaler:finish()
|
ScreenScaler:finish()
|
||||||
|
|
||||||
|
45
src/systems/debug.lua
Normal file
45
src/systems/debug.lua
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
local Debug = {}
|
||||||
|
local rgb = require("helpers.rgb")
|
||||||
|
|
||||||
|
local DRAW_GRID = false
|
||||||
|
local GRID_COLOR = rgb(30, 30, 30)
|
||||||
|
|
||||||
|
local DRAW_COLLIDERS = true
|
||||||
|
local COLLIDER_COLOR = rgb(200, 20, 200)
|
||||||
|
|
||||||
|
function Debug:drawColliders()
|
||||||
|
local physics = self.pool:getSystem(require("systems.physics"))
|
||||||
|
love.graphics.setColor(COLLIDER_COLOR)
|
||||||
|
|
||||||
|
local bump = physics.bump
|
||||||
|
local items = bump:getItems()
|
||||||
|
for _, item in ipairs(items) do
|
||||||
|
love.graphics.rectangle("line", bump:getRect(item))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Debug:drawGrid()
|
||||||
|
local map = self.pool:getSystem(require("systems.map"))
|
||||||
|
if not map.map then return end
|
||||||
|
|
||||||
|
local scaler = self.pool:getSystem(require("systems.screen-scaler"))
|
||||||
|
local w, h = scaler:getDimensions()
|
||||||
|
love.graphics.setColor(GRID_COLOR)
|
||||||
|
for x=0, w, map.map.tilewidth do
|
||||||
|
love.graphics.line(x, 0, x, h)
|
||||||
|
end
|
||||||
|
for y=0, h, map.map.tileheight do
|
||||||
|
love.graphics.line(0, y, w, y)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Debug:draw()
|
||||||
|
if DRAW_GRID then
|
||||||
|
self:drawGrid()
|
||||||
|
end
|
||||||
|
if DRAW_COLLIDERS then
|
||||||
|
self:drawColliders()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return Debug
|
@ -1,12 +1,8 @@
|
|||||||
local rgb = require("helpers.rgb")
|
|
||||||
local sti = require("lib.sti")
|
|
||||||
local Map = {}
|
local Map = {}
|
||||||
|
local sti = require("lib.sti")
|
||||||
local DEBUG_GRID = true
|
|
||||||
local DEBUG_GRID_COLOR = rgb(30, 30, 30)
|
|
||||||
|
|
||||||
function Map:init()
|
function Map:init()
|
||||||
self.map = sti("data/maps/test.lua")
|
self.map = sti("data/maps/test.lua", { "bump" })
|
||||||
self.pool:emit("onMapSwitch", self.map)
|
self.pool:emit("onMapSwitch", self.map)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -15,16 +11,6 @@ function Map:update(dt)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Map:draw()
|
function Map:draw()
|
||||||
if DEBUG_GRID and self.map then
|
|
||||||
local w, h = love.graphics.getDimensions()
|
|
||||||
love.graphics.setColor(DEBUG_GRID_COLOR)
|
|
||||||
for x=0, w, self.map.tilewidth do
|
|
||||||
love.graphics.line(x, 0, x, h)
|
|
||||||
end
|
|
||||||
for y=0, h, self.map.tileheight do
|
|
||||||
love.graphics.line(0, y, w, y)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
love.graphics.setColor(1, 1, 1)
|
love.graphics.setColor(1, 1, 1)
|
||||||
self.map:draw()
|
self.map:draw()
|
||||||
end
|
end
|
||||||
|
@ -1,4 +1,53 @@
|
|||||||
local Physics = {}
|
local Physics = {}
|
||||||
|
local bump = require("lib.bump")
|
||||||
|
local Vec = require("lib.brinevector")
|
||||||
|
|
||||||
|
-- TODO: Tweak bump world `cellSize` at runtime,
|
||||||
|
-- when the map switches
|
||||||
|
|
||||||
|
function Physics:init()
|
||||||
|
self.bump = bump.newWorld()
|
||||||
|
end
|
||||||
|
|
||||||
|
function Physics:onMapSwitch(map)
|
||||||
|
map:bump_init(self.bump)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function getColliderBounds(e)
|
||||||
|
local x = e.pos.x + e.collider[1]
|
||||||
|
local y = e.pos.y + e.collider[2]
|
||||||
|
local w = math.abs(e.collider[3] - e.collider[1])
|
||||||
|
local h = math.abs(e.collider[4] - e.collider[2])
|
||||||
|
return x, y, w, h
|
||||||
|
end
|
||||||
|
|
||||||
|
function Physics:addToGroup(group, e)
|
||||||
|
if group == "collider" then
|
||||||
|
self.bump:add(e, getColliderBounds(e))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Physics:removeFromGroup(group, e)
|
||||||
|
if group == "collider" then
|
||||||
|
self.bump:remove(e)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function collisionFilter(entity, other)
|
||||||
|
if entity.vel or other.vel then
|
||||||
|
return "slide"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Physics:resolveCollisions(e, dt)
|
||||||
|
local targetPos = e.pos + e.vel * dt
|
||||||
|
local ox = e.collider[1]
|
||||||
|
local oy = e.collider[2]
|
||||||
|
local x, y = self.bump:move(e, targetPos.x+ox, targetPos.y+oy, collisionFilter)
|
||||||
|
|
||||||
|
local step = Vec(x-ox, y-oy) - e.pos
|
||||||
|
e.vel = step / dt
|
||||||
|
end
|
||||||
|
|
||||||
function Physics:update(dt)
|
function Physics:update(dt)
|
||||||
for _, e in ipairs(self.pool.groups.physical.entities) do
|
for _, e in ipairs(self.pool.groups.physical.entities) do
|
||||||
@ -9,6 +58,10 @@ function Physics:update(dt)
|
|||||||
e.vel = e.vel * (1 - math.min(e.friction, 1)) ^ dt
|
e.vel = e.vel * (1 - math.min(e.friction, 1)) ^ dt
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if self.pool.groups.collider.hasEntity[e] then
|
||||||
|
self:resolveCollisions(e, dt)
|
||||||
|
end
|
||||||
|
|
||||||
e.pos = e.pos + e.vel * dt
|
e.pos = e.pos + e.vel * dt
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -115,7 +115,8 @@ function Player:tryShootinBolt(player)
|
|||||||
vel = player.aim_dir * player.bolt_speed,
|
vel = player.aim_dir * player.bolt_speed,
|
||||||
friction = player.bolt_friction,
|
friction = player.bolt_friction,
|
||||||
bolt = true,
|
bolt = true,
|
||||||
sprite = {}
|
sprite = {},
|
||||||
|
collider = {-4, -4, 4, 4}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -136,7 +137,8 @@ function Player:spawnPlayer()
|
|||||||
bolt_count = 1,
|
bolt_count = 1,
|
||||||
bolt_speed = 500,
|
bolt_speed = 500,
|
||||||
bolt_cooldown = 0.2,
|
bolt_cooldown = 0.2,
|
||||||
bolt_friction = 0.9
|
bolt_friction = 0.9,
|
||||||
|
collider = {-6, -6, 6, 6}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -44,9 +44,8 @@ function ScreenScaler:getMousePosition()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function ScreenScaler:getDimensions()
|
function ScreenScaler:getDimensions()
|
||||||
if self.scale then
|
if self.current_width and self.current_height then
|
||||||
local w, h = love.graphics.getDimensions()
|
return self.current_width, self.current_height
|
||||||
return w*self.scale, h*self.scale
|
|
||||||
else
|
else
|
||||||
return love.graphics.getDimensions()
|
return love.graphics.getDimensions()
|
||||||
end
|
end
|
||||||
@ -57,6 +56,8 @@ function ScreenScaler:overrideScaling(width, height)
|
|||||||
self.scale = math.min(sw / width, sh / height)
|
self.scale = math.min(sw / width, sh / height)
|
||||||
self.offset_x = (sw - width * self.scale)/2
|
self.offset_x = (sw - width * self.scale)/2
|
||||||
self.offset_y = (sh - height * self.scale)/2
|
self.offset_y = (sh - height * self.scale)/2
|
||||||
|
self.current_width = width
|
||||||
|
self.current_height = height
|
||||||
end
|
end
|
||||||
|
|
||||||
function ScreenScaler:start(p1, p2)
|
function ScreenScaler:start(p1, p2)
|
||||||
@ -72,6 +73,8 @@ function ScreenScaler:start(p1, p2)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local sw, sh = love.graphics.getDimensions()
|
local sw, sh = love.graphics.getDimensions()
|
||||||
|
self.current_width = width
|
||||||
|
self.current_height = height
|
||||||
self.scale = math.min(sw / width, sh / height)
|
self.scale = math.min(sw / width, sh / height)
|
||||||
self.offset_x = (sw - width * self.scale)/2
|
self.offset_x = (sw - width * self.scale)/2
|
||||||
self.offset_y = (sh - height * self.scale)/2
|
self.offset_y = (sh - height * self.scale)/2
|
||||||
@ -90,6 +93,7 @@ function ScreenScaler:finish()
|
|||||||
love.graphics.pop()
|
love.graphics.pop()
|
||||||
if self.canvas then
|
if self.canvas then
|
||||||
love.graphics.setCanvas()
|
love.graphics.setCanvas()
|
||||||
|
love.graphics.setColor(1, 1, 1)
|
||||||
love.graphics.draw(self.canvas, self.offset_x, self.offset_y, 0, self.scale)
|
love.graphics.draw(self.canvas, self.offset_x, self.offset_y, 0, self.scale)
|
||||||
else
|
else
|
||||||
self:hideBorders()
|
self:hideBorders()
|
||||||
|
@ -2,7 +2,7 @@ local Sprite = {}
|
|||||||
|
|
||||||
function Sprite:draw()
|
function Sprite:draw()
|
||||||
for _, e in ipairs(self.pool.groups.sprite.entities) do
|
for _, e in ipairs(self.pool.groups.sprite.entities) do
|
||||||
love.graphics.setColor(1, 1, 1)
|
love.graphics.setColor(1, 1, 1)
|
||||||
love.graphics.circle("fill", e.pos.x, e.pos.y, 10)
|
love.graphics.circle("fill", e.pos.x, e.pos.y, 10)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user