Damage Detection

Apr 18, 2009 at 4:49 PM
I have a class called Projectile which has a Body and a Geom as well as int damage. I have another class called PhysicsObject which has a Body and a Geom as well as an int health. I have it so that when a Projectile collides with a PhysicsObject, the PhysicsObject Geom no longer collides with anything and just falls off the screen in an OnCollision method. What I want is for the Projectile to do a certain amount of damage to the health of the PhysicsObject. I know collisions detect when one geom collides with another geom, but I have no idea how to make it so that when Projectile collides with PhysicsObject,

PhysicsObject.health -= Projectile.damage;

in the OnCollision method, I only have geom1 (projectile) and geom2(physicsobject) but I cant just do geom2.health -= geom1.damage. Maybe this has something to do with the contact list? I am sorry if this is just a noobie question, but I have no idea how I should do this. Thanks a lot for all your work.
Apr 19, 2009 at 3:41 AM
I assume you're using the tags on geoms? If you are, you need to check if geom1 is a physics object and geom2 is a projectile, or vice versa and do the proper steps based on the order of geoms passed in. You can check by going PhysicsObject o1 = (geom1.Tag as PhysicsObject); or similar.
Apr 19, 2009 at 4:19 AM
I seem to have hit the wrong button and lost my long reply.

        // Projectile Collision
        private bool OnCollision(Geom geom1, Geom geom2, ContactList contactList)
            // Spear (Will generalize to any type of projectile later)
            Projectile s = (Projectile)geom1.Tag;

            //Remove the collision event
            geom1.OnCollision -= OnCollision;

            //Disable the body
            geom1.Body.Enabled = false;
            // Register damage if geom2 is in Category that can take damage
            if (geom2.CollisionCategories == CollisionCategory.Cat4)
                if (geom2.Tag is PhysicsObject)
                    PhysicsObject unit;
                    Projectile projectile;
                    unit = (PhysicsObject)geom2.Tag;
                    projectile = (Projectile)geom1.Tag;
                    unit.health -= projectile.damage;
            //Insert the spear back to the pool

            //Remove it from drawing list

            //Cancel the collision since we are removing the geom from simulation.
            return false;

I think I figured out how to register damage, it seems to work basically. However, it takes more hits than it should to kill an enemy. Even if I set geom2.Enabled to false in the event it is hit by a spear, it takes a few hits. The spears are no longer drawn and added back to their pool correctly whenever they hit a ship, but the ship(geom2) does not always react. Is this a problem with ordering in the method I have? The collision still registers, but it seems to take a couple of hits to make it happen, even though the spear disappears each time. I will make it play a sound in a collision just to confirm it is actually colliding. Maybe I should shrink the grid size? Thanks
Apr 19, 2009 at 4:36 AM
Oh yeah, while I am on the subject. I followed to guides to use the Pool for my Enemy and Projectile units, and it works well, but the whole game crashes if I use more than is in the Pool.  How can I protect against this? If I shoot spears and let them all hit the water or an enemy before firing many more, I can shoot them an infinite number of times. If I shoot them all really quickly, and the Pool has no more left in it, my game just crashes.

       Projectile spearTemp = spear.Fetch();
       spearTemp.Update(projectileAngle, playerShip.body);                 <-----This calls it...

        public void Update(float projectileAngle, Body sbody)
                      // Spear does not collide with playerShip
                geom.CollisionCategories = CollisionCategory.Cat2;           <----- Error Points to here and says  Object reference not set to an instance of an object.

I understand that it is trying to fetch a spear that does not exist, the error is not thrown in the Fetch(), but how do I see if one exists in the Pool before it allows it to Update?
Apr 19, 2009 at 7:53 AM
Edited Apr 19, 2009 at 7:57 AM
you could just do a foreach iteration on each projectile and physics object

foreach(Projectile a in PlayerProjectiles)
foreach(physicsObject b in Enemies)
if(a.geom.CollisionResponseEnabled == true)
b.health - b.damage;

this would handle every projectile and enemy in the game,
of course this depends on if you have some sort of collection for the projectiles of the player and the enemies(list, array, etc)

