Ok, there's a keyword that I've intentionally kept away from the tags and the title. That's "Android", but that's because even though the project is in Android, I don't think my question has anything to do with it, and I don't want to scare people without experience in Android.
So, the usual problem with swig. I've a virtual method in a C++ class, which I've made it overloadable in Java by adding the director
feature to the class and it works. The problem is that the method receives a polymorphic argument which is also extended on the java side, and during the virtual method call in Java, the object comes with all polymorphic information stripped.
To present the exact situation; I'm writing a game engine in C++, and I want to use it happily in Java. The game engine has a GameObject
class, which registers CollisionListener
s and when the collision engine detects a collision event, it calls the collidedWith(GameObject & collidee)
method of all registered collisionListener
s passing them with what object they've collided.
class CollisionListener {
public:
virtual bool collidedWith(GameObject &){};
~CollisionListener(){} // I know this needs to be virtual but let's forget about that now
};
I'm exposing this class, along with the GameObject
class to java using the following interface file Bridge.i
%module(directors="1") Bridge
%feature("director") CollisionListener;
%include "CollisionListener";
%feature("director") GameObject;
%include "GameObject.h"
Now, when I inherit from CollisionListener
in java and overload collidedWith
, it get's called with a java side GameObject
object. For instance, if I inherit from the java side GameObject
class and define a Bullet
class, when this bullet collides with another object with a listener, in the collidedWith
method call, all I receive is a bare GameObject
, so that (object instanceof Bullet)
does not work. No surprise, I've dug into the swig generated BridgeJNI.java
and found this:
public static boolean SwigDirector_CollisionListener_collidedWith(CollisionListener self, long arg0) {
return self.collidedWith(new GameObject(arg0, false));
}
So it wraps a new object around the pointer before calling the java overloads.
So, the main question is how to receive a Bullet
object when there's a collision?
I've come up with a way to easily achieve that but I need to modify the auto-generated files, which is a bad idea. So I'm hoping some swig master could help me inject the modifications to the swig generated files.
My little hack is to keep a jobject * self
in every C++ side GameObject
object, and assign the address of the real java object during the construction of the real java side GameObject
(and not the one that merely wraps the pointer). This way, I could define a polymorphic getSelf
method in C++ side GameObject
and use the result happily in java. Is there a way to inject the necessary code to the swig generated files?
Thanks
Note: If you tried directors on Android and they haven't worked, it's because the current stable version does not support it. Download the Bleeding Edge from the swig website. But I'm writing this in 22/03/2012 and this note will soon be unnecessary. The reason why the destructor isn't virtual is that the Bleeding Edge version makes the program crash in the destructor, and making it non-virtual seems to keep it under control for now.
See Question&Answers more detail:
os