added breezefield as a dep, needed to edit some stuff to make it work but it works
This commit is contained in:
238
deps/breezefield/world.lua
vendored
Normal file
238
deps/breezefield/world.lua
vendored
Normal file
@@ -0,0 +1,238 @@
|
||||
-- breezefield: World.lua
|
||||
--[[
|
||||
World: has access to all the functions of love.physics.world
|
||||
additionally stores all Collider objects assigned to it in
|
||||
self.colliders (as key-value pairs)
|
||||
can draw all its Colliders
|
||||
by default, calls :collide on any colliders in it for postSolve
|
||||
or for beginContact if the colliders are sensors
|
||||
--]]
|
||||
-- TODO make updating work from here too
|
||||
-- TODO: update test and tutorial
|
||||
local Collider = require('deps.breezefield.collider') -- it me who put deps.breezefield
|
||||
local set_funcs, lp, lg, COLLIDER_TYPES = unpack(require("deps.breezefield.utils")) -- it me who put deps.breezefield
|
||||
|
||||
|
||||
local World = {}
|
||||
World.__index = World
|
||||
function World:new(...)
|
||||
-- create a new physics world
|
||||
--[[
|
||||
inputs: (same as love.physics.newWorld)
|
||||
xg: float, gravity in x direction
|
||||
yg: float, gravity in y direction
|
||||
sleep: boolean, whether bodies can sleep
|
||||
outputs:
|
||||
w: bf.World, the created world
|
||||
]]--
|
||||
|
||||
local w = {}
|
||||
setmetatable(w, self)
|
||||
w._world = lp.newWorld(...)
|
||||
set_funcs(w, w._world)
|
||||
w.update = nil -- to use our custom update
|
||||
w.colliders = {}
|
||||
|
||||
-- some functions defined here to use w without being passed it
|
||||
|
||||
function w.collide(obja, objb, coll_type, ...)
|
||||
-- collision event for two Colliders
|
||||
local function run_coll(obj1, obj2, ...)
|
||||
if obj1[coll_type] ~= nil then
|
||||
local e = obj1[coll_type](obj1, obj2, ...)
|
||||
if type(e) == 'function' then
|
||||
w.collide_events[#w.collide_events+1] = e
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if obja ~= nil and objb ~= nil then
|
||||
run_coll(obja, objb, ...)
|
||||
run_coll(objb, obja, ...)
|
||||
end
|
||||
end
|
||||
|
||||
function w.enter(a, b, ...)
|
||||
return w.collision(a, b, 'enter', ...)
|
||||
end
|
||||
function w.exit(a, b, ...)
|
||||
return w.collision(a, b, 'exit', ...)
|
||||
end
|
||||
function w.preSolve(a, b, ...)
|
||||
return w.collision(a, b, 'preSolve', ...)
|
||||
end
|
||||
function w.postSolve(a, b, ...)
|
||||
return w.collision(a, b, 'postSolve', ...)
|
||||
end
|
||||
|
||||
function w.collision(a, b, ...)
|
||||
-- objects that hit one another can have collide methods
|
||||
-- by default used as postSolve callback
|
||||
local obja = a:getUserData(a)
|
||||
local objb = b:getUserData(b)
|
||||
w.collide(obja, objb, ...)
|
||||
end
|
||||
|
||||
w:setCallbacks(w.enter, w.exit, w.preSolve, w.postSolve)
|
||||
w.collide_events = {}
|
||||
return w
|
||||
end
|
||||
|
||||
|
||||
function World:draw(alpha, draw_over)
|
||||
-- draw the world
|
||||
--[[
|
||||
alpha: sets the alpha of the drawing, defaults to 1
|
||||
draw_over: draws the collision objects shapes even if their
|
||||
.draw method is overwritten
|
||||
--]]
|
||||
local color = {love.graphics.getColor()}
|
||||
for _, c in pairs(self.colliders) do
|
||||
love.graphics.setColor(1, 1, 1, alpha or 1)
|
||||
c:draw(alpha)
|
||||
if draw_over then
|
||||
love.graphics.setColor(1, 1, 1, alpha or 1)
|
||||
c:__draw__()
|
||||
end
|
||||
end
|
||||
love.graphics.setColor(color)
|
||||
end
|
||||
|
||||
function World:queryRectangleArea(x1, y1, x2, y2)
|
||||
-- query a bounding-box aligned area for colliders
|
||||
--[[
|
||||
inputs:
|
||||
x1, y1, x2, y2: floats, the x and y coordinates of two points
|
||||
outputs:
|
||||
colls: table, all colliders in bounding box
|
||||
--]]
|
||||
|
||||
local colls = {}
|
||||
local callback = function(fixture)
|
||||
table.insert(colls, fixture:getUserData())
|
||||
return true
|
||||
end
|
||||
self:queryBoundingBox(x1, y1, x2, y2, callback)
|
||||
return colls
|
||||
end
|
||||
|
||||
local function check_vertices(vertices)
|
||||
if #vertices % 2 ~= 0 then
|
||||
error('vertices must be a multiple of 2')
|
||||
elseif #vertices < 4 then
|
||||
error('must have at least 2 vertices with x and y each')
|
||||
end
|
||||
end
|
||||
|
||||
local function query_region(world, coll_type, args)
|
||||
local collider = world:newCollider(coll_type, args)
|
||||
collider:setSensor(true)
|
||||
world:update(0)
|
||||
local colls = collider:collider_contacts(collider)
|
||||
collider:destroy()
|
||||
return colls
|
||||
end
|
||||
|
||||
function World:queryPolygonArea(...)
|
||||
-- query an area enclosed by the lines connecting a series of points
|
||||
--[[
|
||||
inputs:
|
||||
x1, y1, x2, y2, ... floats, the x and y positions defining polygon
|
||||
outputs:
|
||||
colls: table, all Colliders intersecting the area
|
||||
--]]
|
||||
local vertices = {...}
|
||||
if type(vertices[1]) == 'table' then
|
||||
vertices = vertices[1]
|
||||
end
|
||||
check_vertices(vertices)
|
||||
return query_region(self, 'Polygon', vertices)
|
||||
end
|
||||
|
||||
function World:queryCircleArea(x, y, r)
|
||||
-- get all colliders in a circle are
|
||||
--[[
|
||||
inputs:
|
||||
x, y, r: floats, x, y and radius of circle
|
||||
outputs:
|
||||
colls: table: colliders in area
|
||||
]]--
|
||||
return query_region(self, 'Circle', {x, y, r})
|
||||
end
|
||||
|
||||
function World:queryEdgeArea(...)
|
||||
-- get all colliders along a (series of) line(s)
|
||||
--[[
|
||||
inputs:
|
||||
x1, y1, x2, y2, ... floats, the x and y positions defining lines
|
||||
outpts:
|
||||
colls: table: colliders intersecting these lines
|
||||
--]]
|
||||
local vertices = {...}
|
||||
if type(vertices[1]) == 'table' then
|
||||
vertices = vertices[1]
|
||||
end
|
||||
check_vertices(vertices)
|
||||
return query_region(self, 'Edge', vertices)
|
||||
end
|
||||
|
||||
|
||||
function World:update(dt)
|
||||
-- update physics world
|
||||
self._world:update(dt)
|
||||
for i, v in pairs(self.collide_events) do
|
||||
v()
|
||||
self.collide_events[i] = nil
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
create a new collider in this world
|
||||
|
||||
args:
|
||||
collider_type (string): the type of the collider (not case seinsitive). any of:
|
||||
circle, rectangle, polygon, edge, chain.
|
||||
shape_arguments (table): arguments required to instantiate shape.
|
||||
circle: {x, y, radius}
|
||||
rectangle: {x, y, width height}
|
||||
polygon/edge/chain: {x1, y1, x2, y2, ...}
|
||||
table_to_use (optional, table): table to generate as the collider
|
||||
]]--
|
||||
function World:newCollider(collider_type, shape_arguments, table_to_use)
|
||||
|
||||
local o = table_to_use or {}
|
||||
setmetatable(o, Collider)
|
||||
-- note that you will need to set static vs dynamic later
|
||||
local _collider_type = COLLIDER_TYPES[collider_type:upper()]
|
||||
assert(_collider_type ~= nil, "unknown collider type: "..collider_type)
|
||||
collider_type = _collider_type
|
||||
if collider_type == 'Circle' then
|
||||
local x, y, r = unpack(shape_arguments)
|
||||
o.body = lp.newBody(self._world, x, y, "dynamic")
|
||||
o.shape = lp.newCircleShape(r)
|
||||
elseif collider_type == "Rectangle" then
|
||||
local x, y, w, h = unpack(shape_arguments)
|
||||
o.body = lp.newBody(self._world, x, y, "dynamic")
|
||||
o.shape = lp.newRectangleShape(w, h)
|
||||
collider_type = "Polygon"
|
||||
else
|
||||
o.body = lp.newBody(self._world, 0, 0, "dynamic")
|
||||
o.shape = lp['new'..collider_type..'Shape'](unpack(shape_arguments))
|
||||
end
|
||||
|
||||
o.collider_type = collider_type
|
||||
|
||||
o.fixture = lp.newFixture(o.body, o.shape, 1)
|
||||
o.fixture:setUserData(o)
|
||||
|
||||
set_funcs(o, o.body)
|
||||
set_funcs(o, o.shape)
|
||||
set_funcs(o, o.fixture)
|
||||
|
||||
-- index by self for now
|
||||
o._world = self
|
||||
self.colliders[o] = o
|
||||
return o
|
||||
end
|
||||
|
||||
return World
|
||||
Reference in New Issue
Block a user