edit: The collision response enabled check is because you said you disabled it when it collided, you could check alive and set it to dead when it collides.
This is to make sure it decreases health only once.
Apr 19, 2009 at 8:32 AM
About your other problem: you should have a if (spearTemp != null) around the update call. Don't take my word for it though, but i'm pretty sure that will help.
Apr 19, 2009 at 4:13 PM
I'm not sure about the multiple damage issue, although you do remove the spear regardless of what it's collided with, so maybe there is something else (other than units) triggering your collision callback?

Also, I had a similar issue with the Pool<T> class... I just made my own version called Cache<T> to avoid name conflicts. It was just a copy of Pool<T> but I added a Count property:

        public int Count { get { return _stack.Count; } }

Apr 21, 2009 at 7:16 AM
I tried the if (spearTemp != null) but same error still happened after I fired too many arrows. I was sure it would work before I did it. Thanks roonda, that's a good idea, that should hopefully work, it's nice knowing the count either way. Yes, each time a spear collides with anything, it is removed and added back into the pool. Also, it looks like mostly when the spear collides with a ship, it will be pushed by the collision, but sometimes it does not seem to react besides the spear appearing to dissappear. It collides but does not trigger the method to do damage for some reason. The ship remains in the same collision category until its health reaches 0, so it should register each time.
Apr 21, 2009 at 7:43 AM
Thanks a lot, the count thing worked great, now there is just a small gap between spears when I fire them quickly instead of a crash. Farseer should add the count in the Pool, it's ever so useful.
Apr 21, 2009 at 1:30 PM
Edited Apr 21, 2009 at 1:56 PM
Yeah I agree, the default Farseer Pool<T> should definitely have a Count property. Hint hint Genbox :)

Just checking for (spear != null) doesn't work because the pool returns a "new T()" instead of null if the internal stack is empty in Fetch(). So the crash was probably because those spears haven't been initialised properly. I guess in some cases it would be nice to have the pool return null, so it can't get bigger than a certain size.

Just for kicks, I thought I'd add some functionality to the Pool class. I haven't actually used it yet, but it has an optional delegate for initializing new objects.

    public class Pool<T> where T : new()
        private Stack<T> _stack;
        private bool _canGrowPool = true; // preserve current behaviour
        public bool CanGrowPool
            get { return _canGrowPool; }
            set { _canGrowPool = value; }
        // Allow users to specify an init method for new objects
        public System.Action<T> InitMethod { get; set; }
        public int Count { get { return _stack.Count; } }

        public Pool()
            _stack = new Stack<T>();
        public Pool(int size)
            _stack = new Stack<T>(size);
            for (int i = 0; i < size; i++)
                _stack.Push(new T());

        public T Fetch()
            if (_stack.Count > 0)
                return _stack.Pop();

            if (_canGrowPool)
                T newObj = new T();

                // call initialise method if it exists
                if (InitMethod != null)

               return newObj;
            return default(T);

        public void Insert(T item)

Apr 21, 2009 at 3:48 PM
The idea behind a pool is actually to pre-create all instances of a class. You can do this in 2 ways:

1. Make the pool instantiate all the objects by giving it the number of objects needed. (Create pool with size)
2. Create all the objects your self and insert them into the pool. (Create the pool without a size)

Because it's based on a stack, you can add and remove to it all the time. This of course only applies to the top of the stack (Last In, First Out (LIFO) concept)
This also means that whenever you are done with an object, you should insert it back into the pool.

As for the Count property, I can't see the harm in not adding it. The initialize method kinda defeats of the purpose of pre-creating all time consuming objects, but it someone might have the use of a strongly typed initialize method. Can I add it to the pool class?
Apr 22, 2009 at 12:42 AM
Genbox, by "I can't see the harm in not adding it", do you mean "I can't see the harm in adding it"? I can't see how you can properly use the Pool without it - you have no way of knowing whether you are grabbing an object you inserted or one that the pool created, unless perhaps you put an "IsInitialized" property on your objects. I also think that the option for allowing the Pool to grow or not would be useful.

I do see what you mean about the initialize defeating the pre-creation purpose of the pool, but I can still see it being useful. For example you may want a Pool that can grow dynamically, but the objects need to be initialized. That initialization may take a little while, but only on the first time the pool returns a new object - after that it would be instant. Obviously it can be done without the pool, but it's nice to encapsulate it in the pool. That said, I personally haven't reached the point where I need it (but think I will). I suppose the drawback is that it makes the pool less simple and possibly confuses the user.