载入中...
搜索中...
未找到
World.cpp
浏览该文件的文档.
1#include "physics/World.h"
2#include "physics/Body.h"
3#include "physics/Fixture.h"
4
5#include "common/Exception.h"
6#include "event/Event.h"
7#include "graphics/Graphics.h"
8#include "graphics/Canvas.h"
9
10#include <Box2D/Box2D.h>
11
12#include <algorithm>
13#include <cmath>
14#include <cstring>
15
16namespace eve::physics {
17namespace {
18// Color lives in eve::graphics (see graphics/Canvas.h); keep the unqualified form.
20
21b2BodyType parseBodyType(const std::string &type) {
22 if (type == "static") return b2_staticBody;
23 if (type == "kinematic") return b2_kinematicBody;
24 if (type == "dynamic") return b2_dynamicBody;
25 throw eve::Exception("World.newBody: unknown body type '%s' (use static|kinematic|dynamic)",
26 type.c_str());
27}
28
29Body *bodyFromFixture(b2Fixture *f) {
30 if (!f) return nullptr;
31 b2Body *b = f->GetBody();
32 if (!b) return nullptr;
33 return static_cast<Body *>(b->GetUserData());
34}
35
36Fixture *fixtureFromRaw(b2Fixture *f) {
37 return f ? static_cast<Fixture *>(f->GetUserData()) : nullptr;
38}
39
40World::ContactEvent contactEventFrom(b2Contact *contact) {
41 World::ContactEvent out;
42 if (!contact) return out;
43 Fixture *fa = fixtureFromRaw(contact->GetFixtureA());
44 Fixture *fb = fixtureFromRaw(contact->GetFixtureB());
45 if (fa) {
46 out.bodyAId = fa->getBodyId();
47 out.fixtureATag = fa->getTag();
48 }
49 if (fb) {
50 out.bodyBId = fb->getBodyId();
51 out.fixtureBTag = fb->getTag();
52 }
53 return out;
54}
55
56} // namespace
57
58class ContactRelay : public b2ContactListener {
59public:
60 explicit ContactRelay(World *world) : world_(world) {}
61
62 void BeginContact(b2Contact *contact) override { world_->onBeginContact(contact); }
63 void EndContact(b2Contact *contact) override { world_->onEndContact(contact); }
64 void PreSolve(b2Contact *contact, const b2Manifold *oldManifold) override {
65 world_->onPreSolve(contact, oldManifold);
66 }
67 void PostSolve(b2Contact *contact, const b2ContactImpulse *impulse) override {
68 world_->onPostSolve(contact, impulse);
69 }
70
71private:
72 World *world_;
73};
74
75class DebugDraw : public b2Draw {
76public:
77 DebugDraw() { SetFlags(e_shapeBit | e_jointBit | e_aabbBit); }
78
79 void begin(graphics::Graphics *gfx, float meter) {
80 gfx_ = gfx;
81 meter_ = meter;
82 }
83 void end() { gfx_ = nullptr; }
84
85 void DrawPolygon(const b2Vec2 *vertices, int32 vertexCount, const b2Color &color) override {
86 drawPoly(vertices, vertexCount, color, false);
87 }
88 void DrawSolidPolygon(const b2Vec2 *vertices, int32 vertexCount, const b2Color &color) override {
89 drawPoly(vertices, vertexCount, color, true);
90 }
91 void DrawCircle(const b2Vec2 &center, float32 radius, const b2Color &color) override {
92 drawCircle(center, radius, color, false);
93 }
94 void DrawSolidCircle(const b2Vec2 &center, float32 radius, const b2Vec2 & /*axis*/,
95 const b2Color &color) override {
96 drawCircle(center, radius, color, true);
97 }
98 void DrawSegment(const b2Vec2 &p1, const b2Vec2 &p2, const b2Color &color) override {
99 if (!gfx_) return;
100 float x1 = p1.x * meter_, y1 = p1.y * meter_;
101 float x2 = p2.x * meter_, y2 = p2.y * meter_;
102 float minx = std::min(x1, x2), miny = std::min(y1, y2);
103 float w = std::max(1.f, std::fabs(x2 - x1));
104 float h = std::max(1.f, std::fabs(y2 - y1));
105 gfx_->drawSolidRect(minx, miny, w, h, Color(color.r, color.g, color.b, color.a * 0.8f));
106 }
107 void DrawTransform(const b2Transform &xf) override {
108 DrawSegment(xf.p, xf.p + 0.5f * xf.q.GetXAxis(), b2Color(1, 0, 0));
109 DrawSegment(xf.p, xf.p + 0.5f * xf.q.GetYAxis(), b2Color(0, 1, 0));
110 }
111
112private:
113 void drawPoly(const b2Vec2 *vertices, int32 vertexCount, const b2Color &color, bool solid) {
114 if (!gfx_ || vertexCount < 2) return;
115 for (int32 i = 0; i < vertexCount; ++i) {
116 const b2Vec2 &a = vertices[i];
117 const b2Vec2 &b = vertices[(i + 1) % vertexCount];
118 DrawSegment(a, b, color);
119 }
120 if (solid && vertexCount >= 3) {
121 float minx = vertices[0].x, maxx = vertices[0].x;
122 float miny = vertices[0].y, maxy = vertices[0].y;
123 for (int32 i = 1; i < vertexCount; ++i) {
124 minx = std::min(minx, vertices[i].x);
125 maxx = std::max(maxx, vertices[i].x);
126 miny = std::min(miny, vertices[i].y);
127 maxy = std::max(maxy, vertices[i].y);
128 }
129 gfx_->drawSolidRect(minx * meter_, miny * meter_, (maxx - minx) * meter_,
130 (maxy - miny) * meter_,
131 Color(color.r, color.g, color.b, color.a * 0.25f));
132 }
133 }
134 void drawCircle(const b2Vec2 &center, float32 radius, const b2Color &color, bool solid) {
135 if (!gfx_) return;
136 float px = (center.x - radius) * meter_;
137 float py = (center.y - radius) * meter_;
138 float d = radius * 2.f * meter_;
139 float a = solid ? color.a * 0.35f : color.a * 0.7f;
140 gfx_->drawSolidRect(px, py, d, d, Color(color.r, color.g, color.b, a));
141 }
142
143 graphics::Graphics *gfx_ = nullptr;
144 float meter_ = 30.f;
145};
146
147World::World(float gravityX, float gravityY, bool sleep, float meter) : meter_(meter) {
148 if (meter_ <= 0.f) meter_ = 30.f;
149 world_ = new b2World(b2Vec2(toMeters(gravityX), toMeters(gravityY)));
150 world_->SetAllowSleeping(sleep);
151 relay_ = new ContactRelay(this);
152 world_->SetContactListener(relay_);
153 draw_ = new DebugDraw();
154 world_->SetDebugDraw(draw_);
155}
156
158
160 if (destroyed_) return;
161 destroyed_ = true;
162
163 // Copy sets — Body/Fixture destructors erase from them.
164 std::vector<Body *> bodies(bodies_.begin(), bodies_.end());
165 for (Body *b : bodies) {
166 if (b) {
167 b->invalidate();
168 // Script may still hold Body*; leave object but null raw pointer.
169 // If World is script-owned and Body is also script-owned, Body::~Body
170 // will see null body_ and skip DestroyBody.
171 }
172 }
173 bodies_.clear();
174
175 std::vector<Fixture *> fixtures(fixtures_.begin(), fixtures_.end());
176 for (Fixture *f : fixtures) {
177 if (f) f->invalidate();
178 }
179 fixtures_.clear();
181
182 if (world_) {
183 world_->SetContactListener(nullptr);
184 world_->SetDebugDraw(nullptr);
185 delete world_;
186 world_ = nullptr;
187 }
188 delete relay_;
189 relay_ = nullptr;
190 delete draw_;
191 draw_ = nullptr;
192}
193
194void World::update(float dt) { updateFull(dt, 8, 3); }
195
196void World::updateFull(float dt, int velocityIterations, int positionIterations) {
197 if (!world_ || destroyed_) return;
198 if (dt < 0.f) dt = 0.f;
199 // Cap to avoid spiral-of-death on hitch frames.
200 if (dt > 0.05f) dt = 0.05f;
201 world_->Step(dt, velocityIterations, positionIterations);
202}
203
204void World::setGravity(float gx, float gy) {
205 if (!world_) return;
206 world_->SetGravity(b2Vec2(toMeters(gx), toMeters(gy)));
207}
208
209float World::getGravityX() const {
210 if (!world_) return 0.f;
211 return toPixels(world_->GetGravity().x);
212}
213
214float World::getGravityY() const {
215 if (!world_) return 0.f;
216 return toPixels(world_->GetGravity().y);
217}
218
219void World::setMeter(float pixelsPerMeter) {
220 if (pixelsPerMeter <= 0.f)
221 throw eve::Exception("World.setMeter: pixelsPerMeter must be > 0");
222 meter_ = pixelsPerMeter;
223}
224
225float World::toMeters(float pixels) const { return pixels / meter_; }
226float World::toPixels(float meters) const { return meters * meter_; }
227
228int World::nextBodyId() { return nextId_++; }
229
230Body *World::newBody(const std::string &bodyType, float x, float y) {
231 if (!world_ || destroyed_) throw eve::Exception("World.newBody: world destroyed");
232
233 b2BodyDef def;
234 def.type = parseBodyType(bodyType);
235 def.position = b2Vec2(toMeters(x), toMeters(y));
236
237 b2Body *raw = world_->CreateBody(&def);
238 Body *body = new Body(this, raw, nextBodyId());
239 raw->SetUserData(body);
240 bodies_.insert(body);
241 return body;
242}
243
245 if (!body) return;
246 body->destroy();
247}
248
250 if (!body) return;
251 const int id = body->getId();
252 bodies_.erase(body);
253 auto touches = [id](const ContactEvent &e) { return e.bodyAId == id || e.bodyBId == id; };
254 beginContacts_.erase(std::remove_if(beginContacts_.begin(), beginContacts_.end(), touches),
255 beginContacts_.end());
256 endContacts_.erase(std::remove_if(endContacts_.begin(), endContacts_.end(), touches),
257 endContacts_.end());
258 impacts_.erase(std::remove_if(impacts_.begin(), impacts_.end(), touches), impacts_.end());
259}
261 if (!fixture) return;
262 const int bodyId = fixture->getBodyId();
263 const std::string tag = fixture->getTag();
264 auto touches = [&](const ContactEvent &e) {
265 return (e.bodyAId == bodyId && e.fixtureATag == tag) ||
266 (e.bodyBId == bodyId && e.fixtureBTag == tag);
267 };
268 beginContacts_.erase(std::remove_if(beginContacts_.begin(), beginContacts_.end(), touches),
269 beginContacts_.end());
270 endContacts_.erase(std::remove_if(endContacts_.begin(), endContacts_.end(), touches),
271 endContacts_.end());
272 impacts_.erase(std::remove_if(impacts_.begin(), impacts_.end(), touches), impacts_.end());
273 b2Fixture *raw = fixture->raw();
274 for (auto it = preSolve_.begin(); it != preSolve_.end();) {
275 b2Contact *contact = it->first;
276 if (contact && (contact->GetFixtureA() == raw || contact->GetFixtureB() == raw))
277 it = preSolve_.erase(it);
278 else
279 ++it;
280 }
281 fixtures_.erase(fixture);
282}
283
284void World::onBeginContact(b2Contact *contact) {
285 if (!contact || !fixtureFromRaw(contact->GetFixtureA()) ||
286 !fixtureFromRaw(contact->GetFixtureB())) return;
287 Body *a = bodyFromFixture(contact->GetFixtureA());
288 Body *b = bodyFromFixture(contact->GetFixtureB());
289 if (!a || !b) return;
290
291 beginContacts_.push_back(contactEventFrom(contact));
292
293 auto *ev = eve::ModuleManager::getInstance<eve::event::Event>("Event");
294 if (!ev) return;
295 std::vector<eve::event::Variant> args = {eve::event::Variant::makeInt(a->getId()),
297 ev->push(new eve::event::Message("begincontact", args));
298}
299
300void World::onEndContact(b2Contact *contact) {
301 preSolve_.erase(contact);
302 if (!contact || !fixtureFromRaw(contact->GetFixtureA()) ||
303 !fixtureFromRaw(contact->GetFixtureB())) return;
304 Body *a = bodyFromFixture(contact->GetFixtureA());
305 Body *b = bodyFromFixture(contact->GetFixtureB());
306 if (!a || !b) return;
307
308 endContacts_.push_back(contactEventFrom(contact));
309
310 auto *ev = eve::ModuleManager::getInstance<eve::event::Event>("Event");
311 if (!ev) return;
312 std::vector<eve::event::Variant> args = {eve::event::Variant::makeInt(a->getId()),
314 ev->push(new eve::event::Message("endcontact", args));
315}
316
317void World::onPreSolve(b2Contact *contact, const b2Manifold * /*oldManifold*/) {
318 if (!contact || !world_) return;
319 b2WorldManifold manifold;
320 contact->GetWorldManifold(&manifold);
321 const b2Manifold *local = contact->GetManifold();
322 if (!local || local->pointCount <= 0) return;
323
324 b2Body *a = contact->GetFixtureA()->GetBody();
325 b2Body *b = contact->GetFixtureB()->GetBody();
326 if (!a || !b) return;
327 const b2Vec2 point = manifold.points[0];
328 const b2Vec2 va = a->GetLinearVelocityFromWorldPoint(point);
329 const b2Vec2 vb = b->GetLinearVelocityFromWorldPoint(point);
330
331 PreSolveData data;
332 data.pointX = toPixels(point.x);
333 data.pointY = toPixels(point.y);
334 data.normalX = manifold.normal.x;
335 data.normalY = manifold.normal.y;
336 data.relativeNormalSpeed = toPixels(std::max(0.f, b2Dot(va - vb, manifold.normal)));
337 preSolve_[contact] = data;
338}
339
340void World::onPostSolve(b2Contact *contact, const b2ContactImpulse *impulse) {
341 if (!contact || !impulse) return;
342 auto found = preSolve_.find(contact);
343 if (found == preSolve_.end()) return;
344
345 ImpactEvent out;
346 static_cast<ContactEvent &>(out) = contactEventFrom(contact);
347 out.pointX = found->second.pointX;
348 out.pointY = found->second.pointY;
349 out.normalX = found->second.normalX;
350 out.normalY = found->second.normalY;
351 out.relativeNormalSpeed = found->second.relativeNormalSpeed;
352 const int count = contact->GetManifold() ? contact->GetManifold()->pointCount : 0;
353 for (int i = 0; i < count; ++i) {
354 out.normalImpulse += toPixels(impulse->normalImpulses[i]);
355 out.tangentImpulse += toPixels(std::fabs(impulse->tangentImpulses[i]));
356 }
357 if (out.normalImpulse > 0.f) impacts_.push_back(std::move(out));
358}
359
360namespace {
361template <typename Event>
362const Event *eventAt(const std::vector<Event> &events, int index) {
363 return index >= 0 && index < int(events.size()) ? &events[size_t(index)] : nullptr;
364}
365} // namespace
366
367int World::getBeginContactBodyAId(int index) const {
368 auto *e = eventAt(beginContacts_, index); return e ? e->bodyAId : 0;
369}
370int World::getBeginContactBodyBId(int index) const {
371 auto *e = eventAt(beginContacts_, index); return e ? e->bodyBId : 0;
372}
373std::string World::getBeginContactFixtureATag(int index) const {
374 auto *e = eventAt(beginContacts_, index); return e ? e->fixtureATag : std::string();
375}
376std::string World::getBeginContactFixtureBTag(int index) const {
377 auto *e = eventAt(beginContacts_, index); return e ? e->fixtureBTag : std::string();
378}
379int World::getEndContactBodyAId(int index) const {
380 auto *e = eventAt(endContacts_, index); return e ? e->bodyAId : 0;
381}
382int World::getEndContactBodyBId(int index) const {
383 auto *e = eventAt(endContacts_, index); return e ? e->bodyBId : 0;
384}
385std::string World::getEndContactFixtureATag(int index) const {
386 auto *e = eventAt(endContacts_, index); return e ? e->fixtureATag : std::string();
387}
388std::string World::getEndContactFixtureBTag(int index) const {
389 auto *e = eventAt(endContacts_, index); return e ? e->fixtureBTag : std::string();
390}
391int World::getImpactBodyAId(int index) const {
392 auto *e = eventAt(impacts_, index); return e ? e->bodyAId : 0;
393}
394int World::getImpactBodyBId(int index) const {
395 auto *e = eventAt(impacts_, index); return e ? e->bodyBId : 0;
396}
397std::string World::getImpactFixtureATag(int index) const {
398 auto *e = eventAt(impacts_, index); return e ? e->fixtureATag : std::string();
399}
400std::string World::getImpactFixtureBTag(int index) const {
401 auto *e = eventAt(impacts_, index); return e ? e->fixtureBTag : std::string();
402}
403float World::getImpactPointX(int index) const {
404 auto *e = eventAt(impacts_, index); return e ? e->pointX : 0.f;
405}
406float World::getImpactPointY(int index) const {
407 auto *e = eventAt(impacts_, index); return e ? e->pointY : 0.f;
408}
409float World::getImpactNormalX(int index) const {
410 auto *e = eventAt(impacts_, index); return e ? e->normalX : 0.f;
411}
412float World::getImpactNormalY(int index) const {
413 auto *e = eventAt(impacts_, index); return e ? e->normalY : 0.f;
414}
416 auto *e = eventAt(impacts_, index); return e ? e->relativeNormalSpeed : 0.f;
417}
418float World::getImpactNormalImpulse(int index) const {
419 auto *e = eventAt(impacts_, index); return e ? e->normalImpulse : 0.f;
420}
421float World::getImpactTangentImpulse(int index) const {
422 auto *e = eventAt(impacts_, index); return e ? e->tangentImpulse : 0.f;
423}
424
426 beginContacts_.clear();
427 endContacts_.clear();
428 impacts_.clear();
429 preSolve_.clear();
430}
431
433 if (!world_ || !draw_ || !gfx) return;
434 draw_->begin(gfx, meter_);
435 world_->DrawDebugData();
436 draw_->end();
437}
438
439int World::rayCast(float x1, float y1, float x2, float y2) {
440 rayHitBodyId_ = -1;
441 rayHitX_ = 0.f;
442 rayHitY_ = 0.f;
443 rayHitNormalX_ = 0.f;
444 rayHitNormalY_ = 0.f;
445 rayHitFraction_ = 0.f;
446 if (!world_ || destroyed_) return -1;
447
448 struct Closest : public b2RayCastCallback {
449 World *world = nullptr;
450 float best = 1.f;
451 Body *hit = nullptr;
452 b2Vec2 point{};
453 b2Vec2 normal{};
454
455 float32 ReportFixture(b2Fixture *fixture, const b2Vec2 &pointIn, const b2Vec2 &normalIn,
456 float32 fraction) override {
457 Body *b = bodyFromFixture(fixture);
458 if (!b) return -1.f;
459 if (fraction < best) {
460 best = fraction;
461 hit = b;
462 point = pointIn;
463 normal = normalIn;
464 }
465 return fraction;
466 }
467 } cb;
468 cb.world = this;
469
470 b2Vec2 p1(toMeters(x1), toMeters(y1));
471 b2Vec2 p2(toMeters(x2), toMeters(y2));
472 world_->RayCast(&cb, p1, p2);
473
474 if (!cb.hit) return -1;
475 rayHitBodyId_ = cb.hit->getId();
476 rayHitX_ = toPixels(cb.point.x);
477 rayHitY_ = toPixels(cb.point.y);
478 rayHitNormalX_ = cb.normal.x;
479 rayHitNormalY_ = cb.normal.y;
480 rayHitFraction_ = cb.best;
481 return rayHitBodyId_;
482}
483
484int World::queryAABB(float x, float y, float w, float h) {
485 queryBodyIds_.clear();
486 if (!world_ || destroyed_) return 0;
487
488 struct Collector : public b2QueryCallback {
489 World *world = nullptr;
490 std::vector<int> *ids = nullptr;
491 std::unordered_set<int> seen;
492
493 bool ReportFixture(b2Fixture *fixture) override {
494 Body *b = bodyFromFixture(fixture);
495 if (!b) return true;
496 int id = b->getId();
497 if (seen.insert(id).second) ids->push_back(id);
498 return true;
499 }
500 } cb;
501 cb.world = this;
502 cb.ids = &queryBodyIds_;
503
504 b2AABB aabb;
505 float x0 = toMeters(x);
506 float y0 = toMeters(y);
507 float x1 = toMeters(x + w);
508 float y1 = toMeters(y + h);
509 aabb.lowerBound = b2Vec2(std::min(x0, x1), std::min(y0, y1));
510 aabb.upperBound = b2Vec2(std::max(x0, x1), std::max(y0, y1));
511 world_->QueryAABB(&cb, aabb);
512 return static_cast<int>(queryBodyIds_.size());
513}
514
515int World::getQueryBodyId(int index) const {
516 if (index < 0 || index >= static_cast<int>(queryBodyIds_.size()))
517 throw eve::Exception("World.getQueryBodyId: index out of range");
518 return queryBodyIds_[static_cast<size_t>(index)];
519}
520
521} // namespace eve::physics
std::string type
std::vector< HostEvent > events
std::string id
int y
Definition Grass.cpp:135
int x
Definition Grass.cpp:135
int h
int w
std::vector< Colorf > px
JobFunc body
uint32_t a
uint32_t b
Texture * normal
float f
Light2D::Data * data
int d
image::ImageData::Colorf color
A named event carrying an ordered list of Variant payloads. Pushed messages are heap-allocated; the q...
Definition Event.h:56
virtual void drawSolidRect(float x, float y, float w, float h, const Color &color, BlendMode blend=BlendMode::Alpha)=0
Internal immediate-mode helper used by RenderSystem / Batcher.
2D rigid body (Box2D) in pixel-space coordinates. Owned by a World; create shapes with newRectangleFi...
Definition Body.h:16
ContactRelay(World *world)
Definition World.cpp:60
void PreSolve(b2Contact *contact, const b2Manifold *oldManifold) override
Definition World.cpp:64
void BeginContact(b2Contact *contact) override
Definition World.cpp:62
void PostSolve(b2Contact *contact, const b2ContactImpulse *impulse) override
Definition World.cpp:67
void EndContact(b2Contact *contact) override
Definition World.cpp:63
void begin(graphics::Graphics *gfx, float meter)
Definition World.cpp:79
void DrawSolidCircle(const b2Vec2 &center, float32 radius, const b2Vec2 &, const b2Color &color) override
Definition World.cpp:94
void DrawCircle(const b2Vec2 &center, float32 radius, const b2Color &color) override
Definition World.cpp:91
void DrawTransform(const b2Transform &xf) override
Definition World.cpp:107
void DrawSegment(const b2Vec2 &p1, const b2Vec2 &p2, const b2Color &color) override
Definition World.cpp:98
void DrawPolygon(const b2Vec2 *vertices, int32 vertexCount, const b2Color &color) override
Definition World.cpp:85
void DrawSolidPolygon(const b2Vec2 *vertices, int32 vertexCount, const b2Color &color) override
Definition World.cpp:88
2D fixture: a shape attached to a Body with material + filter settings. Also carries a string tag use...
Definition Fixture.h:16
b2Fixture * raw()
Raw Box2D fixture.
Definition Fixture.h:64
int getBodyId() const
Id of the owning body.
Definition Fixture.cpp:103
const std::string & getTag() const
Definition Fixture.h:41
Box2D world wrapper (2D physics) with pixel-space coordinates. Handles stepping, gravity,...
Definition World.h:31
void setMeter(float pixelsPerMeter)
Changes the pixels-per-meter conversion.
Definition World.cpp:219
void update(float dt)
Steps the simulation by dt seconds (5 velocity / 2 position iterations).
Definition World.cpp:194
int queryAABB(float x, float y, float w, float h)
Query fixtures overlapping an axis-aligned box in pixel space (x,y,w,h). Returns match count; read id...
Definition World.cpp:484
float getImpactNormalY(int index) const
Definition World.cpp:412
void destroyBody(Body *body)
Destroys a body (null is ignored).
Definition World.cpp:244
void onBeginContact(b2Contact *contact)
Definition World.cpp:284
std::string getBeginContactFixtureATag(int index) const
Definition World.cpp:373
void forgetBody(Body *body)
Definition World.cpp:249
void onEndContact(b2Contact *contact)
Definition World.cpp:300
void forgetFixture(Fixture *fixture)
Definition World.cpp:260
std::string getEndContactFixtureATag(int index) const
Definition World.cpp:385
float getImpactPointX(int index) const
Definition World.cpp:403
void drawDebug(graphics::Graphics *gfx)
Optional: draw fixture AABBs via Graphics::drawSolidRect.
Definition World.cpp:432
int getQueryBodyId(int index) const
Definition World.cpp:515
int getEndContactBodyBId(int index) const
Definition World.cpp:382
int getBeginContactBodyBId(int index) const
Definition World.cpp:370
void destroy()
Destroys the underlying Box2D world and resets event buffers.
Definition World.cpp:159
void setGravity(float gx, float gy)
Sets the world gravity vector in pixels/s^2.
Definition World.cpp:204
void onPostSolve(b2Contact *contact, const b2ContactImpulse *impulse)
Definition World.cpp:340
int getEndContactBodyAId(int index) const
Definition World.cpp:379
float getGravityX() const
Definition World.cpp:209
float toPixels(float meters) const
Converts a meter-space length to pixels.
Definition World.cpp:226
friend class Body
Definition World.h:154
float getImpactNormalX(int index) const
Definition World.cpp:409
float getImpactRelativeNormalSpeed(int index) const
Definition World.cpp:415
b2World * raw()
The underlying Box2D world (advanced use).
Definition World.h:140
Body * newBody(const std::string &bodyType, float x, float y)
bodyType: "static" | "kinematic" | "dynamic". x/y in pixels.
Definition World.cpp:230
int getBeginContactBodyAId(int index) const
Definition World.cpp:367
int getImpactBodyAId(int index) const
Definition World.cpp:391
int getImpactBodyBId(int index) const
Definition World.cpp:394
float getImpactNormalImpulse(int index) const
Definition World.cpp:418
std::string getEndContactFixtureBTag(int index) const
Definition World.cpp:388
int rayCast(float x1, float y1, float x2, float y2)
Closest raycast in pixel space from (x1,y1) to (x2,y2). Returns hit body id, or -1....
Definition World.cpp:439
float getImpactTangentImpulse(int index) const
Definition World.cpp:421
float getGravityY() const
Definition World.cpp:214
std::string getBeginContactFixtureBTag(int index) const
Definition World.cpp:376
void updateFull(float dt, int velocityIterations, int positionIterations)
Steps with explicit iteration counts.
Definition World.cpp:196
void clearContactEvents()
Clears collected begin/end contact and impact event buffers.
Definition World.cpp:425
void onPreSolve(b2Contact *contact, const b2Manifold *oldManifold)
Definition World.cpp:317
float toMeters(float pixels) const
Converts a pixel-space length to meters.
Definition World.cpp:225
std::string getImpactFixtureATag(int index) const
Definition World.cpp:397
std::string getImpactFixtureBTag(int index) const
Definition World.cpp:400
World(float gravityX, float gravityY, bool sleep, float meter)
Creates a physics world.
Definition World.cpp:147
float getImpactPointY(int index) const
Definition World.cpp:406
glm::vec4 Color
RGBA color used by every graphics draw call. Lives inside eve::graphics so including a graphics heade...
Definition Color.h:13
static Variant makeInt(int64_t v)
Constructs an integer variant.
Definition Event.h:29