Impact

This forum is read only and just serves as an archive. If you have any questions, please post them on github.com/phoboslab/impact

10 years ago by quidmonkey

I believe the physics demo still uses Box2d 2.0.2, but I think Dom updated the demo recently so that it's using Impact 1.20 or 1.21. To use the plugin, simply require it in your main.js:

ig.module( 
	'game.main' 
)
.requires(
	'impact.game',

	'plugins.box2d.collision',

    // more code

Be sure to add collision.js into the plugins/box2d/ directory.

10 years ago by quidmonkey

Quote from number101010
However, I think with some more work the res object could be rebuilt from the information available and the correct function call could be made.


Great idea!

This is untested, but something like this might work:
if (!a || !b) {
    var ent = !a ? b : a,
        res = {
        collision: {x: false, y: false, slope: false},
        pos: null,
        slopeAngle: null,
        tile: null
    };

    res.pos = {
        x: (ent.pos.x / b2.SCALE - ent.size.x / 2),
        y: (ent.pos.y / b2.SCALE - ent.size.y / 2)
    },

    if (Math.abs(point.normal.x) === 1) {
        pos.x += ent.vel.x > 0 ? ent.size.x : 0;
        res.collision.x = true;
    } else if (point.normal.x) {
        res.collision.slope = true;
        res.slopeAngle = Math.atan2(point.normal.x, -point.normal.y); // atan of normal orthogonal
    }

    if (Math.abs(point.normal.y) === 1) {
        pos.y += ent.vel.y > 0 ? ent.size.y : 0;
        res.collision.y = true;
    } else if (point.normal.y) {
        res.collision.slope = true;
        res.slopeAngle = Math.atan2(point.normal.x, -point.normal.y); // atan of normal orthogonal
    }

    res.tile = ig.game.collisionMap.getTile(pos.x, pos.y);

    ent.handleMovementTrace(res);
    return;
}

Be aware you don't want to use the base handleMovementTrace logic because your entity is already being moved by box2d. I also added a .slopeAngle to the res object for those who might be interested in something like that.

10 years ago by Neerav

I was looking for ways to detect collision in box2D and found your plugin. Although I am yet to try it for what i want to do with it, I wanted to ask , do you think this would work with the box2d 2.1a version ? Is it a good idea to use the box2d 2.1a in general ?

10 years ago by Neerav

So I decided not to move to Box2D 2.1a, as it would require a lot of refactoring and we do not foresee much use of new features. But now I am stuck as I was trying to extend functionality of your plugin. I wanted to have callback from b2.ContactLisener.Remove method in plugins/box2d/collision.js. This is what I am trying

listener.Remove = function(point){
            var a = point.shape1.GetBody().entity,
                b = point.shape2.GetBody().entity;

            // is this an entity collision?
            if (!a || !b) {
                return;
            }

            // preserve impact's entity checks even
            // though these are unnecessary
            if (a.checkAgainst & b.type) {
                a.check(b);
            }

            if (b.checkAgainst & a.type) {
                b.check(a);
            }

            // call impact
            if (point.normal.y) {
                a.collideExit(b, 'y',point);
                b.collideExit(a, 'y',point);
            }
            else {
                a.collideExit(b, 'x', point);
                b.collideExit(a, 'x', point);
            }
        };

Even though I have collideExit defined in my Entity ( extended from Box2DEntity) I am getting ' function not defined' error.

I am new to Object Oriented Javascript and Impact so please feel free to redirect me to any relevant tutorial or jargon I should be searching on the internet.

Thanks in Advance

10 years ago by quidmonkey

Did you add the .collideExit() to all Box2dEntities or a single entity?

10 years ago by Neerav

I added it to single entity extending from box2DEntity. In my game there is only one type of entity that is involved in the collision, and it has the method. I tried to debug the code and I could see the function in the entity object that is added to the body by collision.js, but when it comes to this section (listener.Remove) of code the entity no longer has the function inside the entity object.

10 years ago by quidmonkey

The plugin will detect collisions between all Entities, not necessarily just the single entity you extended from Box2dEntity. Notice this line:
if (!a || !b) {
     return;
}

The collision plugin won't do anything unless both Entities involved are Box2dEntities. Thus, one of your Entities is your extended Entity, which contains the collideExit() method, while the other does not, and thus, the function is undefined.

What you'll want to do is define a collideExit for all Box2dEntities by changing the .inject in the plugin to this:
ig.Box2DEntity.inject({

    init: function (x, y, settings) {
        this.parent(x, y, settings);
        if (!ig.global.wm) {
            this.body.entity = this;
        }
    },

    collideExit: function (ent, axis, point) {}

});

This way every Box2dEntity will have the function defined, but can override it to do the logic it needs.

10 years ago by Neerav

Thank you for the reply. I tried doing what you have suggested, although I do not get any error now. The code does not reach the overridden piece of class. Here is how my code looks like ...

ig.module(
    'game.entities.rock'
)
.requires(
    'plugins.box2d.entity',
    'plugins.box2d.collision'

)
.defines(function(){
    
    ig.ROCKSTATES = {
        'INITIAL'   : 1,
        'SELECTED'  : 2,
        'ONBEAM'    : 3
    };

    EntityRock = ig.Box2DEntity.extend({
        
        size:{ x:53, y:50 },////gus
        currRockState : ig.ROCKSTATES.INITIAL,
        .
        .
        .
        .
        collideWith:function(other,axis,point) {
            console.log("[ENTER}Is Shape1 Sensor" + point.shape1.IsSensor() + " Is Shape2 Sensor" + point.shape2.IsSensor());

        },
        collideExit:function(other,axis,point) {
            console.log("{EXIT]Is Shape1 Sensor" + point.shape1.IsSensor() + " Is Shape2 Sensor" + point.shape2.IsSensor());
        },
    });
})

Let me know If you would like to see the whole code. The Inject part of collision.js is exactly the way you have put int he earlier post.

10 years ago by quidmonkey

Neerav-

In your previous post you stated, "In my game there is only one type of entity that is involved in the collision, and it has the method." Is this still the case? Is this an entity vs. entity (dynamic) collision, or is this entity vs. collision map (static) collision?

10 years ago by Neerav

It is a entity(EntityBeam) vs entity(EntityRock) collision, both of them are dynamic, actually both of them are extended from box2DEntitiy. Beam entitly does not have "collideExit" method overidden, Rock entity has it overridden (as pasted above). The beam entity has two shapes attached to it, one of which is marked as a sensor. I am trying to detect when a rock enters the beam, which works great thanks to your plugin. the plugin does not call the overridden method in the rock when it detects the collision exit , instead it calls the injected code(for both of them).

I saw that you store the entity inside the body and then call methods on that entity, could this be the reason of injected code being called ?

10 years ago by quidmonkey

Neerav-

You'll want to update my plugin directly with your logic (remove my old logic):
ig.Box2DEntity.inject({

    init: function (x, y, settings) {
        this.parent(x, y, settings);
        if (!ig.global.wm) {
            this.body.entity = this;
        }
    }

});

ig.Box2DGame.inject({

    // remove impact's collision detection
    // for performance
    checkEntities: function () {},

    loadLevel: function (data) {
        this.parent(data);

        // create impact collision listener
        var listener = new b2.ContactListener();
        listener.Add = function(point){
            var a = point.shape1.GetBody().entity,
                b = point.shape2.GetBody().entity;

            // is this an entity collision?
            if (!a || !b) {
                return;
            }

            // preserve impact's entity checks even
            // though these are unnecessary
            if (a.checkAgainst & b.type) {
                a.check(b);
            }
            
            if (b.checkAgainst & a.type) {
                b.check(a);
            }

            // call impact
            if (point.normal.y) {
                a.collideExit(b, 'y', point);
                b.collideExit(a, 'y', point);
            }
            else {
                a.collideExit(b, 'x', point);
                b.collideExit(a, 'x', point);
            }
        };

        // attach to box2d world
        ig.world.SetContactListener(listener);
    }

});

Are you also certain you want a .Remove listener? I would think you'd want to use the .Add listener, especially since you want the event handled when the rock enters the beam vs. leaving it. See this video to explain the difference.

10 years ago by Neerav

I have done exactly that, I have updated your logic to call events for both add and remove. I my case I need to know both the cases of add and remove, hence I have both the things. When the rock comes closer to beam and when it leaves. What puzzles me is that collideExit is not called in the derived class. I think I will have to dig deeper to figure out what exactly is happening

10 years ago by Neerav

Hi there,
I found out where my mistake was, while injecting into Box2DEntity adds method "collideExit" to it, it was not setting the proper object with 'this' keyword. Hence in the init method of my extended entity(EntityRock & EntityBeam), I added this line
this.body.entity = this;

It stil was'nt working 100% for me , and digging a little bit into plugins/box2D/lib.js I found a bug where both the shapes involved in to collision were being set to the same body. After fixing this .. it worked out for me.

Thank you quidmonkey for all the help and the plugin !

9 years ago by Joncom

check does not behave the way it would with a vanilla copy of ImpactJS. A player entity can sit atop a pile of the entity it's checking for, but once the pile comes to a rest, check is no longer called.

Edit 1:

The same is true when Box2D bodies are not allowed to sleep.
var allowSleep = false;
var world = new b2.World( worldBoundingBox, gravity, allowSleep );

Edit 2:

The collideWith method seems to sometimes report unusual data.

collideWith: function(other, axis) {
    console.log("Collided with entity on axis: " + axis);
}

This will sometimes report a collision on y when two entities standing on the ground bump into each other from the side.

Edit 3:

I noticed this code in the plugin:
// remove impact's collision detection
// for performance
checkEntities: function () {},

Just curious if this is a good idea? Because this would prevent checks from working properly between non-Box2D-entities. Perhaps a non-issue because maybe it can be assumed that all entities will be Box2D entities...

Edit 4:

Also, as Xatruch pointed out:
A very important point to note if you do this, is that the existence of a contact in these lists does not mean that the two fixtures of the contact are actually touching - it only means their AABBs are touching. If you want to know if the fixtures themselves are really touching you can use IsTouching() to check.
It does not appear that this is presently accounted for. Meaning cases like this will still pop up as collisions, which really should not:

/>			</div>
		</div>
			<div class=

9 years ago by quidmonkey

Great work, Joncom. I updated the plugin to add a greater penetration check for your Edit 2, so that collideWith gets called on the axis where the overlap is the greatest. It's live on github.

Do you have any suggestions in regards to Edit 4? I believe the .isTouching() method is a 2.1 feature.

9 years ago by paulh

use the bounding boxes to trigger a Collision "alert", then check for the is touching?

9 years ago by Joncom

Quote from quidmonkey
Do you have any suggestions in regards to Edit 4? I believe the .isTouching() method is a 2.1 feature.
Yeah, it appears that .isTouching is not included with Box2D 2.0.2...
Will investigate to determine if there's another way.

Edit 1

Also, because ImpactJS makes no distinction between "new contact" and "persisting contact", usual functionality of check may be restored via the following:

var handleContact = function(point) {
    var a = point.shape1.GetBody().entity,
        b = point.shape2.GetBody().entity;

    // is this an entity collision?
    if (!a || !b) {
        return;
    }

    // preserve impact's entity checks even
    // though these are unnecessary
    if (a.checkAgainst & b.type) {
        a.check(b);
    }

    if (b.checkAgainst & a.type) {
        b.check(a);
    }

    // call impact
    // favor the axis of greater penetration
    if (Math.abs(point.normal.y) > Math.abs(point.normal.x)) {
        a.collideWith(b, 'y');
        b.collideWith(a, 'y');
    } else {
        a.collideWith(b, 'x');
        b.collideWith(a, 'x');
    }
};

var listener = new b2.ContactListener();
listener.Add = handleContact;
listener.Persist = handleContact;

Edit 2:

It turns out I was wrong when I said that contact points don't necessarily means the objects are touching. ContactListeners only call the callback method if there's a real touch. That other quote was actually talking about manually looping through the world's contact list, which is something else entirely.

This will not trigger check calls:

/><br />
<br />
This will trigger <code>check</code> calls:<br />
<br />
<img src=

9 years ago by Joncom

Non-issue, removed.

9 years ago by quidmonkey

Thanks for your help, Joncom! I pushed the persist listener change and updated the documentation. Finally, I added you to the list of thanks.

8 years ago by Seeders

I am unable to detect any collisions at all using this plugin.

I added a line to the loadLevel function in ig.Box2DGame.inject:

loadLevel: function (data) {
            this.parent(data);
            var handleContact = function (point) {
                var a = point.shape1.GetBody().entity,
                    b = point.shape2.GetBody().entity;

                console.log("a,b : " + a + ", " + b);
                // is this an entity collision?
                if (!a || !b) {
                    return;
                }

                // preserve impact's entity checks even
                // though these are unnecessary
                if (a.checkAgainst & b.type) {
                    a.check(b);
                }

                if (b.checkAgainst & a.type) {
                    b.check(a);
                }
                // call impact
                // favor the axis of greater penetration
                if (Math.abs(point.normal.y) > Math.abs(point.normal.x)) {
                    a.collideWith(b, 'y');
                    b.collideWith(a, 'y');
                } else {
                    a.collideWith(b, 'x');
                    b.collideWith(a, 'x');
                }
            };

            var listener = new Box2D.Dynamics.b2ContactListener();
            listener.Add = handleContact;      // on first contact
            listener.Persist = handleContact;  // on subsequent contacts

            // attach to box2d world
            ig.world.SetContactListener(listener);
        }

and my console never logs anything. I am simply trying to have bullets that contact enemies.


My Bullet:

    EntityBullet = ig.Box2DEntity.extend({
...
        collideWith : function (other, axis) {
            console.log("collideWith called");
        },
        collideEntity: function (other, point, normal) {
            console.log("collideEntity called");
        },

        collideTile: function (tile, point, normal) {
            console.log(tile, point, normal);
        },
...

My zombie:

EntityZombie = ig.Box2DEntity.extend({
...

		collideEntity: function (other, point, normal) {
		    console.log("zombie collided");
		},
..

Nothing gets logged, but my bullets bounce off the zombies as if they are colliding. I need to catch the collision and remove zombie hp/etc.

You can't fight zombies with potato guns!

8 years ago by Seeders

I had to modify the plugin to get it working for 2.1a:

ig.module(
    'plugins.box2d.collision'
)
.requires(
    'plugins.box2d.entity',
    'plugins.box2d.game'
)
.defines(function () {

    ig.Box2DEntity.inject({

        init: function (x, y, settings) {
            this.parent(x, y, settings);
            if (!ig.global.wm) {
                this.body.entity = this;
            }
        }

    });

    ig.Box2DGame.inject({

        // remove impact's collision detection for performance
        // comment out this line if you're using both
        // ig.Entity and ig.Box2dEntity
        checkEntities: function () { },

        loadLevel: function (data) {
            this.parent(data);
            var handleContact = function (point) {
                if (!point.m_fixtureA || !point.m_fixtureB) {              
                    return;
                }

                var a = point.m_fixtureA.GetBody().entity,
                    b = point.m_fixtureB.GetBody().entity;

                // is this an entity collision?
                if (!a || !b) {
                    return;
                }

                // preserve impact's entity checks even
                // though these are unnecessary
                if (a.checkAgainst & b.type) {
                    a.check(b);
                }

                if (b.checkAgainst & a.type) {
                    b.check(a);
                }
                // call impact
                // favor the axis of greater penetration
                a.collideWith(b);
                b.collideWith(a);
            };

            var handleEndContact = function (point) {
                if (!point.m_fixtureA || !point.m_fixtureB) {
                    return;
                }

                var a = point.m_fixtureA.GetBody().entity,
                    b = point.m_fixtureB.GetBody().entity;

                // is this an entity collision?
                if (!a || !b) {
                    return;
                }

                // preserve impact's entity checks even
                // though these are unnecessary
                if (a.checkAgainst & b.type) {
                    a.check(b);
                }

                if (b.checkAgainst & a.type) {
                    b.check(a);
                }
                // call impact
                // favor the axis of greater penetration
                a.endCollideWith(b);
                b.endCollideWith(a);
            };

            var listener = new Box2D.Dynamics.b2ContactListener();
            listener.Add = handleContact;      // on first contact
            listener.Persist = handleContact;  // on subsequent contacts
            listener.BeginContact = handleContact;
            listener.EndContact = handleEndContact;
            // attach to box2d world
            ig.world.SetContactListener(listener);
        }

    });

});

8 years ago by RockLeo

I got the error:

Uncaught TypeError: undefined is not a function

Line:
// call impact
// favor the axis of greater penetration
a.endCollideWith(b);

I didnt get very well how this works, do I have to use Check from Impact or CollideWith?

8 years ago by Joncom

Quote from RockLeo
I didnt get very well how this works, do I have to use Check from Impact or CollideWith?
I suggest you use this version of the Box2D plugin. It was created, in part, from the code in this thread, and made to be as easy to use as possible. If you use it, check and collideWith will work just like in any other Impact game.

8 years ago by RockLeo

Thx @Joncom, but I tried to use your version and I coundnt get it to work.

I'm not a dev and I fail to code simple stuff lol.

Even the "this.standing" in your plugin didnt work with me.

Thx!

8 years ago by Joncom

Quote from RockLeo
I'm not a dev and I fail to code simple stuff lol.
What error message do you get with this.standing or isn't there one?

8 years ago by RockLeo

Quote from Joncom
What error message do you get with this.standing or isn't there one?


this.standing is always "false", even when player is on the ground.

8 years ago by Joncom

A couple things you can try. Make sure you're calling this.parent() in your update call at some point, preferably first-thing.

If that doesn't work, you can try changing this line from:
if (normal.y < 0) {

to:
if (normal.y > 0) {

and see if that makes a difference.

If no luck, you may want to enable debug by adding to this your main.js requires:
'plugins.joncom.box2d.debug'

That will allow you to see all the Box2D bodies.
Make sure your entities and environment appear where you expect them to be.

By the way, we are off-topic for this thread. For follow-up posts, it might be a good idea to put them here instead...
Page 2 of 2
« first ‹ previous next › last »