7#include <Box2D/Box2D.h>
32 runtimeHandle_(runtimeHandle),
38bool Joint2D::isValid()
const {
return joint_ !=
nullptr && world_ !=
nullptr && world_->
raw() !=
nullptr; }
47 gearJoint1_ =
nullptr;
48 gearJoint2_ =
nullptr;
58 std::vector<Joint2D *> gears;
59 for (
Joint2D *candidate : world_->joints_) {
60 if (!candidate || candidate->kind_ !=
Kind::Gear || !candidate->isValid())
continue;
61 if (candidate->gearJoint1_ ==
this || candidate->gearJoint2_ ==
this)
62 gears.push_back(candidate);
64 for (
Joint2D *gear : gears) gear->destroy();
66 world_->
raw()->DestroyJoint(joint_);
96 if (collide != joint_->GetCollideConnected())
98 "Joint2D.setCollideConnected: collideConnected is fixed at creation for Box2D joints");
102 return isValid() ? joint_->GetCollideConnected() :
false;
105void Joint2D::requireKind(Kind expected,
const char *
operation)
const {
112 nonNegative(lengthPixels,
"Joint2D.setDistanceLength",
"length");
113 static_cast<b2DistanceJoint *
>(joint_)->SetLength(world_->
toMeters(lengthPixels));
117 return world_->
toPixels(
static_cast<b2DistanceJoint *
>(joint_)->GetLength());
121 nonNegative(frequencyHz,
"Joint2D.setDistanceSpring",
"frequencyHz");
122 nonNegative(dampingRatio,
"Joint2D.setDistanceSpring",
"dampingRatio");
123 auto *
distance =
static_cast<b2DistanceJoint *
>(joint_);
124 distance->SetFrequency(frequencyHz);
125 distance->SetDampingRatio(dampingRatio);
129 return static_cast<b2DistanceJoint *
>(joint_)->GetFrequency();
133 return static_cast<b2DistanceJoint *
>(joint_)->GetDampingRatio();
138 finite(lower,
"Joint2D.setRevoluteLimits",
"lower");
139 finite(upper,
"Joint2D.setRevoluteLimits",
"upper");
141 throw eve::Exception(
"Joint2D.setRevoluteLimits: lower must be <= upper");
142 auto *revolute =
static_cast<b2RevoluteJoint *
>(joint_);
143 revolute->SetLimits(lower, upper);
144 revolute->EnableLimit(
enabled);
148 finite(speed,
"Joint2D.setRevoluteMotor",
"speed");
149 nonNegative(maxTorque,
"Joint2D.setRevoluteMotor",
"maxTorque");
150 auto *revolute =
static_cast<b2RevoluteJoint *
>(joint_);
151 revolute->SetMotorSpeed(speed);
152 revolute->SetMaxMotorTorque(maxTorque);
153 revolute->EnableMotor(
enabled);
157 return static_cast<b2RevoluteJoint *
>(joint_)->GetJointAngle();
161 return static_cast<b2RevoluteJoint *
>(joint_)->GetJointSpeed();
165 return static_cast<b2RevoluteJoint *
>(joint_)->GetMotorTorque(1.f / 60.f);
170 finite(lowerPixels,
"Joint2D.setPrismaticLimits",
"lower");
171 finite(upperPixels,
"Joint2D.setPrismaticLimits",
"upper");
172 if (lowerPixels > upperPixels)
173 throw eve::Exception(
"Joint2D.setPrismaticLimits: lower must be <= upper");
174 auto *prismatic =
static_cast<b2PrismaticJoint *
>(joint_);
175 prismatic->SetLimits(world_->
toMeters(lowerPixels), world_->
toMeters(upperPixels));
176 prismatic->EnableLimit(
enabled);
180 finite(speedPixels,
"Joint2D.setPrismaticMotor",
"speed");
181 nonNegative(maxForcePixels,
"Joint2D.setPrismaticMotor",
"maxForce");
182 auto *prismatic =
static_cast<b2PrismaticJoint *
>(joint_);
183 prismatic->SetMotorSpeed(world_->
toMeters(speedPixels));
184 prismatic->SetMaxMotorForce(world_->
toMeters(maxForcePixels));
185 prismatic->EnableMotor(
enabled);
189 return world_->
toPixels(
static_cast<b2PrismaticJoint *
>(joint_)->GetJointTranslation());
193 return world_->
toPixels(
static_cast<b2PrismaticJoint *
>(joint_)->GetJointSpeed());
197 requireKind(
Kind::Weld,
"Joint2D.setWeldSpring");
198 nonNegative(frequencyHz,
"Joint2D.setWeldSpring",
"frequencyHz");
199 nonNegative(dampingRatio,
"Joint2D.setWeldSpring",
"dampingRatio");
200 auto *weld =
static_cast<b2WeldJoint *
>(joint_);
201 weld->SetFrequency(frequencyHz);
202 weld->SetDampingRatio(dampingRatio);
205 requireKind(
Kind::Weld,
"Joint2D.getWeldFrequency");
206 return static_cast<b2WeldJoint *
>(joint_)->GetFrequency();
209 requireKind(
Kind::Weld,
"Joint2D.getWeldDampingRatio");
210 return static_cast<b2WeldJoint *
>(joint_)->GetDampingRatio();
214 requireKind(
Kind::Wheel,
"Joint2D.setWheelSpring");
215 nonNegative(frequencyHz,
"Joint2D.setWheelSpring",
"frequencyHz");
216 nonNegative(dampingRatio,
"Joint2D.setWheelSpring",
"dampingRatio");
217 auto *wheel =
static_cast<b2WheelJoint *
>(joint_);
218 wheel->SetSpringFrequencyHz(frequencyHz);
219 wheel->SetSpringDampingRatio(dampingRatio);
223 finite(speed,
"Joint2D.setWheelMotor",
"speed");
224 nonNegative(maxTorque,
"Joint2D.setWheelMotor",
"maxTorque");
225 auto *wheel =
static_cast<b2WheelJoint *
>(joint_);
226 wheel->SetMotorSpeed(speed);
227 wheel->SetMaxMotorTorque(maxTorque);
231 requireKind(
Kind::Wheel,
"Joint2D.getWheelTranslation");
232 return world_->
toPixels(
static_cast<b2WheelJoint *
>(joint_)->GetJointTranslation());
236 return static_cast<b2WheelJoint *
>(joint_)->GetJointSpeed();
240 requireKind(
Kind::Motor,
"Joint2D.setMotorLinearOffset");
241 finite(xPixels,
"Joint2D.setMotorLinearOffset",
"x");
242 finite(yPixels,
"Joint2D.setMotorLinearOffset",
"y");
243 static_cast<b2MotorJoint *
>(joint_)->SetLinearOffset(
247 requireKind(
Kind::Motor,
"Joint2D.setMotorAngularOffset");
248 finite(radians,
"Joint2D.setMotorAngularOffset",
"radians");
249 static_cast<b2MotorJoint *
>(joint_)->SetAngularOffset(radians);
252 requireKind(
Kind::Motor,
"Joint2D.setMotorLimits");
253 nonNegative(maxForcePixels,
"Joint2D.setMotorLimits",
"maxForce");
254 nonNegative(maxTorque,
"Joint2D.setMotorLimits",
"maxTorque");
255 auto *motor =
static_cast<b2MotorJoint *
>(joint_);
256 motor->SetMaxForce(world_->
toMeters(maxForcePixels));
257 motor->SetMaxTorque(maxTorque);
260 requireKind(
Kind::Motor,
"Joint2D.getMotorLinearOffsetX");
261 return world_->
toPixels(
static_cast<b2MotorJoint *
>(joint_)->GetLinearOffset().
x);
264 requireKind(
Kind::Motor,
"Joint2D.getMotorLinearOffsetY");
265 return world_->
toPixels(
static_cast<b2MotorJoint *
>(joint_)->GetLinearOffset().
y);
268 requireKind(
Kind::Motor,
"Joint2D.getMotorAngularOffset");
269 return static_cast<b2MotorJoint *
>(joint_)->GetAngularOffset();
273 requireKind(
Kind::Gear,
"Joint2D.setGearRatio");
274 if (!std::isfinite(ratio) || std::fabs(ratio) < 1e-8f)
275 throw eve::Exception(
"Joint2D.setGearRatio: ratio must be finite and non-zero");
276 static_cast<b2GearJoint *
>(joint_)->SetRatio(ratio);
279 requireKind(
Kind::Gear,
"Joint2D.getGearRatio");
280 return static_cast<b2GearJoint *
>(joint_)->GetRatio();
ActionParameterOperation operation
EVENGINE_API_FOUNDATION public API.
static constexpr RuntimeHandle invalid() noexcept
Returns the canonical invalid handle.
2D rigid body (Box2D) in pixel-space coordinates. Owned by a World; create shapes with newRectangleFi...
int getId() const
Stable id used by contact/impact events.
Script-facing Box2D joint owned by a World.
void setWheelSpring(float frequencyHz, float dampingRatio)
Configures wheel suspension spring.
void setGearRatio(float ratio)
Changes gear ratio.
float getMotorAngularOffset() const
Motor angular offset in radians.
std::string getKind() const
Joint kind string for script/debug.
float getRevoluteSpeed() const
Current revolute speed in radians/second.
void setPrismaticMotor(bool enabled, float speedPixels, float maxForcePixels)
Configures a prismatic motor in pixels/second and pixel-force units.
float getWeldFrequency() const
Weld spring frequency in Hertz.
void setMotorAngularOffset(float radians)
Sets motor-joint angular offset in radians.
float getDistanceLength() const
Distance-joint rest length in pixels.
void destroy()
Destroys the backend joint and invalidates this wrapper.
void setWeldSpring(float frequencyHz, float dampingRatio)
Configures weld rotational spring frequency and damping.
float getMotorLinearOffsetX() const
Motor linear offset X in pixels.
void setPrismaticLimits(bool enabled, float lowerPixels, float upperPixels)
Configures prismatic translation limits in pixels.
void invalidate()
Internal invalidation used by body/world destruction.
void setCollideConnected(bool collide)
Enables or disables collision between the attached bodies.
void setMotorLimits(float maxForcePixels, float maxTorque)
Sets motor max force (pixel-force) and torque (N·m).
void setWheelMotor(bool enabled, float speed, float maxTorque)
Configures wheel spin motor in radians/second and newton-metres.
float getPrismaticSpeed() const
Current prismatic speed in pixels/second.
int getBodyBId() const
Stable ID of attached body B, or -1 after invalidation.
void setDistanceSpring(float frequencyHz, float dampingRatio)
Configures distance spring frequency (Hz) and damping ratio.
Kind
Supported joint geometry.
bool isValid() const
Whether the backend joint still exists.
bool getCollideConnected() const
Whether attached bodies may collide.
float getDistanceFrequency() const
Distance spring frequency in Hertz.
float getWheelTranslation() const
Current wheel translation along the suspension axis in pixels.
int getBodyAId() const
Stable ID of attached body A, or -1 after invalidation.
void setRevoluteMotor(bool enabled, float speed, float maxTorque)
Configures the revolute motor in radians/second and newton-metres.
float getRevoluteAngle() const
Current revolute angle in radians.
float getMotorLinearOffsetY() const
Motor linear offset Y in pixels.
void setRevoluteLimits(bool enabled, float lower, float upper)
Configures revolute angular limits in radians.
float getGearRatio() const
Current gear ratio.
Joint2D(World *world, Body *bodyA, Body *bodyB, b2Joint *joint, PhysicsJointHandle runtimeHandle, Kind kind, int id)
Internal wrapper constructor; use World::new*Joint.
float getWeldDampingRatio() const
Weld spring damping ratio.
float getPrismaticTranslation() const
Current prismatic translation in pixels.
void setDistanceLength(float lengthPixels)
Changes distance-joint rest length in pixels.
float getWheelSpeed() const
Current wheel spin speed in radians/second.
float getDistanceDampingRatio() const
Distance spring damping ratio.
void setMotorLinearOffset(float xPixels, float yPixels)
Sets motor-joint linear offset in pixels (bodyA frame).
float getRevoluteMotorTorque() const
Current revolute motor torque in newton-metres.
Box2D world wrapper (2D physics) with pixel-space coordinates. Handles stepping, gravity,...
void forgetJoint(Joint2D *joint)
Internal: removes a joint wrapper from ownership bookkeeping.
float toPixels(float meters) const
Converts a meter-space length to pixels.
b2World * raw()
Exposes the underlying Box2D world for tightly-scoped backend integration.
float toMeters(float pixels) const
Converts a pixel-space length to meters.
Optional physics backend for vehicle mobility and body attach.