载入中...
搜索中...
未找到
Body.cpp
浏览该文件的文档.
1#include "physics/Body.h"
2#include "physics/Fixture.h"
3#include "physics/World.h"
4
5#include "common/Exception.h"
6
7#include <Box2D/Box2D.h>
8
9#include <cstring>
10
11namespace eve::physics {
12namespace {
13
14b2BodyType parseBodyType(const std::string &type) {
15 if (type == "static") return b2_staticBody;
16 if (type == "kinematic") return b2_kinematicBody;
17 if (type == "dynamic") return b2_dynamicBody;
18 throw eve::Exception("Body.setType: unknown body type '%s'", type.c_str());
19}
20
21const char *bodyTypeName(b2BodyType t) {
22 switch (t) {
23 case b2_staticBody: return "static";
24 case b2_kinematicBody: return "kinematic";
25 case b2_dynamicBody: return "dynamic";
26 default: return "static";
27 }
28}
29
30} // namespace
31
32Body::Body(World *world, b2Body *body, int id) : world_(world), body_(body), id_(id) {}
33
35 if (body_ && world_ && world_->raw()) {
36 // Invalidate fixture wrappers before DestroyBody frees b2Fixtures.
37 b2Fixture *f = body_->GetFixtureList();
38 while (f) {
39 b2Fixture *next = f->GetNext();
40 auto *wrap = static_cast<Fixture *>(f->GetUserData());
41 if (wrap) {
42 world_->forgetFixture(wrap);
43 wrap->invalidate();
44 }
45 f = next;
46 }
47 body_->SetUserData(nullptr);
48 world_->raw()->DestroyBody(body_);
49 world_->forgetBody(this);
50 }
51 body_ = nullptr;
52 world_ = nullptr;
53}
54
56 if (body_) body_->SetUserData(nullptr);
57 body_ = nullptr;
58 world_ = nullptr;
59}
60
62 if (!body_ || !world_ || !world_->raw()) {
63 invalidate();
64 return;
65 }
66 b2Fixture *f = body_->GetFixtureList();
67 while (f) {
68 b2Fixture *next = f->GetNext();
69 auto *wrap = static_cast<Fixture *>(f->GetUserData());
70 if (wrap) {
71 world_->forgetFixture(wrap);
72 wrap->invalidate();
73 }
74 f = next;
75 }
76 body_->SetUserData(nullptr);
77 world_->raw()->DestroyBody(body_);
78 world_->forgetBody(this);
79 body_ = nullptr;
80 world_ = nullptr;
81}
82
83void Body::setPosition(float x, float y) {
84 if (!body_ || !world_) return;
85 body_->SetTransform(b2Vec2(world_->toMeters(x), world_->toMeters(y)), body_->GetAngle());
86}
87
88float Body::getX() const {
89 if (!body_ || !world_) return 0.f;
90 return world_->toPixels(body_->GetPosition().x);
91}
92
93float Body::getY() const {
94 if (!body_ || !world_) return 0.f;
95 return world_->toPixels(body_->GetPosition().y);
96}
97
98void Body::setAngle(float radians) {
99 if (!body_) return;
100 body_->SetTransform(body_->GetPosition(), radians);
101}
102
103float Body::getAngle() const {
104 if (!body_) return 0.f;
105 return body_->GetAngle();
106}
107
108void Body::setLinearVelocity(float vx, float vy) {
109 if (!body_ || !world_) return;
110 body_->SetLinearVelocity(b2Vec2(world_->toMeters(vx), world_->toMeters(vy)));
111}
112
114 if (!body_ || !world_) return 0.f;
115 return world_->toPixels(body_->GetLinearVelocity().x);
116}
117
119 if (!body_ || !world_) return 0.f;
120 return world_->toPixels(body_->GetLinearVelocity().y);
121}
122
123float Body::getLinearSpeed() const {
124 if (!body_ || !world_) return 0.f;
125 return world_->toPixels(body_->GetLinearVelocity().Length());
126}
127
128float Body::getMass() const { return body_ ? body_->GetMass() : 0.f; }
129
131 if (!body_ || !world_) return 0.f;
132 return world_->toPixels(body_->GetWorldCenter().x);
133}
134
136 if (!body_ || !world_) return 0.f;
137 return world_->toPixels(body_->GetWorldCenter().y);
138}
139
140void Body::setAngularVelocity(float omega) {
141 if (!body_) return;
142 body_->SetAngularVelocity(omega);
143}
144
146 if (!body_) return 0.f;
147 return body_->GetAngularVelocity();
148}
149
150void Body::applyForce(float fx, float fy) {
151 if (!body_ || !world_) return;
152 // Force in Newtons ≈ (pixels/s² * mass) with mass in kg; convert like LÖVE.
153 body_->ApplyForceToCenter(b2Vec2(world_->toMeters(fx), world_->toMeters(fy)), true);
154}
155
156void Body::applyForceAt(float fx, float fy, float x, float y) {
157 if (!body_ || !world_) return;
158 body_->ApplyForce(b2Vec2(world_->toMeters(fx), world_->toMeters(fy)),
159 b2Vec2(world_->toMeters(x), world_->toMeters(y)), true);
160}
161
162void Body::applyLinearImpulse(float ix, float iy) {
163 if (!body_ || !world_) return;
164 body_->ApplyLinearImpulse(b2Vec2(world_->toMeters(ix), world_->toMeters(iy)),
165 body_->GetWorldCenter(), true);
166}
167
168void Body::applyAngularImpulse(float impulse) {
169 if (!body_) return;
170 body_->ApplyAngularImpulse(impulse, true);
171}
172
173void Body::setType(const std::string &bodyType) {
174 if (!body_) return;
175 body_->SetType(parseBodyType(bodyType));
176}
177
178std::string Body::getType() const {
179 if (!body_) return "static";
180 return bodyTypeName(body_->GetType());
181}
182
183void Body::setFixedRotation(bool fixed) {
184 if (!body_) return;
185 body_->SetFixedRotation(fixed);
186}
187
188bool Body::isFixedRotation() const { return body_ ? body_->IsFixedRotation() : false; }
189
191 if (!body_) return;
192 body_->SetActive(active);
193}
194
195bool Body::isActive() const { return body_ ? body_->IsActive() : false; }
196
197void Body::setBullet(bool bullet) {
198 if (!body_) return;
199 body_->SetBullet(bullet);
200}
201
202bool Body::isBullet() const { return body_ ? body_->IsBullet() : false; }
203
204void Body::setAwake(bool awake) {
205 if (!body_) return;
206 body_->SetAwake(awake);
207}
208
209bool Body::isAwake() const { return body_ ? body_->IsAwake() : false; }
210
211Fixture *Body::newRectangleFixture(float width, float height, float density, float friction,
212 float restitution) {
213 return newRectangleFixtureAt(width, height, 0.f, 0.f, density, friction, restitution);
214}
215
216Fixture *Body::newRectangleFixtureAt(float width, float height, float offsetX, float offsetY,
217 float density, float friction, float restitution) {
218 if (!body_ || !world_) throw eve::Exception("Body.newRectangleFixture: body destroyed");
219 if (width <= 0.f || height <= 0.f)
220 throw eve::Exception("Body.newRectangleFixture: width/height must be > 0");
221
222 b2PolygonShape shape;
223 shape.SetAsBox(world_->toMeters(width) * 0.5f, world_->toMeters(height) * 0.5f,
224 b2Vec2(world_->toMeters(offsetX), world_->toMeters(offsetY)), 0.f);
225
226 b2FixtureDef def;
227 def.shape = &shape;
228 def.density = density;
229 def.friction = friction;
230 def.restitution = restitution;
231
232 b2Fixture *raw = body_->CreateFixture(&def);
233 auto *fx = new Fixture(world_, this, raw);
234 raw->SetUserData(fx);
235 world_->fixtures_.insert(fx);
236 return fx;
237}
238
239Fixture *Body::newCircleFixture(float radius, float density, float friction, float restitution) {
240 if (!body_ || !world_) throw eve::Exception("Body.newCircleFixture: body destroyed");
241 if (radius <= 0.f) throw eve::Exception("Body.newCircleFixture: radius must be > 0");
242
243 b2CircleShape shape;
244 shape.m_radius = world_->toMeters(radius);
245
246 b2FixtureDef def;
247 def.shape = &shape;
248 def.density = density;
249 def.friction = friction;
250 def.restitution = restitution;
251
252 b2Fixture *raw = body_->CreateFixture(&def);
253 auto *fx = new Fixture(world_, this, raw);
254 raw->SetUserData(fx);
255 world_->fixtures_.insert(fx);
256 return fx;
257}
258
259} // namespace eve::physics
bool active
Definition CardTypes.cpp:34
std::string type
std::string id
int y
Definition Grass.cpp:135
float height
Definition Grass.cpp:235
int x
Definition Grass.cpp:135
JobFunc body
int width
float f
Fixture * newRectangleFixture(float width, float height, float density=1.f, float friction=0.2f, float restitution=0.f)
width/height in pixels; density kg/m² (Box2D units).
Definition Body.cpp:211
float getLinearVelocityX() const
Definition Body.cpp:113
void applyForceAt(float fx, float fy, float x, float y)
Force applied at a world pixel position.
Definition Body.cpp:156
void setBullet(bool bullet)
CCD bullet mode (recommended for fast small bodies).
Definition Body.cpp:197
float getX() const
Definition Body.cpp:88
void setAwake(bool awake)
Wakes / sleeps the body manually.
Definition Body.cpp:204
void setType(const std::string &bodyType)
"static" | "kinematic" | "dynamic".
Definition Body.cpp:173
void setAngle(float radians)
Rotation in radians.
Definition Body.cpp:98
float getLinearVelocityY() const
Definition Body.cpp:118
bool isActive() const
Definition Body.cpp:195
void applyLinearImpulse(float ix, float iy)
Instantaneous linear impulse.
Definition Body.cpp:162
Fixture * newCircleFixture(float radius, float density=1.f, float friction=0.2f, float restitution=0.f)
Definition Body.cpp:239
void setFixedRotation(bool fixed)
Locks rotation so the body cannot spin.
Definition Body.cpp:183
void applyForce(float fx, float fy)
Force (pixels/s² * kg) applied at the center of mass.
Definition Body.cpp:150
bool isAwake() const
Definition Body.cpp:209
bool isFixedRotation() const
Definition Body.cpp:188
bool isBullet() const
Definition Body.cpp:202
friend class Fixture
Definition Body.h:105
void setAngularVelocity(float omega)
Angular velocity in radians/s.
Definition Body.cpp:140
b2Body * raw()
Definition Body.h:97
float getAngularVelocity() const
Definition Body.cpp:145
void destroy()
Destroys the body inside its world.
Definition Body.cpp:61
void applyAngularImpulse(float impulse)
Instantaneous angular impulse.
Definition Body.cpp:168
float getWorldCenterY() const
Definition Body.cpp:135
float getLinearSpeed() const
Magnitude of the linear velocity.
Definition Body.cpp:123
float getAngle() const
Definition Body.cpp:103
std::string getType() const
Definition Body.cpp:178
void invalidate()
Internal: marks the wrapper invalid after world destruction.
Definition Body.cpp:55
void setPosition(float x, float y)
Position in pixels.
Definition Body.cpp:83
float getWorldCenterX() const
World center of mass in pixels.
Definition Body.cpp:130
Fixture * newRectangleFixtureAt(float width, float height, float offsetX, float offsetY, float density=1.f, float friction=0.2f, float restitution=0.f)
Rectangle fixture with a local pixel-space offset from the body origin.
Definition Body.cpp:216
float getMass() const
Mass in kilograms (Box2D units).
Definition Body.cpp:128
void setActive(bool active)
Disables/enables the body and its fixtures.
Definition Body.cpp:190
void setLinearVelocity(float vx, float vy)
Linear velocity in pixels/s.
Definition Body.cpp:108
Body(World *world, b2Body *body, int id)
Internal: wraps a Box2D body (use World::newBody).
Definition Body.cpp:32
float getY() const
Definition Body.cpp:93
2D fixture: a shape attached to a Body with material + filter settings. Also carries a string tag use...
Definition Fixture.h:16
Box2D world wrapper (2D physics) with pixel-space coordinates. Handles stepping, gravity,...
Definition World.h:31
void forgetBody(Body *body)
Definition World.cpp:249
void forgetFixture(Fixture *fixture)
Definition World.cpp:260
float toPixels(float meters) const
Converts a meter-space length to pixels.
Definition World.cpp:226
b2World * raw()
The underlying Box2D world (advanced use).
Definition World.h:140
float toMeters(float pixels) const
Converts a pixel-space length to meters.
Definition World.cpp:225