[committed] collision-masks

No, I don't think you're the only one who would want this (I have a need for it actually myself). It would be very useful. Of course, a user could implement this themselves, but having it built in would be nice.

snareoj2 said:

i made this by having the "pickgroups" in seperate Tree branches...


As a Spatial can only have one parent, this doesn't satisfy the requirements.


Personally i dont like acting with bitsets, i think there was a cleaner solution in Blochs Effective Javabook, but i dont remember...

Bitsets are clean, and any Java developer who works with AWT event masks, for example, must know how to use them, but I understand many Java developers do not like to use them.

If somebody knows of an alternative impl. tactic that is close to the efficiency of bit masks, please let me know.  The collision methods sometimes run very frequently (e.g. when moving quickly to determine ground height; and to change cursor upon every mouse drag event).

There are efficient ways to do it with arrays or Sets of Classes (one could pass marker interfaces, for example), but that requires the sets to be defined at class/interface definition time, instead of by dynamic runtime data.

I don't think any other tactic is going to improve on bitmasks for efficiency.  If jME users don't want to deal with bit masks, then I can just make wrapper methods to transform user-defined Strings to the needed bit values.

   public Spatial addIsCollidable(String);
   public Spatial setIsCollidable(String[])  (or Set<String>)
   public Spatial hasCollision(String[]), etc.

The scope of the internal String->integer mappings must be considered, but since jME uses static singletons zealously elsewhere, that tactic would be easy and safe for the first implementation here, and would exactly match existing behavior when user sets no Strings at all.  (The known limitation being independent sets for independent scenes, but there is no need for that at this point).

Regards

snare
Starnick said:

No, I don't think you're the only one who would want this (I have a need for it actually myself). It would be very useful. Of course, a user could implement this themselves, but having it built in would be nice.


This situation is not one that facilitates DIY.  isCollidable usage is spread among very basic jME classes like Node, Spatial, and others... classes that you can't just extend, because all of the Spatial subclasses extend them, and classes that you probably should not override by classpath because you don't want them to get out-of-sync with the jME code base.

If one were to implement the feature external to those classes, you'd lose the performance benefits of the tight and direct integration with world bounds.  This performance is the only reason I want to leverage collisions more.

i made this by having the "pickgroups" in seperate Tree branches…



Personally i dont like acting with bitsets, i think there was a cleaner solution in Blochs Effective Javabook, but i dont remember…



Regards



snare

I was actually thinking of implementing this in jME3. JGame library seems to use this as well.

You could have something like Spatial.setCollisionMask(COL_ENTITY | COL_CHARACTER) then you can test it with Spatial.isCollisionMask(COL_ENTITY). Very useful in games and such where you need to select what you want to collide with.

Momoko_Fan said:

I was actually thinking of implementing this in jME3. JGame library seems to use this as well.
You could have something like Spatial.setCollisionMask(COL_ENTITY | COL_CHARACTER) then you can test it with Spatial.isCollisionMask(COL_ENTITY). Very useful in games and such where you need to select what you want to collide with.


Right on.
blaine said:

Starnick said:

No, I don't think you're the only one who would want this (I have a need for it actually myself). It would be very useful. Of course, a user could implement this themselves, but having it built in would be nice.


This situation is not one that facilitates DIY.  isCollidable usage is spread among very basic jME classes like Node, Spatial, and others... classes that you can't just extend, because all of the Spatial subclasses extend them, and classes that you probably should not override by classpath because you don't want them to get out-of-sync with the jME code base.

If one were to implement the feature external to those classes, you'd lose the performance benefits of the tight and direct integration with world bounds.  This performance is the only reason I want to leverage collisions more.


Well I was thinking more along the lines of spatial's setUserData, but I'd find that sloppy. Still, doesn't matter since I support this ;)

I've begun work.



Be aware that custom Spatial subclasses which work with the isCollidable field directly will need to be updated.  Subclasses which use isCollidable() to prevent tight bindings (which non-jME-codebase code should do for this exact reason) are fine.



I've added backwards-compatible Savable.read() support (for the "isCollidable" boolean) so that old models will continue to work as expected… and have tested it.

committed w/ rev. 4640



In addition to the isCollision usage described in my previous post, rare, custom Spatial subclasses (outside of the jME code base) which override calculateCollisions, findCollisions, hasCollision, or findPick; and TriMesh subclasses (outside of the jME code base) which override hasTriangleCollision will need to be updated.  Where an update is required, it just consists of changing existing tests like x.isCollidable(boolean) to x.isCollidable(int), using the newly provided int parameter.



All compatibility discussion has been about subclasses.  The public interfaces are fully backwards compatible and require no updates.



A nice, little, extra feature is that by specifying matching bits of 0, like "s.isCollidable(0)", you purposefully ignore Spatials' isCollidable settings and test for collisions with all Spatials in the scene.  This is the natural consequence of using the specified bits to narrow the candidate set.  The default is "1", but if you specify "0", you aren't narrowing the candidate set at all.  Similarly, on the other side (setting Spatial bit masks, a.o.t. collision operations), you can turn all bits on to make sure that Spatial will never be eliminated from a collision by virtue of its bit mask (perhaps should make a constant like ALWAYS_COLLIDE for -1 = all bits on).  Since for some collision operations, nodes can exclude all descendants from consideration, I've changed the default of Nodes to -1 (subject to change).  This only effects users who purposefully use different bitmask values, since if you just use setIsCollidable(boolean),  -1 and 1 will do the same thing.



If that hasn't already made it clear, due to this default behavior isCollidable() == isCollidable(1).

Good job. Using collision-masks is quite usefull! Thx for commiting.