Closed jyoung4242 closed 1 year ago
follow up, in the diagnostic draw() method for debugging, you could draw that label onto the canvas in the box/circle,... just a thought
another follow up, since i'm using TS, i just created a new type to extend box/circle that added a catagory property to the type, and i can switch on that but still, i'd think its useful...
This has come up for my project as well.
I am considering switching my project to this library from the older Sinova/Collisions lib. Being able to perform collisions on a filtered subset is critically important. I have hundreds of objects in a small space, but most of them do not collide with each other. Being able to check only a small fraction of objects would yield dramatic performance gains. It would be best to do any filtering before doing collision math checks. Ideally, i am looking for an optional string type or more flexible callback on collision, like:
system.checkAll( onCollideCallback, 'type_player' )
or
system.checkAll( onCollideCallback, filterCallback )
If the library internals already allow for this, please advise. I would also be interested in implementing this if it is not already.
Thanks!
@leiavoia this library uses a library (rbush) to create collision trees no unnecessary math is done there
see https://prozi.github.io/detect-collisions/demo/?stress
BUT you can always try to use something like
players.forEach(player => {
system.checkOne(player, onCollideCallback)
})
if that suits your use-case, to try some micro optimization
this way you will check only what players collide with, and not check if other objects do (with other things than players)
so this will detect player-nonplayer and player-player but not nonplayer-nonplayer collisions if that's where you're aiming
@jyoung4242 thank you for your comments
one idea that might be useful, because i've found myself needing this while using your library, is maybe adding a string property to the Body types where you can add a label, like "tile", "enemy", "player"
This could assist in categorizing collision resolutions so you can quickly switch on type of body to a different resolution.
you can do this like
class Bullet extends Circle {};
class Player extends Circle {};
type ExtendedBody = Player | Bullet;
const system = new System<ExtendedBody>();
// ...
see https://prozi.github.io/detect-collisions/classes/System.html
you can do new System<YourNewType>()
or actually if you read
https://www.npmjs.com/package/rbush#creating-a-tree and our documentation and know that system extends rbush
then you can do
const maxEntriesInTreeNode = 16 // or other
new System<YourNewType>(maxEntriesInTreeNode)
if you'd ever need it or want to try to micro optimize here
I see. This may not work then.
In my scenario, i have a fishtank with fish and food flakes. Fish need to detect food collisions to eat the food. Fish do not collide with each other, but they do need to collide with obstacles (rocks) and food. Fish also need to be locally detectable by other fish (flocking behavior), even though there is no direct collision resolution.
Currently, I have something analogous to this:
fish.forEach( fish => {
system.findCollisions( fish, onCollideCallback, 'Food' ); // only check "Food" objects
})
I suppose a roundabout solution would be to maintain separate "systems" with each system keeping track of a different object type.
@leiavoia
I see. This may not work then.
In my scenario, i have a fishtank with fish and food flakes. Fish need to detect food collisions to eat the food. Fish do not collide with each other, but they do need to collide with obstacles (rocks) and food. Fish also need to be locally detectable by other fish (flocking behavior), even though there is no direct collision resolution.
Currently, I have something analogous to this:
fish.forEach( fish => { system.findCollisions( fish, onCollideCallback, 'Food' ); // only check "Food" objects })
then u were quite close just do something like below I havent tested this but something along those lines are what you're looking for this is optimal and unless you got more than 1000 entries updated each frame I wouldn't worry about optimisations at all
// type definition
class Fish extends Circle {
isFish = true
eatFood(food) {
this.system?.remove(food)
}
}
class Food extends Circle {
isFood = true
}
class Rock extends Polygon {
isRock = true
}
class Tank extends System<Fish | Food | Rock> {}
// initialisation
const system = new Tank()
const fishes = [
new Fish({ x: 10, y: 10 }, 10),
new Fish({ x: 30, y: 10 }, 10),
new Fish({ x: 50, y: 10 }, 10),
]
fishes.forEach(fish => {
system.insert(fish)
})
system.insert(
new Rock({ x: 30, y: 100 }, [{ x: 0, y: 0 }, { x: 50, y: 50 }, { x: 0, y: 50 }], { isStatic: true })
)
system.insert(
new Food({ x: 30, y: -50 }, 5)
)
// usage - each frame - detect and handle collisions
fishes.forEach(fish => {
system.checkOne(fish, ({ a: thatFish, b: maybeFood, overlapV: { x, y } }) => {
if (maybeFood.isFood) {
fish.eatFood(maybeFood)
} else if (maybeFood.isRock) {
// push back the fish by rock
fish.setPosition(fish.x - x, fish.y - y)
} else { // propably another fish
// do nothing just log the collider
console.log(maybeFood)
}
})
})
I suppose a roundabout solution would be to maintain separate "systems" with each system keeping track of a different object type.
this is the last thing I would recommend especially for the performance reasons, this seems it would be twice as slow trust in the broad phase search of the library and having all of the entries in collision trees this means for each entry in the system, it isn't checked agains each of the other objects, just the nearest candidates, in the same sector in the tree
and since you also need to handle the food I wouldn't even use the fishes array and checkOne just replace it with one system.checkAll and handle it there based on those is* props like above TBH
since food collides with rocks right?
just use system.checkAll(handler)
try it
I tried a working prototype with the collision detection code using this lib instead of the older Sinova lib and my own custom spacial grid system. It has more features, but it runs 25-25% slower now ;-(
Are there any performance tuning parameters or optimizations available? I see that RBush takes a few, but not sure if i can pass those in as parameters.
Thanks
I tried a working prototype with the collision detection code using this lib instead of the older Sinova lib and my own custom spacial grid system. It has more features, but it runs 25-25% slower now ;-(
sorry to hear that, maybe I can help with the code if you show the main parts
Are there any performance tuning parameters or optimizations available? I see that RBush takes a few, but not sure if i can pass those in as parameters.
Thanks
System extends RBush so the constructor params are the same refer to https://www.npmjs.com/package/rbush#creating-a-tree
as for optimizations there are two powerful optimization methods:
isStatic bodies are omitted in some computations
padding makes body not reinsert into collision tree when the movement it has is within the padding (close collision is still accurate based on real box etc)
also what kind of calculations you do each frame?
what changes in the bodies?
is it only position or more?
how do you update the bodies?
@jyoung4242 thank you for your comments
one idea that might be useful, because i've found myself needing this while using your library, is maybe adding a string property to the Body types where you can add a label, like "tile", "enemy", "player" This could assist in categorizing collision resolutions so you can quickly switch on type of body to a different resolution.
you can do this like
class Bullet extends Circle {}; class Player extends Circle {}; type ExtendedBody = Player | Bullet; const system = new System<ExtendedBody>(); // ...
i actually did something very similar to this and it worked well
is it fair to close this issue?
one idea that might be useful, because i've found myself needing this while using your library, is maybe adding a string property to the Body types where you can add a label, like "tile", "enemy", "player"
This could assist in categorizing collision resolutions so you can quickly switch on type of body to a different resolution.