Is there any possibilty to get the same collision events from Box2D as from Bullet?
I am pretty infamiliar with Box2D physics… In fact, I started to work with it today.
Upd: Damn, I somehow missed PhysicsEvents2D
/_-
Solved.
Is there any possibilty to get the same collision events from Box2D as from Bullet?
I am pretty infamiliar with Box2D physics… In fact, I started to work with it today.
Upd: Damn, I somehow missed PhysicsEvents2D
/_-
Solved.
Huh. How to parse b2Contact at the script side?
Shall I write some wrappers for it?
There is no chance to make real Box2D game on scripts currently. For example to make one side platforms I redefine PhysicsWorld2D class and compare pointers to shapes to detect collision player sensors with ground and walls
Is my PR similar to your changes in Urho2D?
I see.
IMO, my way is cleaner.
However, I still feel a bit uncomfortable about that HashSet of contacts and its cleanup…
class OneSidePlatform : ScriptObject
{
void Start()
{
SubscribeToEvent(node, "NodeUpdateContact2D", "HandleNodeUpdateContact2D");
}
void HandleNodeUpdateContact2D(StringHash eventType, VariantMap& eventData)
{
Node@ otherNode = eventData["OtherNode"].GetPtr();
VectorBuffer points = eventData["ContactPoints"].GetBuffer();
Vector2 contactPosition = points.ReadVector2();
Vector2 contactNormal = points.ReadVector2();
if (contactNormal.y < 0.5)
eventData["Enabled"] = false;
}
}
Box2D uses own memory allocator for hundreds created/destroy contacts. So I think copying its to own structures/adding to lists destroys the whole idea. I have no idea how to combine speed and convenience. May be using Box2D memory allocator for own purposes.
EDIT:
I don’t copy contacts, I just strore pointers.
Moreover, I store pointers only for contacts that are disabled on client side.
My concern is about HashSet clenup. Box2D may skip EndContact in some artificail cases, and such contact will stay in HashSet forever:
Note: if you set the number of contact points to zero, you will not get an EndContact callback
I think I shall do something with it before merging PR…
This is even worse: http://box2d.org/manual.pdf
Caution
Do not keep a reference to the pointers sent to b2ContactListener. Instead make a
deep copy of the contact point data into your own buffer. The example below
shows one way of doing this.
Huh. That sounds bad.
Unfortunatelly, they don’t explain why and what will happen if I do.
They suggest to copy interesting data from contact, but I have no interest in contact content. I need to somehow identify contact in-between. If Box2D has no way to do it, these callbacks are piece of ship.
I shall probably ask on Box2D forum…
I think we should just allow Box2D to re enable contacts every frame. It is documented behavior and used everywhere. Islands and forces also cleared every step.
/// Enable/disable this contact. This can be used inside the pre-solve
/// contact listener. The contact is only disabled for the current
/// time step (or sub-step in continuous collisions).
void SetEnabled(bool flag);
Anyway you can not just disable contact and forget about him. For one side platform you should check conditions every step and enable/disbale collisions. If you want two bodies to never interact, then you better use collision categories and groups
This sounds reasonable.
However, I don’t know how to walk around this malicious re-enabling if I make one-side platform.
I can correctly check normal of contact only on the very first step. After that I have no relevant information about the contact.
Then please help me to rewrite this to something logically equivalent:
void HandleNodeUpdateContact2D(StringHash eventType, VariantMap& eventData)
{
Node@ otherNode = eventData["OtherNode"].GetPtr();
VectorBuffer points = eventData["ContactPoints"].GetBuffer();
Vector2 contactPosition = points.ReadVector2();
Vector2 contactNormal = points.ReadVector2();
if (contactNormal.y < 0.5)
eventData["Enabled"] = false;
}
Note that I don’t know anything about object shapes here.
I do not understand why this works. In my tests normal can be directed in opposite directions randomly.
Then please help me to rewrite this to something logically equivalent:
Why not official method? https://github.com/erincatto/Box2D/blob/master/Box2D/Testbed/Tests/OneSidedPlatform.h
Wow. Why? Or maybe I just was lucky… But I always had good normals.
This doesn’t matter, actually. I may check position and it would be really meaningful only on the first iteration.
Because
position.y < m_top + m_radius - 3.0f * b2_linearSlop
what’s this piece of shit and how does it work for e.g. rotating box actor?
I was not interested in the case for a rotated box (my character always vertical), but I think there’s no problem in finding out the bottom coordinate of the transformed box.
I want one-way obstacle to work with any simulated object with unknown shape.
So… I can’t imagine how to make this code generic enough.
And anyway… This is so dirty. Real check is trivial - if begin point of the contact is on passable side, ignore this contact forever. I want to make the same (so simple!) logic in Box2D.
I want one-way obstacle to work with any simulated object with unknown shape.
if contact exists, you can use AABB to get bottom coord
Box2D author may get medal of the most awkward architecture.
Small bugfeature that breaks ton of possibilities. Great.
Rigid body don’t have AABB in its API.
b2Shape::ComputeAABB()
What about diagonal platforms?
I will repeat, I was not interested in this question on practice, and I can not quickly answer this question, how to effectively deal with the situation, if both shapes are transformed
I understood. I am just trying to find nice solution.
Do you know how to match BeginContact and EndContact if Box2D recommend not to store pointers on contacts?
fixtures can contain user data SetUserData (currently it is pointer to Urho3D::CollisionShape2D)
but currently has no way to identify urho’s components, so I compare pointers
void PlayerLogic::HandleNodeBeginContact2D(StringHash eventType, VariantMap& eventData)
{
using namespace NodeBeginContact2D;
CollisionShape2D* shape = (CollisionShape2D*)eventData[P_SHAPE].GetPtr();
CollisionShape2D* otherShape = (CollisionShape2D*)eventData[P_OTHERSHAPE].GetPtr();
if (shape == bottomSensor_)
bottomSensorContacts_.Push(otherShape);
}
void PlayerLogic::HandleNodeEndContact2D(StringHash eventType, VariantMap& eventData)
{
using namespace NodeBeginContact2D;
CollisionShape2D* shape = (CollisionShape2D*)eventData[P_SHAPE].GetPtr();
CollisionShape2D* otherShape = (CollisionShape2D*)eventData[P_OTHERSHAPE].GetPtr();
if (shape == bottomSensor_)
bottomSensorContacts_.Remove(otherShape);
}