The new collision callbacks, how to use them, simplest method returns an empty list

So in a bleeding edge build done within the last hour, I opened up Blender, create a cube falling into a piece of ground, and gave it an always sensor to run this piece of code.

from bge import logic

con = bge.logic.getCurrentController()
own = con.owner

collide = own.collisionCallbacks

print(collide)

The only issue I’m having right now is that I don’t seem to get yet how to get useful information out of the new collisionCallbacks attribute (all it returns is an empty list). Do note that the revision I used is one after the recent typo fix.

Is there anything I must do to start getting information out of it, perhaps the scene wasn’t ideal or that you have to use the code in a different way? I also tried Solarlune’s code but that didn’t get anywhere either, If the developer especially (Agoose77 since he introduced it) can show how to use the attribute to where it returns information, I’m all ears.

Thanks.

KX_GameObject.collisionCallbacks is a list of callables that are called when a collision occurs with the object. These are used in a similar fashion to KX_Scene.pre/post_draw:


# untested
from bge import logic

ob = logic.getCurrentController().owner

def cb(other):
    print("Collision with", other)

ob.collisionCallbacks.append(cd)

This is really useful when combined with mutated KX_GameObject classes:


# also untested
from bge import logic

class MyObject(KX_GameObject):
    def __init__(self, gameobj):
        self.collisionCallbacks.append(self.onCollision)

    def onCollision(self, other):
        print(self, "collided with", other)

Who would actually want to program like that? And why? I mean, where is the benefit in handing over control to something else?

A hit_objects method would be a nice alternative to sensors: semantically cleaner, and more straightforward overall.

Just tested it and I got it to work. Is it also possible to get a hitObjectList?

I think what Goran proposes would be really cleaner and easier to use. Or do I miss something? ^^

Edit
Just played with the collision callbacks. I have to say this is really unhandy! Once a collision handler is appended it runs all the time. How would I check for specific properties in hitObjects? Always append a new handler to the collision callback list?

I would love to see as Goran already mentioned collisions handled something like this! Just a collision method ontop of KX_GameObject: obj.hit_objects(or something similar, I don’t know what the best design is)

Maybe we can use it something like this:

for hit_object in obj.hit_objects:
    if 'property' in hit_object:
        return hit_object

But maybe I am just not used to working with callbacks? Maybe there is a nice workflow?

I do not like the callback technique. It makes the current chaotic looking API much more confusing by adding a complete different processflow.

I think it is added because of the timing (logic frames vs. physics steps). But I’m not sure what a better solution can be if it is really necessary to do that.

Currently I do not see benefits in difference to the collision sensors. (I’m sure the people favoriting “code only” think different ;).)

Here is another example: https://github.com/Moguri/ullur/blob/master/src/scripts/collectable.py

The one thing I like about callbacks is I can just set them up and they handle themselves. I don’t have to explicitly check them every frame. However, I can see how this might be awkward to use for some people…

How about creating a module “bge.callback” which deal with the callback management?

The point being that you’re given the responsibility of filtering collisions in python. The reason that the collisions sensor does this is because it is designed for use with logic bricks only.
The callback list is looped over every time a discrete collision occurs. It gives the collided object as an argument. You can check if it stops colliding when the callbacks are no longer executed.

The issue with hit objects as a list is that you would need to maintain a list of colliders during during the collisions update. This adds unnecessary code to the game object, but it would be possible if users preferred it. However, having a callback rather than polling the collided objects is a preferred implementation for me, and for most scripting purposes. It’s quite trivial to add a python callback that can write to the property dictionary.

They only “handle themselves” when you just need to act on collision.

For anything more involved, with substantial state, you would have to actually manage the collisionCallbacks list. For example: If I go from state A (where I want to run some code on a certain collision event), to state B (where I don’t want to run that code), I have to track and remove the relevant functions, and then add them again when I go back.

With hit_objects, I could just look at the code in the state, and know, right away: “This code runs here, and only here, and only for this state.”.

Well, I think you should demonstrate that for us, so that we can see how it compares to this:


if jello in own.hit_objects:
    own.jiggle()
else:
    own.wiggle()

