This commit is contained in:
blueloveTH 2023-08-05 16:14:57 +08:00
parent f16f98fcf8
commit 8eb01dc352
5 changed files with 104 additions and 188 deletions

View File

@ -26,6 +26,11 @@ using namespace pkpy;
namespace imbox2d{ namespace imbox2d{
inline PyObject* get_body_object(b2Body* p){
auto userdata = p->GetUserData().pointer;
return reinterpret_cast<PyObject*>(userdata);
}
// maybe we will use this class later // maybe we will use this class later
struct PyDebugDraw: b2Draw{ struct PyDebugDraw: b2Draw{
PK_ALWAYS_PASS_BY_POINTER(PyDebugDraw) PK_ALWAYS_PASS_BY_POINTER(PyDebugDraw)
@ -63,16 +68,16 @@ struct PyContactListener: b2ContactListener{
PyContactListener(VM* vm): vm(vm){} PyContactListener(VM* vm): vm(vm){}
void _contact_f(b2Contact* contact, StrName name){ void _contact_f(b2Contact* contact, StrName name){
auto a = contact->GetFixtureA()->GetBody()->GetUserData().pointer; b2Body* bodyA = contact->GetFixtureA()->GetBody();
auto b = contact->GetFixtureB()->GetBody()->GetUserData().pointer; b2Body* bodyB = contact->GetFixtureB()->GetBody();
Body* bodyA = reinterpret_cast<Body*>(a); PyObject* a = get_body_object(bodyA);
Body* bodyB = reinterpret_cast<Body*>(b); PyObject* b = get_body_object(bodyB);
PyObject* self; PyObject* self;
PyObject* f; PyObject* f;
f = vm->get_unbound_method(bodyA->obj, name, &self, false); f = vm->get_unbound_method(a, name, &self, false);
if(f != nullptr) vm->call_method(self, f, VAR_T(PyBody, bodyB)); if(f != nullptr) vm->call_method(self, f, b);
f = vm->get_unbound_method(bodyB->obj, name, &self, false); f = vm->get_unbound_method(b, name, &self, false);
if(f != nullptr) vm->call_method(self, f, VAR_T(PyBody, bodyA)); if(f != nullptr) vm->call_method(self, f, a);
} }
void BeginContact(b2Contact* contact) override { void BeginContact(b2Contact* contact) override {
@ -100,7 +105,31 @@ struct PyBody{
PK_OBJ_MARK(node_like); PK_OBJ_MARK(node_like);
} }
PyBody& _() { return *this; }
b2Body& _b2Body() { return *body; }
b2Fixture& _b2Fixture() { return *fixture; }
static void _register(VM* vm, PyObject* mod, PyObject* type); static void _register(VM* vm, PyObject* mod, PyObject* type);
// methods
b2Vec2 get_position() const { return body->GetPosition(); }
void set_position(b2Vec2 v){ body->SetTransform(v, body->GetAngle()); }
float get_rotation() const { return body->GetAngle(); }
void set_rotation(float v){ body->SetTransform(body->GetPosition(), v); }
void apply_force(b2Vec2 force, b2Vec2 point){ body->ApplyForce(force, point, true); }
void apply_force_to_center(b2Vec2 force){ body->ApplyForceToCenter(force, true); }
void apply_torque(float torque){ body->ApplyTorque(torque, true); }
void apply_impulse(b2Vec2 impulse, b2Vec2 point){
body->ApplyLinearImpulse(impulse, point, true);
}
void apply_impulse_to_center(b2Vec2 impulse){
body->ApplyLinearImpulseToCenter(impulse, true);
}
void apply_angular_impulse(float impulse){
body->ApplyAngularImpulse(impulse, true);
}
}; };
struct PyWorld { struct PyWorld {
@ -223,12 +252,6 @@ struct Body final{
} }
}; };
inline PyObject* get_body_object(b2Body* p){
auto userdata = p->GetUserData().pointer;
return reinterpret_cast<PyObject*>(userdata);
}
} // namespace imbox2d } // namespace imbox2d
namespace pkpy{ namespace pkpy{

View File

@ -1,12 +1,12 @@
#include "box2d/b2_world.h" #include "box2d/b2_world.h"
#include "box2d/b2_world_callbacks.h" #include "box2d/b2_world_callbacks.h"
#include "box2d_bindings.hpp" #include "box2d_bindings.hpp"
#include "pocketpy/bindings.h"
using namespace pkpy; using namespace pkpy;
namespace imbox2d{ namespace imbox2d{
void PyBody::_register(VM* vm, PyObject* mod, PyObject* type){ void PyBody::_register(VM* vm, PyObject* mod, PyObject* type){
vm->bind(type, "__new__(cls, world: World, node: _NodeLike = None)", vm->bind(type, "__new__(cls, world: World, node: _NodeLike = None)",
[](VM* vm, ArgsView args){ [](VM* vm, ArgsView args){
@ -23,6 +23,66 @@ void PyBody::_register(VM* vm, PyObject* mod, PyObject* type){
body.node_like = node; body.node_like = node;
return obj; return obj;
}); });
PK_REGISTER_PROPERTY(PyBody, "type: int", _b2Body, GetType, SetType)
PK_REGISTER_PROPERTY(PyBody, "gravity_scale: float", _b2Body, GetGravityScale, SetGravityScale)
PK_REGISTER_PROPERTY(PyBody, "fixed_rotation: bool", _b2Body, IsFixedRotation, SetFixedRotation)
PK_REGISTER_PROPERTY(PyBody, "enabled: bool", _b2Body, IsEnabled, SetEnabled)
PK_REGISTER_PROPERTY(PyBody, "bullet: bool", _b2Body, IsBullet, SetBullet)
PK_REGISTER_READONLY_PROPERTY(PyBody, "mass: float", _b2Body, GetMass)
PK_REGISTER_READONLY_PROPERTY(PyBody, "inertia: float", _b2Body, GetInertia)
PK_REGISTER_PROPERTY(PyBody, "position: vec2", _, get_position, set_position)
PK_REGISTER_PROPERTY(PyBody, "rotation: float", _, get_rotation, set_rotation)
PK_REGISTER_PROPERTY(PyBody, "velocity: vec2", _b2Body, GetLinearVelocity, SetLinearVelocity)
PK_REGISTER_PROPERTY(PyBody, "angular_velocity: float", _b2Body, GetAngularVelocity, SetAngularVelocity)
PK_REGISTER_PROPERTY(PyBody, "damping: float", _b2Body, GetLinearDamping, SetLinearDamping)
PK_REGISTER_PROPERTY(PyBody, "angular_damping: float", _b2Body, GetAngularDamping, SetAngularDamping)
PK_REGISTER_PROPERTY(PyBody, "density: float", _b2Fixture, GetDensity, SetDensity)
PK_REGISTER_PROPERTY(PyBody, "friction: float", _b2Fixture, GetFriction, SetFriction)
PK_REGISTER_PROPERTY(PyBody, "restitution: float", _b2Fixture, GetRestitution, SetRestitution)
PK_REGISTER_PROPERTY(PyBody, "restitution_threshold: float", _b2Fixture, GetRestitutionThreshold, SetRestitutionThreshold)
PK_REGISTER_PROPERTY(PyBody, "is_trigger: bool", _b2Fixture, IsSensor, SetSensor)
// methods
_bind(vm, type, "apply_force(self, force: vec2, point: vec2)", &PyBody::apply_force);
_bind(vm, type, "apply_force_to_center(self, force: vec2)", &PyBody::apply_force_to_center);
_bind(vm, type, "apply_torque(self, torque: float)", &PyBody::apply_torque);
_bind(vm, type, "apply_impulse(self, impulse: vec2, point: vec2)", &PyBody::apply_impulse);
_bind(vm, type, "apply_impulse_to_center(self, impulse: vec2)", &PyBody::apply_impulse_to_center);
_bind(vm, type, "apply_angular_impulse(self, impulse: float)", &PyBody::apply_angular_impulse);
// get_node
vm->bind(type, "get_node(self)", [](VM* vm, ArgsView args){
PyBody& body = CAST(PyBody&, args[1]);
return body.node_like;
});
// get_contacts
vm->bind(type, "get_contacts(self) -> list[Body]", [](VM* vm, ArgsView args){
PyBody& self = _CAST(PyBody&, args[0]);
b2ContactEdge* edge = self.body->GetContactList();
List list;
while(edge){
b2Fixture* fixtureB = edge->contact->GetFixtureB();
b2Body* bodyB = fixtureB->GetBody();
list.push_back(get_body_object(bodyB));
edge = edge->next;
}
return VAR(std::move(list));
});
// destroy
vm->bind(type, "destroy(self)", [](VM* vm, ArgsView args){
PyBody& body = CAST(PyBody&, args[1]);
body.body->GetWorld()->DestroyBody(body.body);
body.body = nullptr;
body.fixture = nullptr;
body.node_like = nullptr;
return vm->None;
});
} }
} // namespace imbox2d } // namespace imbox2d

View File

@ -48,7 +48,7 @@ void PyWorld::_register(VM* vm, PyObject* mod, PyObject* type){
}); });
// gravity // gravity
vm->bind_property(type, "gravity", "vec2", [](VM* vm, ArgsView args){ vm->bind_property(type, "gravity: vec2", [](VM* vm, ArgsView args){
PyWorld& self = _CAST(PyWorld&, args[0]); PyWorld& self = _CAST(PyWorld&, args[0]);
return VAR(self.world.GetGravity()); return VAR(self.world.GetGravity());
}, [](VM* vm, ArgsView args){ }, [](VM* vm, ArgsView args){

View File

@ -1,170 +0,0 @@
#include "box2d_bindings.hpp"
namespace pkpy{
namespace imbox2d{
void PyBody::_register(VM* vm, PyObject* mod, PyObject* type){
vm->bind_notimplemented_constructor<PyBody>(type);
PK_REGISTER_READONLY_PROPERTY(PyBody, debug_color, "vec4");
PK_REGISTER_PROPERTY(PyBody, position, "vec2");
PK_REGISTER_PROPERTY(PyBody, rotation, "float");
PK_REGISTER_PROPERTY(PyBody, velocity, "vec2");
PK_REGISTER_PROPERTY(PyBody, angular_velocity, "float");
PK_REGISTER_PROPERTY(PyBody, damping, "float");
PK_REGISTER_PROPERTY(PyBody, angular_damping, "float");
PK_REGISTER_PROPERTY(PyBody, gravity_scale, "float");
PK_REGISTER_PROPERTY(PyBody, type, "int");
PK_REGISTER_READONLY_PROPERTY(PyBody, mass, "float");
PK_REGISTER_READONLY_PROPERTY(PyBody, inertia, "float");
// fixture settings
PK_REGISTER_PROPERTY(PyBody, density, "float");
PK_REGISTER_PROPERTY(PyBody, friction, "float");
PK_REGISTER_PROPERTY(PyBody, restitution, "float");
PK_REGISTER_PROPERTY(PyBody, restitution_threshold, "float");
PK_REGISTER_PROPERTY(PyBody, is_trigger, "bool");
// methods
_bind_opaque<PyBody>(vm, type, "apply_force(self, force: vec2, point: vec2)", &Body::apply_force);
_bind_opaque<PyBody>(vm, type, "apply_force_to_center(self, force: vec2)", &Body::apply_force_to_center);
_bind_opaque<PyBody>(vm, type, "apply_torque(self, torque: float)", &Body::apply_torque);
_bind_opaque<PyBody>(vm, type, "apply_linear_impulse(self, impulse: vec2, point: vec2)", &Body::apply_linear_impulse);
_bind_opaque<PyBody>(vm, type, "apply_linear_impulse_to_center(self, impulse: vec2)", &Body::apply_linear_impulse_to_center);
_bind_opaque<PyBody>(vm, type, "apply_angular_impulse(self, impulse: float)", &Body::apply_angular_impulse);
vm->bind__eq__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){
PyBody& self = _CAST(PyBody&, lhs);
if(is_non_tagged_type(rhs, PyBody::_type(vm))) return vm->NotImplemented;
PyBody& other = _CAST(PyBody&, rhs);
return VAR(self->body == other->body);
});
vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){
PyBody& self = _CAST(PyBody&, obj);
return VAR(fmt("<Body* at ", self->body, ">"));
});
// destroy
_bind_opaque<PyBody>(vm, type, "destroy(self)", &Body::destroy);
// contacts
vm->bind(type, "get_contacts(self) -> list", [](VM* vm, ArgsView args){
PyBody& self = _CAST(PyBody&, args[0]);
b2ContactEdge* edge = self->body->GetContactList();
List list;
while(edge){
b2Fixture* fixtureB = edge->contact->GetFixtureB();
b2Body* bodyB = fixtureB->GetBody();
PyObject* objB = reinterpret_cast<Body*>(bodyB->GetUserData().pointer)->obj;
list.push_back(objB);
edge = edge->next;
}
return VAR(std::move(list));
});
// userdata
vm->bind(type, "get_node(self)", [](VM* vm, ArgsView args){
PyBody& self = _CAST(PyBody&, args[0]);
return self->obj;
});
// shape
vm->bind(type, "set_box_shape(self, hx: float, hy: float)", [](VM* vm, ArgsView args){
PyBody& self = _CAST(PyBody&, args[0]);
float hx = CAST(float, args[1]);
float hy = CAST(float, args[2]);
b2PolygonShape shape;
shape.SetAsBox(hx, hy);
self->_update_fixture(&shape);
return vm->None;
});
vm->bind(type, "set_circle_shape(self, radius: float)", [](VM* vm, ArgsView args){
PyBody& self = _CAST(PyBody&, args[0]);
float radius = CAST(float, args[1]);
b2CircleShape shape;
shape.m_radius = radius;
self->_update_fixture(&shape);
return vm->None;
});
vm->bind(type, "set_polygon_shape(self, points: list[vec2])", [](VM* vm, ArgsView args){
PyBody& self = _CAST(PyBody&, args[0]);
List& points = CAST(List&, args[1]);
if(points.size() > b2_maxPolygonVertices || points.size() < 3){
vm->ValueError(fmt("invalid polygon vertices count: ", points.size()));
return vm->None;
}
std::vector<b2Vec2> vertices(points.size());
for(int i = 0; i < points.size(); ++i){
vertices[i] = CAST(b2Vec2, points[i]);
}
b2PolygonShape shape;
shape.Set(vertices.data(), vertices.size());
self->_update_fixture(&shape);
return vm->None;
});
vm->bind(type, "set_chain_shape(self, points: list[vec2])", [](VM* vm, ArgsView args){
PyBody& self = _CAST(PyBody&, args[0]);
List& points = CAST(List&, args[1]);
std::vector<b2Vec2> vertices(points.size());
for(int i = 0; i < points.size(); ++i){
vertices[i] = CAST(b2Vec2, points[i]);
}
b2ChainShape shape;
shape.CreateLoop(vertices.data(), vertices.size());
self->_update_fixture(&shape);
return vm->None;
});
vm->bind(type, "get_shape_info(self) -> tuple", [](VM* vm, ArgsView args){
PyBody& self = _CAST(PyBody&, args[0]);
b2Shape* shape = self->fixture->GetShape();
switch(shape->GetType()){
case b2Shape::e_polygon:{
b2PolygonShape* poly = static_cast<b2PolygonShape*>(shape);
Tuple points(poly->m_count + 1);
for(int i = 0; i < poly->m_count; ++i){
points[i] = VAR(poly->m_vertices[i]);
}
points[poly->m_count] = points[0];
return VAR(Tuple({
VAR("polygon"), VAR(std::move(points))
}));
}
case b2Shape::e_circle:{
b2CircleShape* circle = static_cast<b2CircleShape*>(shape);
return VAR(Tuple({
VAR("circle"), VAR(circle->m_radius)
}));
}
case b2Shape::e_chain:{
b2ChainShape* chain = static_cast<b2ChainShape*>(shape);
Tuple points(chain->m_count);
for(int i = 0; i < chain->m_count; ++i){
points[i] = VAR(chain->m_vertices[i]);
}
return VAR(Tuple({
VAR("chain"), VAR(std::move(points))
}));
}
default:
vm->ValueError("unsupported shape type");
return vm->None;
}
});
}
}
} // namespace pkpy

View File

@ -90,13 +90,16 @@ class World:
class Body: class Body:
type: int # 0-static, 1-kinematic, 2-dynamic, by default 2 type: int # 0-static, 1-kinematic, 2-dynamic, by default 2
mass: float
inertia: float
gravity_scale: float gravity_scale: float
fixed_rotation: bool fixed_rotation: bool
enabled: bool enabled: bool
bullet: bool # whether to use continuous collision detection bullet: bool # whether to use continuous collision detection
@property
def mass(self) -> float: ...
@property
def inertia(self) -> float: ...
position: vec2 position: vec2
rotation: float # in radians (counter-clockwise) rotation: float # in radians (counter-clockwise)
velocity: vec2 # linear velocity velocity: vec2 # linear velocity