Archive 17/01/2023.

Why don’t 2D bodies with a ConstraintPrismatic2D collide in Urho3D despite SetCollideConnected(true)?

cirosantilli

This is a copy of https://discourse.urho3d.io/t/why-dont-2d-bodies-with-a-constraintprismatic2d-collide-in-urho3d-despite-setcollideconnected-true-ask-question/3840 with everything inlined here to remove any political references.

For other types of constraints, e.g. ConstraintRope2D, SetCollideConnected(true) has the expected effect.

However, for ConstraintPrismatic2D, I can’t make the bodies collide when the constraint is applied.

To test this out, take 5e8a2756db27ff88098cab351822c6f2f1ed9ea9 and hack the sample Source/Samples/32_Urho2DConstraints/Urho2DConstraints.cpp so that the prismatic constraint allows both bodies to touch:

// Create a ConstraintPrismatic2D
CreateFlag("ConstraintPrismatic2D", 2.53f, 3.0f); // Display Text3D flag
Node* boxPrismaticNode = box->Clone();
tempBody = boxPrismaticNode->GetComponent<RigidBody2D>(); // Get body to make it static
tempBody->SetBodyType(BT_STATIC);
Node* ballPrismaticNode = ball->Clone();
boxPrismaticNode->SetPosition(Vector3(3.3f, 2.5f, 0.0f));
ballPrismaticNode->SetPosition(Vector3(3.3f, 2.0f, 0.0f));

ConstraintPrismatic2D* constraintPrismatic = boxPrismaticNode->CreateComponent<ConstraintPrismatic2D>();
constraintPrismatic->SetOtherBody(ballPrismaticNode->GetComponent<RigidBody2D>()); // Constrain ball to box
constraintPrismatic->SetAxis(Vector2(0.0f, 1.0f)); // Slide from [0,0] to [1,1]
constraintPrismatic->SetAnchor(Vector2(3.3f, 2.5f));
constraintPrismatic->SetLowerTranslation(-1.0f);
constraintPrismatic->SetUpperTranslation(0.5f);
constraintPrismatic->SetEnableLimit(true);
constraintPrismatic->SetMaxMotorForce(1.0f);
constraintPrismatic->SetMotorSpeed(0.0f);
constraintPrismatic->SetCollideConnected(true);

Now, the anchor and dynamic bodies can be superposed with the mouse, and they don’t collide despite constraintPrismatic->SetCollideConnected(true);.

I have also uploaded a minimalistic test on GitHub: https://github.com/cirosantilli/Urho3D-cheat/blob/e6cc904660fcf89ec558415d7da1f191f38b42f1/prismatic_collide_connected.cpp

Collision works as expected for ConstraintRope2D, which has SetCollideConnected(true); set by default, in the same example if you move the bodies with the mouse.

If I test the same thing on the Box2D testbed, by hacking the Prismatic.h testbed example at f655c603ba9d83f07fc566d38d2654ba35739102
slightly to contain:

#ifndef PRISMATIC_H
#define PRISMATIC_H

// The motor in this test gets smoother with higher velocity iterations.
class Prismatic : public Test
{
public:
	Prismatic()
	{
		b2Body* ground = NULL;
		{
			b2BodyDef bd;
			ground = m_world->CreateBody(&bd);

			b2EdgeShape shape;
			shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
			ground->CreateFixture(&shape, 0.0f);
		}

		{
			b2PolygonShape shape;
			shape.SetAsBox(1.0f, 1.0f);

			b2BodyDef bd;
			bd.type = b2_dynamicBody;
			bd.position.Set(0.0f, 0.0f);
			bd.angle = b2_pi;
			bd.allowSleep = false;
			b2Body* body = m_world->CreateBody(&bd);
			body->CreateFixture(&shape, 5.0f);

			b2PrismaticJointDef pjd;

			// Bouncy limit
			b2Vec2 axis(0.0f, 1.0f);
			axis.Normalize();
			pjd.Initialize(ground, body, b2Vec2(0.0f, 0.0f), axis);

			// Non-bouncy limit
			//pjd.Initialize(ground, body, b2Vec2(-10.0f, 10.0f), b2Vec2(1.0f, 0.0f));

			pjd.motorSpeed = 10.0f;
			pjd.maxMotorForce = 10000.0f;
			pjd.enableMotor = true;
			pjd.lowerTranslation = -20.0f;
			pjd.upperTranslation = 20.0f;
			pjd.enableLimit = true;
			pjd.collideConnected = true;

			m_joint = (b2PrismaticJoint*)m_world->CreateJoint(&pjd);
		}
	}

	void Keyboard(int key)
	{
		switch (key)
		{
		case GLFW_KEY_L:
			m_joint->EnableLimit(!m_joint->IsLimitEnabled());
			break;

		case GLFW_KEY_M:
			m_joint->EnableMotor(!m_joint->IsMotorEnabled());
			break;

		case GLFW_KEY_S:
			m_joint->SetMotorSpeed(-m_joint->GetMotorSpeed());
			break;
		}
	}

	void Step(Settings* settings)
	{
		Test::Step(settings);
		g_debugDraw.DrawString(5, m_textLine, "Keys: (l) limits, (m) motors, (s) speed");
		m_textLine += DRAW_STRING_NEW_LINE;
		float32 force = m_joint->GetMotorForce(settings->hz);
		g_debugDraw.DrawString(5, m_textLine, "Motor Force = %4.0f", (float) force);
		m_textLine += DRAW_STRING_NEW_LINE;
	}

	static Test* Create()
	{
		return new Prismatic;
	}

	b2PrismaticJoint* m_joint;
};

#endif

then those bodies do obey pjd.collideConnected = true; as expected.