How can I find what game object a colliding Geom is a member of

Jan 30, 2010 at 11:31 AM

This may seem like a fairly amature question, but it's got me stumped.

Geoms and bodies are great for physics, but I use a GameObjectClass for most things. In my game, the geom and the body are members of a GameObjectClass, which deals with most game interactions.

My problem is that the OnCollision code gives you two Geoms and a contact list, but no clear way to go higher in the chain. At the moment, I find what GameObject is involved in the collision by looping through every GameObject and comparing it's geom to the two involved in the collision. Once there's a match, I've found which GameObject has collided, because its geom is one of the two involved.

It works fine, but there's got to be a better way to find what class a geom belongs to than looping and comparing, right? Or should I add a member to the geom class in farseer called "owningGameObject" or some such. As a rookie, I'm a bit reluctant to alter the farseer code itself.

Jan 30, 2010 at 5:14 PM
Edited Jan 30, 2010 at 5:16 PM

I solved this by using a dictionary. In the collision event I find the object registered to the Geom in the collision.

Here's my implementation, but it's just because it fit my own design:

 

 

public sealed class SpriteMap : Dictionary<Geom, ICollidable>
    {
        private static readonly SpriteMap instance = new SpriteMap();

        private SpriteMap()
        {
        }

        public static SpriteMap Instance
        {
            get { return instance; }
        }
    }

 

 

ICollidable is just:

 

public interface ICollidable
    {
        Geom Geometry { get; }
    }


And in my base sprite-class's initialize method:

SpriteMap.Instance.Add(Geometry, this);


I think you get the idea.


Joni

 

 

Feb 1, 2010 at 6:42 PM

This is how I do it: I have an abstract 'PhysicsEntity' class, which looks like this (shortened version):

 

        public Body Body { get; protected set; }

        public Geom Geom { get; protected set; }

 

        protected PhysicsEntity()
        {
            physicsSimulator = EntityController.Instance.PhysicsSimulator;
            EntityController.Instance.RegisterEntity(this);
        }

        public virtual void Kill()
        {
            EntityController.Instance.RemoveEntity(this);
        }

 

        protected void CreateSimpleCollisionHelper()
        {
            collisionHelper = new SimpleCollisionHelper();
            Geom.OnCollision = collisionHelper.OnCollision;
        }

 

All my game objects that use physics inherit from this class. When the GameObject is constructed, it automatically registers itself with the EntityController. The EntityController manages the drawing and update list etc. The 'Kill' method removes the game object from the drawing list.

So what I do for specific collision checking: from  the constructor of my concrete gameobject class I call the CreateSimpleCollisionHelper() method and attach the CollisionHelper class to the object's geom. The collision helper checks for collisions with other game objects, and raises a specific event that the gameobject can handle.

The example below uses a singleton (there's one and only one 'BirdHouse' object in the game), but some other collision checks iterate over lists as well.

 

public event CollisionWithBirdHouseEventHandler CollisionWithBirdHouse = delegate { };

        public bool OnCollision(Geom geometry1, Geom geometry2, ContactList contactlist)
        {
            if(geometry2.Equals(BirdHouse.Instance.Geom))
            {
                CollisionWithBirdHouse();
            }

        }

 

 

I hope this helps. I know it's definitely not the best/most performant way, but it works for me and allows me to reuse a lot of the code.

Feb 2, 2010 at 12:38 PM

hmmm.....
after seeing people go through such complex ways, it makes me wonder if I'm doing something wrong !!

acutally I simply use the tag in the geom.

so it goes something like this.

ballBody = BodyFactory.Instance.CreateCircleBody(radius, mass);
ballBody.Tag = this;

ballGeom = GeomFactory.Instance.CreateCircleGeom(ballBody, radius, 24);
ballGeom.Tag = this;

of course, all classes should inherit from a class that identifies the object type as environment, character or anything else.

And in the OnCollision Handler, I would do something like this

IGameObject obj1 = (IGameObject)geom1.Tag;
IGameObject obj2 = (IGameObject)geom2.Tag;

then compare obj1.ObjectType to the Types that i expect, then cast it again to that Type, & call the corresponding method.

Hope that helps, & I'm not using something that should be avoided.

 

Feb 2, 2010 at 7:54 PM

Confirmed - I just tried what nab477 suggested and it works.

In the constructor of my player object, after its geom is created:

Geom.Tag = this;

And then then to check the collision (e.g. in a powerup object)

       private bool OnCollision(Geom geometry1, Geom geometry2, ContactList contactlist)
        {
            if(geometry2.Tag is Player)
            {
                PickUp();
            }
            return true;
        }
(I think the cast is only necessary if you want to call a specific method on the other object as well, which is not the case in my example)

I Guess it's so simple I didn't think about it... I can't see any downsides to this approach at the moment.

Feb 5, 2010 at 6:55 PM

I also use the Tag attribute and cast it to the appropriate type when needed.

It works like a charm.