1
0

add collisions using "bump"

This commit is contained in:
Rokas Puzonas 2022-07-12 15:01:49 +00:00
parent 467c450349
commit 6fdb954b36
11 changed files with 210 additions and 61 deletions

View File

@ -16,7 +16,8 @@ return {
{
name = "test",
firstgid = 1,
filename = "../tilesets/test.tsx"
filename = "../tilesets/test.tsx",
exportfilename = "../tilesets/test.lua"
}
},
layers = {

View File

@ -27,5 +27,12 @@ return {
properties = {},
wangsets = {},
tilecount = 36,
tiles = {}
tiles = {
{
id = 0,
properties = {
["collidable"] = true
}
}
}
}

View File

@ -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>

View File

@ -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

View File

@ -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
View 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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