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.
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&
039;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.
1 decade 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 ?
1 decade 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
Did you add the .collideExit()
to all Box2dEntities or a single entity?
1 decade 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.
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.
1 decade 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.
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?
1 decade 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 ?
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.
1 decade 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
1 decade 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 !
1 decade 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&
039;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:
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.
1 decade ago
by paulh
use the bounding boxes to trigger a Collision "alert", then check for the is touching?
1 decade 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:
1 decade ago
by Joncom
Non-issue, removed.
Thanks for your help, Joncom! I pushed the persist listener change and updated the documentation. Finally, I added you to the list of thanks.
1 decade 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!
1 decade 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);
}
});
});
1 decade 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?
1 decade 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.
1 decade 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!
1 decade ago
by Joncom
Quote from RockLeo
I&039;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?
1 decade 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.
1 decade ago
by Joncom
A couple things you can try. Make sure you&
039;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...