Page MenuHome

BGE physics: When colliding, report first contact point to Python
ClosedPublic

Authored by Sybren A. Stüvel (sybren) on Dec 4 2014, 4:30 PM.

Details

Summary

This patch adds two parameters to the functions in the collisionCallbacks list. The callback function should thus be like this:

def on_colliding(other, point, normal):
    print("Colliding with %s at %s with normal %s" % (other, point, normal))

game_ob.collisionCallbacks.append(on_colliding)

The point parameter will contain the collision point in world coordinates on the current object, and the normal contains the surface normal at the collision point.

An alternative would be to pass a list of all collision points to the callback, rather than just the first one. I could implement this, if it is deemed much better -- the current implementation suits my needs.

Due to the change in the arity of the callback function, this patch constitutes an API-breaking change. We could try to use introspection to find out whether the new parameters will be accepted or not. However, this will cost CPU time, and may not always work (for example when the callback is routed through functools.partial or other function with a variable nr of arguments).

Diff Detail

Repository
rB Blender

Event Timeline

inactive account (sybrenstuvel) retitled this revision from to BGE physics: When colliding, report first contact point to Python.

Initial glance looks good to me. Having tested this, do you find the reported point is sensible? I've written a patch for providing contact data, but I noticed that unusual values were sometimes reported, most specifically the collision impulse.

To me they are quite sensible. I've been thinking about exposing all contact points, but the first one per colliding object seems to work for me.

From the implementation point of view seems fine and seems useful as well. But isn't it gonna to break quite a few of existing scripts?

source/gameengine/Ketsji/KX_TouchEventManager.h
72

Remove whitespace changes.

Campbell Barton (campbellbarton) requested changes to this revision.Jan 28 2015, 6:35 PM
Campbell Barton (campbellbarton) edited edge metadata.
Campbell Barton (campbellbarton) added inline comments.
source/gameengine/Ketsji/KX_GameObject.cpp
1498

This isn't really an efficient way to make a tuple, see PyTuple_SET_ITEMS macro.

1498

Passing more arguments in will break existing scripts, You can inspect the function.

See how bpy_prop_callback_check gets co_argcount

This revision now requires changes to proceed.Jan 28 2015, 6:35 PM
Sybren A. Stüvel (sybren) edited edge metadata.

Removed whitespace changes.
Using PyTuple_SET_ITEMS to create tuple.

@Sergey Sharybin (sergey): yes, this change is going to break scripts if we accept the patch as it is now. This is something I want to avoid if we can. I see three ways to continue:

  1. Implement as-is, and accept that there will be breakage (not my favourite).
  2. Use co_argcount to detect whether the new arguments will be accepted like @Campbell Barton (campbellbarton) suggested. I too feel that this is better than option 1. However, it may still break when a variable number of parameters is used; for example: def callback(*args): ..., as co_argcount only counts the fixed arguments. I'm also not familiar with how fast such a check would be, and it probably has to be performed for every call to every callback. The setter for KX_GameObject.collisionCallbacks won't be called when appending a callback function, so we won't be able to perform the check there.
  3. Add a second callback list for the new parameters, for example collisionCallbacksExtended. That way the semantics of the current collisionCallbacks don't change, and old/current scripts don't need updating. Per-call checks also won't have to be performed.

Personally I prefer option 3, but if 2 is deemed better I'll implement that.

Note that this patch doesn't contain updates to the documentation yet. I wanted to be sure how we proceed before documenting.

@Sybren A. Stüvel (sybren), sergey and me noted *args would fail, should have mentioned in review.

While correct, its unlikely that a function accepting a single arg would be using *args,
So while it could break scripts, in practice its not very likely.

You could also use a single argument in the case of *args so as not to break anything.

Its not a perfect solution anyway, because python can have callable objects which aren't functions, its just that they arent used so often. especially not in situations like this.

I don't think having a separate list is needed really, getting co_argcount is a direct lookup in memory, theres no expensive dictionary access for example.

Sybren A. Stüvel (sybren) planned changes to this revision.Jan 29 2015, 12:31 PM

@Sybren A. Stüvel (sybren), sergey and me noted *args would fail, should have mentioned in review.

This is also what I referred to in my initial description ("However, this will cost CPU time, and may not always work (for example when the callback is routed through functools.partial or other function with a variable nr of arguments).") so I was already aware of that ;-)

I'll do a check on co_argcount, update the documentation, and send in an updated patch for review.

On a slightly related note, would someone mind checking whether my suspicions of a bug are correct? I am concerned that sensor objects register with collision sensors when they have collision callbacks.
Personally speaking, I think we should break the existing API given that I suspect its usage is quite rare, and those who do will be aware of the necessary changes.

Sybren A. Stüvel (sybren) edited edge metadata.

Checking co_argcount to see how we should call the callback. Supports functions, methods, and generic callables (objects with a __call__ method). Also updated documentation.

Regarding inspecting function args, I think its important just to check for the common case, if its a single arg. else it can pass 3 in.

source/gameengine/Ketsji/KX_GameObject.cpp
1532

this will leak memory (Py_DECREF(call) is needed before exiting)

1532–1543

I think this is overkill..

Sybren A. Stüvel (sybren) updated this object.

Removed generic callable support + improved readability of example code.

Removed some changes that accidentally made it into the previous patch.

Campbell Barton (campbellbarton) requested changes to this revision.Feb 4 2015, 6:48 PM
Campbell Barton (campbellbarton) edited edge metadata.
Campbell Barton (campbellbarton) added inline comments.
source/gameengine/Ketsji/KX_GameObject.cpp
1512

would call args_1, args_3 - with note that args_1 is only for compatibility

1531

Wouldnt bother raising an exception, just set co_argcoun == 3 in this case and assume the callable takes the right number of args.

This revision now requires changes to proceed.Feb 4 2015, 6:48 PM
Sybren A. Stüvel (sybren) edited edge metadata.

Implemented Campbell's suggested changes.

Campbell Barton (campbellbarton) edited edge metadata.

LGTM

source/gameengine/Ketsji/KX_GameObject.cpp
1530

style:

}
else {
This revision is now accepted and ready to land.Feb 8 2015, 3:46 PM
This revision was automatically updated to reflect the committed changes.