The issue with hit objects as a list is that you would need to maintain a list of colliders during during the collisions update. This adds unnecessary code to the game object, but it would be possible if users preferred it.

The collision sensor already carries such a list; It’s not unnecessary code if it’s required for feature parity.

As for what the users prefer: It would probably be better to establish this before tossing code into trunk, but right now, it seems that I’m not alone in my opinion.

The two concepts are dependent upon how the user wishes to implement logic. Polling a collision list to find a change against running a callback directly

Sent from my Nexus 7 using Tapatalk 4

I feel like the collision list fits better with existing logic. It might be needlessly complex, but if this was implemented in a fashion similar to the bge.events module, where a dictionary of events points to the current status of the event, you could poll for the collision status of certain objects:

for hit_object in object.hit_objects:
    if hit_object.status == JUST_COLLIDED:
        pass
    if hit_object.status == COLLIDED:
        pass

If the user wanted callbacks to be called directly, they could write their own system that polls the collision list and calls appropriate callbacks based on changes.

I think the biggest need right now is some extensive documentation with plenty of example code covering different uses, because right now it’s just a simple entry in the Blender python docs. and doesn’t really help at all in helping people use it.

In short, this feature will only be considered useful if people have a good idea on how to use it as a major part of their collision logic.




class CollisionStatus:
    """Handles collision for Actors"""
    def __init__(self, actor):

        self.register_callback(actor)

        self._new_colliders = set()
        self._old_colliders = set()
        self._registered = set()
        self._actor = actor


        self.receive_collisions = True


    @property
    def colliding(self):
        return bool(self._registered)


    def is_colliding(self, other, data):
        if not self.receive_collisions:
            return

        # If we haven't already stored the collision
        self._new_colliders.add(other)

        if not other in self._registered:
            self._registered.add(other)
             #CollisionEvent.invoke(other, True, target=self._actor)

    def not_colliding(self):
        if not self.receive_collisions:
            return


        # If we have a stored collision
        difference = self._old_colliders.difference(self._new_colliders)

        self._old_colliders = self._new_colliders
        self._new_colliders = set()

        if not difference:
            return

        for obj in difference:
            self._registered.remove(obj)

             #CollisionEvent.invoke(obj, False, target=self._actor)


    def register_callback(self, actor):
        actor.collisionCallbacks.append(self.is_colliding)

This maintains a list of existing collisions, and invokes callbacks when a collision changes state.

I actually like gruntbatch’s idea. It looks more “bgeonic” if collisions were added to the event system which they actually are.
But there would have to be a mechanism to “register” colision objects in order to keep it performant.

Apart from async libload I don’t know of any other callback functionality inside the bge api.

I think collision callbacks can be implemented by the game developers themselves quite easily.

Pré and post draw callbacks

Sent from my Nexus 7 using Tapatalk 4

Technically that isn’t correct. The hitobjects list is just accumulated during one frame. Plus to keep things identical one wouldn’t add a hitobject.status attribute. If users are so averse to callbacks interfering with design of the engine, the game loop patch I’m finalising could be one alternative, as you’d have greater control over the draw.

Sent from my Nexus 7 using Tapatalk 4

I’ve just finished a patch to add support for collision information in the BGE - namely the contact points, the impulse (and therefore the force of collision).

I’ve not given a lot of thought to the logic bricks, but I’ve exposed the data there (it was already partially implemented). I just need the logic bricks to make use of the data. Could anyone think of a good implementation case?

I think what would at least be needed is to add new properties to the collision brick that can be read and used through Python, so along with hitObject and hitObjectList, you would also have properties like contactPointList and impulse.

Anyway, to get this in right after 2.69 is released will serve as an important asset when it comes to enhancing BGE projects, think of the idea of creating dust right where a tire meets a dirt road or breaking an object when it hits a wall with enough force.

It would be even better if we can add a property like hitPoly to the list (for executing logic based on the material the object is in contact with), or maybe even hitPixel (for getting a collision point in camera space or getting the color of the texture on that spot).

hitPolyData?

Getting the polygon’s data from the collision sensor would only duplicate functionality, all you would need to get is the polygon in which you would afterwards use the PolyProxy module to get the material, vertices, ect…