Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 40 additions & 10 deletions README.org
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,42 @@
if there are any issues in breezefields implementation that complicates using
love.physics together with it, let me know, or better yet, send a pull request

** Collision classes

Collision classes allow you to set filters to colliders.
Collision classes in breezefield is just like windfield.
If you want to the collider A ignores collider B (or collider B ignores collider A), you would do:

#+BEGIN_SRC lua
local bf = require "breezefield"

local world = bf.newWorld(0, 100)

-- creating collision classes --
world:addCollisionClass("ColliderB")
world:addCollisionClass("ColliderA", {
ignores = {"ColliderB"},
})

-- creating colliders
local colliderA = world:newCollider("Rectangle", {100, 100, 32, 32})
local colliderB = world:newCollider("Rectangle", {120, 100, 32, 32})

-- adding to colliders --
colliderA:setCollisionClass("ColliderA")
colliderB:setCollisionClass("ColliderB")

function love.update(dt)
world:update(dt)
end

function love.draw()
world:draw()
end
#+END_SRC

See the folder tests/test_collisionclass for deep undestanding.

* Installation
I reccomend you ensure you understand love.physics, as breezefield mostly just wraps that. You can start [[https://love2d.org/wiki/Tutorial:Physics][here]].
To install simply clone or download the repository and place breezefield anywhere in your lua path or in your project directory.
Expand All @@ -95,14 +131,14 @@ function love.load()
-- any function of love.physics.world should work on World
print(world:getGravity())

ground = bf.Collider.new(world, "Polygon",
ground = world:newCollider("Polygon",
{0, 550, 650, 550 , 650, 650, 0, 650})
ground:setType("static")

ball = bf.Collider.new(world, "Circle", 325, 325, 20)
ball = world:newCollider("Circle", 325, 325, 20)

ball:setRestitution(0.8) -- any function of shape/body/fixture works
block1 = bf.Collider.new(world, "Polygon", {150, 375, 250, 375,
block1 = world:newCollider("Polygon", {150, 375, 250, 375,
250, 425, 150, 425})

end
Expand Down Expand Up @@ -148,7 +184,7 @@ function spawn_random_ball()
end

function little_ball.new(x, y)
local n = bf.Collider.new(world, 'Circle', x, y, 5)
local n = world:newCollider('Circle', x, y, 5)
setmetatable(n, little_ball)
return n
end
Expand Down Expand Up @@ -201,13 +237,7 @@ and after little_ball's declaration
#+BEGIN_SRC lua
little_ball.identity = little_ball
#+END_SRC
** TODO define some form of collision filtering
for now, see:
[[https://love2d.org/wiki/Contact:setEnabled]]
[[https://love2d.org/wiki/Fixture:setFilterData]]



* links
** forum
[[https://love2d.org/forums/viewtopic.php?f=5&t=86113&p=224718#p224718][forum]]
Expand Down
54 changes: 54 additions & 0 deletions collider.lua
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,58 @@ function Collider:collider_contacts()
return colliders
end

--- Sets a collision class to the collider.
---@param name string
function Collider:setCollisionClass(name)
local cls = self._world.collision_classes[name]

assert(cls, "collision class '" .. tostring(name) .. "' does not exist")

local cls_id = cls.id
local cls_info = cls.info

self.fixture:setCategory(cls_id)

-- classes to be not inserted
local doesnot_insert = {}

if cls_info.except then
for i=1, #cls_info.except do
doesnot_insert[cls_info.except[i]] = true
end
end

local to_ignore = {}
if cls_info.ignores then
-- if it's All then expand to every collision class that exist
if cls_info.ignores == "All" then
cls_info.ignores = {}
for cls_name in pairs(self._world.collision_classes) do
if cls_name ~= name then
cls_info.ignores[#cls_info.ignores+1] = cls_name
end
end
end

for i=1, #cls_info.ignores do
local ignore_cls = cls_info.ignores[i]

if not doesnot_insert[ignore_cls] then
local id = self._world.collision_classes[ignore_cls].id

table.insert(to_ignore, id)
end
end
end

self.collision_class = name

self.fixture:setMask(unpack(to_ignore))
end

-- returns the collision class of the object
function Collider:getClass()
return self.collision_class
end

return Collider
6 changes: 5 additions & 1 deletion test.sh
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,8 @@ love test/test_rendering

mkdir test/test_queryareas/breezefield
cp * test/test_queryareas/breezefield
love test/test_queryareas
love test/test_queryareas

mkdir test/test_collisionclass/breezefield
cp * test/test_collisionclass/breezefield
love test/test_collisionclass
58 changes: 58 additions & 0 deletions test/test_collisionclass/main.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
local bf = require "breezefield"

local world = bf.newWorld(0,100,true)

world:addCollisionClass("GroundA")
world:addCollisionClass("GroundB")
world:addCollisionClass("GroundC")

world:addCollisionClass("CircleA", {
ignores = "All",
except = {"GroundA"}
})

world:addCollisionClass("CircleB", {
ignores = "All",
except = {"GroundB"}
})

world:addCollisionClass("CircleC", {
ignores = "All",
except = {"GroundC"}
})


local groundA, groundB, groundC
local circleA, circleB, circleC

function love.load()
local w_width = love.graphics.getWidth()
local w_height = love.graphics.getHeight()
groundA = world:newCollider("Rectangle", {w_width/2, 50, w_width, 5})
groundB = world:newCollider("Rectangle", {w_width/2, 100, w_width, 5})
groundC = world:newCollider("Rectangle", {w_width/2, 150, w_width, 5})
groundA:setCollisionClass("GroundA")
groundB:setCollisionClass("GroundB")
groundC:setCollisionClass("GroundC")

groundA:setType("static")
groundB:setType("static")
groundC:setType("static")

circleA = world:newCollider("Circle", {100, 10, 10})
circleA:setCollisionClass("CircleA")

circleB = world:newCollider("Circle", {200, 10, 10})
circleB:setCollisionClass("CircleB")

circleA = world:newCollider("Circle", {300, 10, 10})
circleA:setCollisionClass("CircleC")
end

function love.update(dt)
world:update(dt)
end

function love.draw()
world:draw()
end
21 changes: 21 additions & 0 deletions world.lua
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ function World:new(...)
w.update = nil -- to use our custom update
w.colliders = {}


w.collision_classes = {}

-- starts at 1 and go to 16
w._classes_id = 1

-- some functions defined here to use w without being passed it

function w.collide(obja, objb, coll_type, ...)
Expand Down Expand Up @@ -330,4 +336,19 @@ function World:newCollider(collider_type, shape_arguments, table_to_use)
return o
end

--- Adds a collision class to the world
---@param name string
---@param info { ignores: {integer: string} | "All", except?: {integer: string}}
function World:addCollisionClass(name, info)
assert(type(name) == "string", "invalid collision class name")
assert(self._classes_id <= 16, "limit of collision classes was exceeded")

self.collision_classes[name] = {
info = info or {},
id = self._classes_id
}

self._classes_id = self._classes_id + 1
end

return World