add collisions using "bump"
This commit is contained in:
parent
467c450349
commit
6fdb954b36
@ -16,7 +16,8 @@ return {
|
||||
{
|
||||
name = "test",
|
||||
firstgid = 1,
|
||||
filename = "../tilesets/test.tsx"
|
||||
filename = "../tilesets/test.tsx",
|
||||
exportfilename = "../tilesets/test.lua"
|
||||
}
|
||||
},
|
||||
layers = {
|
||||
|
@ -27,5 +27,12 @@ return {
|
||||
properties = {},
|
||||
wangsets = {},
|
||||
tilecount = 36,
|
||||
tiles = {}
|
||||
tiles = {
|
||||
{
|
||||
id = 0,
|
||||
properties = {
|
||||
["collidable"] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,12 @@
|
||||
<?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">
|
||||
<editorsettings>
|
||||
<export target="test.lua" format="lua"/>
|
||||
</editorsettings>
|
||||
<image source="test.png" width="96" height="96"/>
|
||||
<tile id="0">
|
||||
<properties>
|
||||
<property name="collidable" type="bool" value="true"/>
|
||||
</properties>
|
||||
</tile>
|
||||
</tileset>
|
||||
|
@ -6,6 +6,30 @@
|
||||
|
||||
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 {
|
||||
bump_LICENSE = "MIT/X11",
|
||||
bump_URL = "https://github.com/karai17/Simple-Tiled-Implementation",
|
||||
@ -18,44 +42,24 @@ return {
|
||||
bump_init = function(map, world)
|
||||
local collidables = {}
|
||||
|
||||
for _, tileset in ipairs(map.tilesets) do
|
||||
for _, tile in ipairs(tileset.tiles) do
|
||||
local gid = tileset.firstgid + tile.id
|
||||
for _, gid in ipairs(getKeys(map.tileInstances)) do
|
||||
local id = bit.band(gid, GID_MASK)
|
||||
local tile = findTileFromTilesets(map.tilesets, id)
|
||||
|
||||
if map.tileInstances[gid] then
|
||||
for _, instance in ipairs(map.tileInstances[gid]) do
|
||||
-- Every object in every instance of a tile
|
||||
if tile.objectGroup then
|
||||
for _, object in ipairs(tile.objectGroup.objects) do
|
||||
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
|
||||
for _, instance in ipairs(map.tileInstances[gid]) do
|
||||
-- Every object in every instance of a tile
|
||||
if tile.objectGroup then
|
||||
for _, object in ipairs(tile.objectGroup.objects) do
|
||||
if object.properties.collidable == true then
|
||||
local t = {
|
||||
x = instance.x + map.offsetx,
|
||||
y = instance.y + map.offsety,
|
||||
width = map.tilewidth,
|
||||
height = map.tileheight,
|
||||
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,
|
||||
type = tile.type,
|
||||
properties = tile.properties
|
||||
properties = object.properties
|
||||
}
|
||||
|
||||
world:add(t, t.x, t.y, t.width, t.height)
|
||||
@ -63,6 +67,39 @@ return {
|
||||
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
|
||||
|
||||
|
@ -13,7 +13,8 @@ function MainState:enter(_, host_socket)
|
||||
}},
|
||||
controllable_player = {filter = {"controllable"}},
|
||||
sprite = {filter = {"sprite"}},
|
||||
bolt = {filter={"pos", "vel", "bolt"}}
|
||||
bolt = {filter={"pos", "vel", "bolt"}},
|
||||
collider = {filter={"pos", "collider"}}
|
||||
}
|
||||
|
||||
local systems = {
|
||||
@ -21,9 +22,13 @@ function MainState:enter(_, host_socket)
|
||||
require("systems.map"),
|
||||
require("systems.player"),
|
||||
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
|
||||
table.insert(systems, require("systems.multiplayer"))
|
||||
end
|
||||
@ -106,6 +111,7 @@ function MainState:draw()
|
||||
-- Draw UI on top
|
||||
local w, h = self.downscaled_canvas:getDimensions()
|
||||
ScreenScaler:start(1000, h/w * 1000)
|
||||
love.graphics.setColor(1, 1, 1)
|
||||
love.graphics.print("Hello World!")
|
||||
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 DEBUG_GRID = true
|
||||
local DEBUG_GRID_COLOR = rgb(30, 30, 30)
|
||||
local sti = require("lib.sti")
|
||||
|
||||
function Map:init()
|
||||
self.map = sti("data/maps/test.lua")
|
||||
self.map = sti("data/maps/test.lua", { "bump" })
|
||||
self.pool:emit("onMapSwitch", self.map)
|
||||
end
|
||||
|
||||
@ -15,16 +11,6 @@ function Map:update(dt)
|
||||
end
|
||||
|
||||
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)
|
||||
self.map:draw()
|
||||
end
|
||||
|
@ -1,4 +1,53 @@
|
||||
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)
|
||||
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
|
||||
end
|
||||
|
||||
if self.pool.groups.collider.hasEntity[e] then
|
||||
self:resolveCollisions(e, dt)
|
||||
end
|
||||
|
||||
e.pos = e.pos + e.vel * dt
|
||||
end
|
||||
end
|
||||
|
@ -115,7 +115,8 @@ function Player:tryShootinBolt(player)
|
||||
vel = player.aim_dir * player.bolt_speed,
|
||||
friction = player.bolt_friction,
|
||||
bolt = true,
|
||||
sprite = {}
|
||||
sprite = {},
|
||||
collider = {-4, -4, 4, 4}
|
||||
}
|
||||
end
|
||||
end
|
||||
@ -136,7 +137,8 @@ function Player:spawnPlayer()
|
||||
bolt_count = 1,
|
||||
bolt_speed = 500,
|
||||
bolt_cooldown = 0.2,
|
||||
bolt_friction = 0.9
|
||||
bolt_friction = 0.9,
|
||||
collider = {-6, -6, 6, 6}
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -44,9 +44,8 @@ function ScreenScaler:getMousePosition()
|
||||
end
|
||||
|
||||
function ScreenScaler:getDimensions()
|
||||
if self.scale then
|
||||
local w, h = love.graphics.getDimensions()
|
||||
return w*self.scale, h*self.scale
|
||||
if self.current_width and self.current_height then
|
||||
return self.current_width, self.current_height
|
||||
else
|
||||
return love.graphics.getDimensions()
|
||||
end
|
||||
@ -57,6 +56,8 @@ function ScreenScaler:overrideScaling(width, height)
|
||||
self.scale = math.min(sw / width, sh / height)
|
||||
self.offset_x = (sw - width * self.scale)/2
|
||||
self.offset_y = (sh - height * self.scale)/2
|
||||
self.current_width = width
|
||||
self.current_height = height
|
||||
end
|
||||
|
||||
function ScreenScaler:start(p1, p2)
|
||||
@ -72,6 +73,8 @@ function ScreenScaler:start(p1, p2)
|
||||
end
|
||||
|
||||
local sw, sh = love.graphics.getDimensions()
|
||||
self.current_width = width
|
||||
self.current_height = height
|
||||
self.scale = math.min(sw / width, sh / height)
|
||||
self.offset_x = (sw - width * self.scale)/2
|
||||
self.offset_y = (sh - height * self.scale)/2
|
||||
@ -90,6 +93,7 @@ function ScreenScaler:finish()
|
||||
love.graphics.pop()
|
||||
if self.canvas then
|
||||
love.graphics.setCanvas()
|
||||
love.graphics.setColor(1, 1, 1)
|
||||
love.graphics.draw(self.canvas, self.offset_x, self.offset_y, 0, self.scale)
|
||||
else
|
||||
self:hideBorders()
|
||||
|
@ -2,7 +2,7 @@ local Sprite = {}
|
||||
|
||||
function Sprite:draw()
|
||||
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)
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user