mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 11:30:18 +00:00
...
This commit is contained in:
parent
536a51b817
commit
f9d4269caf
@ -12,6 +12,8 @@ aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/src/common BOX2D_SRC_1)
|
||||
aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/src/dynamics BOX2D_SRC_2)
|
||||
aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/src/rope BOX2D_SRC_3)
|
||||
|
||||
aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/src BOX2D_BINDINGS_SRC)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O2")
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
@ -20,5 +22,5 @@ add_library(
|
||||
box2d
|
||||
STATIC
|
||||
${BOX2D_SRC_0} ${BOX2D_SRC_1} ${BOX2D_SRC_2} ${BOX2D_SRC_3}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/box2d_bindings.cpp
|
||||
${BOX2D_BINDINGS_SRC}
|
||||
)
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "box2d/b2_world.h"
|
||||
#include "box2d/box2d.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include <cstdlib>
|
||||
@ -24,6 +25,7 @@ inline PyObject* py_var(VM* vm, b2Vec2 v){
|
||||
|
||||
namespace imbox2d{
|
||||
|
||||
|
||||
struct Body final{
|
||||
b2Body* body;
|
||||
b2Fixture* fixture;
|
||||
@ -133,12 +135,7 @@ struct PyBody: OpaquePointer<Body>{
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||
};
|
||||
|
||||
struct PyWorld: OpaquePointer<b2World>{
|
||||
PY_CLASS(PyWorld, box2d, World)
|
||||
|
||||
using OpaquePointer<b2World>::OpaquePointer;
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||
};
|
||||
|
||||
} // namespace imbox2d
|
||||
|
||||
|
0
3rd/box2d/src/box2d_Body.cpp
Normal file
0
3rd/box2d/src/box2d_Body.cpp
Normal file
194
3rd/box2d/src/box2d_World.cpp
Normal file
194
3rd/box2d/src/box2d_World.cpp
Normal file
@ -0,0 +1,194 @@
|
||||
#include "box2d/b2_world.h"
|
||||
#include "box2d/b2_world_callbacks.h"
|
||||
#include "box2d_bindings.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace imbox2d{
|
||||
|
||||
// This class captures the closest hit shape.
|
||||
class MyRayCastCallback : public b2RayCastCallback
|
||||
{
|
||||
VM* vm;
|
||||
public:
|
||||
List result;
|
||||
MyRayCastCallback(VM* vm): vm(vm) {}
|
||||
|
||||
float ReportFixture(b2Fixture* fixture, const b2Vec2& point,
|
||||
const b2Vec2& normal, float fraction)
|
||||
{
|
||||
auto userdata = fixture->GetBody()->GetUserData().pointer;
|
||||
Body* body = reinterpret_cast<Body*>(userdata);
|
||||
result.push_back(VAR_T(PyBody, body));
|
||||
// if(only_one) return 0;
|
||||
return fraction;
|
||||
}
|
||||
};
|
||||
|
||||
class MyBoxCastCallback: public b2QueryCallback{
|
||||
VM* vm;
|
||||
public:
|
||||
List result;
|
||||
MyBoxCastCallback(VM* vm): vm(vm) {}
|
||||
|
||||
bool ReportFixture(b2Fixture* fixture) override{
|
||||
auto userdata = fixture->GetBody()->GetUserData().pointer;
|
||||
Body* body = reinterpret_cast<Body*>(userdata);
|
||||
result.push_back(VAR_T(PyBody, body));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// maybe we will use this class later
|
||||
class PyDebugDraw: public b2Draw{
|
||||
VM* vm;
|
||||
public:
|
||||
PyDebugDraw(VM* vm): vm(vm){}
|
||||
|
||||
void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) override{
|
||||
}
|
||||
|
||||
void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) override{
|
||||
}
|
||||
|
||||
void DrawCircle(const b2Vec2& center, float radius, const b2Color& color) override{
|
||||
}
|
||||
|
||||
void DrawSolidCircle(const b2Vec2& center, float radius, const b2Vec2& axis, const b2Color& color) override{
|
||||
}
|
||||
|
||||
void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) override{
|
||||
}
|
||||
|
||||
void DrawTransform(const b2Transform& xf) override{
|
||||
}
|
||||
|
||||
void DrawPoint(const b2Vec2& p, float size, const b2Color& color) override{
|
||||
}
|
||||
};
|
||||
|
||||
class PyContactListener : public b2ContactListener{
|
||||
VM* vm;
|
||||
public:
|
||||
PyContactListener(VM* vm): vm(vm){}
|
||||
|
||||
void _contact_f(b2Contact* contact, StrName name){
|
||||
auto a = contact->GetFixtureA()->GetBody()->GetUserData().pointer;
|
||||
auto b = contact->GetFixtureB()->GetBody()->GetUserData().pointer;
|
||||
Body* bodyA = reinterpret_cast<Body*>(a);
|
||||
Body* bodyB = reinterpret_cast<Body*>(b);
|
||||
PyObject* self;
|
||||
PyObject* f;
|
||||
f = vm->get_unbound_method(bodyA->obj, name, &self, false);
|
||||
if(f != nullptr) vm->call_method(self, f, VAR_T(PyBody, bodyB));
|
||||
f = vm->get_unbound_method(bodyB->obj, name, &self, false);
|
||||
if(f != nullptr) vm->call_method(self, f, VAR_T(PyBody, bodyA));
|
||||
}
|
||||
|
||||
void BeginContact(b2Contact* contact) override {
|
||||
DEF_SNAME(on_contact_begin);
|
||||
_contact_f(contact, on_contact_begin);
|
||||
}
|
||||
|
||||
void EndContact(b2Contact* contact) override {
|
||||
DEF_SNAME(on_contact_end);
|
||||
_contact_f(contact, on_contact_end);
|
||||
}
|
||||
};
|
||||
|
||||
// implement placement VAR_T...!!!!
|
||||
struct PyWorld {
|
||||
PY_CLASS(PyWorld, box2d, World)
|
||||
|
||||
// this object is too large, so we use unique_ptr
|
||||
std::unique_ptr<b2World> world;
|
||||
std::unique_ptr<PyContactListener> _contact_listener;
|
||||
std::unique_ptr<PyDebugDraw> _debug_draw;
|
||||
|
||||
PyWorld(VM* vm):
|
||||
world(new b2World(b2Vec2(0, 0))),
|
||||
_contact_listener(new PyContactListener(vm)),
|
||||
_debug_draw(new PyDebugDraw(vm)){
|
||||
world->SetAllowSleeping(true);
|
||||
world->SetAutoClearForces(true);
|
||||
world->SetContactListener(_contact_listener.get());
|
||||
world->SetDebugDraw(_debug_draw.get());
|
||||
}
|
||||
|
||||
PyWorld(const PyWorld&) = delete;
|
||||
PyWorld& operator=(const PyWorld&) = delete;
|
||||
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type){
|
||||
vm->bind(type, "__new__(cls)", [](VM* vm, ArgsView args){
|
||||
return VAR_T(PyWorld, PyWorld(vm));
|
||||
});
|
||||
|
||||
// gravity
|
||||
vm->bind_property(type, "gravity", "vec2", [](VM* vm, ArgsView args){
|
||||
PyWorld& self = _CAST(PyWorld&, args[0]);
|
||||
return VAR(self.world->GetGravity());
|
||||
}, [](VM* vm, ArgsView args){
|
||||
PyWorld& self = _CAST(PyWorld&, args[0]);
|
||||
self.world->SetGravity(CAST(b2Vec2, args[1]));
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind(type, "get_bodies(self) -> list[Body]", [](VM* vm, ArgsView args){
|
||||
PyWorld& self = _CAST(PyWorld&, args[0]);
|
||||
List list;
|
||||
b2Body* p = self.world->GetBodyList();
|
||||
while(p != nullptr){
|
||||
Body* body = (Body*)p->GetUserData().pointer;
|
||||
list.push_back(VAR_T(PyBody, body));
|
||||
p = p->GetNext();
|
||||
}
|
||||
return VAR(std::move(list));
|
||||
});
|
||||
|
||||
vm->bind(type, "ray_cast(self, start: vec2, end: vec2) -> list[Body]", [](VM* vm, ArgsView args){
|
||||
auto _lock = vm->heap.gc_scope_lock();
|
||||
PyWorld& self = _CAST(PyWorld&, args[0]);
|
||||
b2Vec2 start = CAST(b2Vec2, args[1]);
|
||||
b2Vec2 end = CAST(b2Vec2, args[2]);
|
||||
MyRayCastCallback callback(vm);
|
||||
self.world->RayCast(&callback, start, end);
|
||||
return VAR(std::move(callback.result));
|
||||
});
|
||||
|
||||
vm->bind(type, "box_cast(self, lower: vec2, upper: vec2) -> list[Body]", [](VM* vm, ArgsView args){
|
||||
auto _lock = vm->heap.gc_scope_lock();
|
||||
PyWorld& self = _CAST(PyWorld&, args[0]);
|
||||
b2AABB aabb;
|
||||
aabb.lowerBound = CAST(b2Vec2, args[1]);
|
||||
aabb.upperBound = CAST(b2Vec2, args[2]);
|
||||
MyBoxCastCallback callback(vm);
|
||||
self.world->QueryAABB(&callback, aabb);
|
||||
return VAR(std::move(callback.result));
|
||||
});
|
||||
|
||||
vm->bind(type, "step(self, dt: float, velocity_iterations: int, position_iterations: int)",
|
||||
[](VM* vm, ArgsView args){
|
||||
PyWorld& self = _CAST(PyWorld&, args[0]);
|
||||
float dt = CAST(float, args[1]);
|
||||
int velocity_iterations = CAST(int, args[2]);
|
||||
int position_iterations = CAST(int, args[3]);
|
||||
|
||||
auto f = [](VM* vm, b2Body* p, StrName name){
|
||||
while(p != nullptr){
|
||||
Body* body = (Body*)p->GetUserData().pointer;
|
||||
vm->call_method(body->obj, name);
|
||||
p = p->GetNext();
|
||||
}
|
||||
};
|
||||
|
||||
DEF_SNAME(on_box2d_pre_step);
|
||||
DEF_SNAME(on_box2d_post_step);
|
||||
f(vm, self.world->GetBodyList(), on_box2d_pre_step);
|
||||
self.world->Step(dt, velocity_iterations, position_iterations);
|
||||
f(vm, self.world->GetBodyList(), on_box2d_post_step);
|
||||
return vm->None;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace imbox2d
|
||||
} // namespace pkpy
|
@ -10,62 +10,7 @@ void add_module_box2d(VM *vm){
|
||||
|
||||
namespace imbox2d{
|
||||
|
||||
// maybe we will use this class later
|
||||
class PyDebugDraw: public b2Draw{
|
||||
VM* vm;
|
||||
public:
|
||||
PyDebugDraw(VM* vm): vm(vm){}
|
||||
|
||||
void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) override{
|
||||
}
|
||||
|
||||
void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) override{
|
||||
}
|
||||
|
||||
void DrawCircle(const b2Vec2& center, float radius, const b2Color& color) override{
|
||||
}
|
||||
|
||||
void DrawSolidCircle(const b2Vec2& center, float radius, const b2Vec2& axis, const b2Color& color) override{
|
||||
}
|
||||
|
||||
void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) override{
|
||||
}
|
||||
|
||||
void DrawTransform(const b2Transform& xf) override{
|
||||
}
|
||||
|
||||
void DrawPoint(const b2Vec2& p, float size, const b2Color& color) override{
|
||||
}
|
||||
};
|
||||
|
||||
class PyContactListener : public b2ContactListener{
|
||||
VM* vm;
|
||||
public:
|
||||
PyContactListener(VM* vm): vm(vm){}
|
||||
|
||||
void _contact_f(b2Contact* contact, StrName name){
|
||||
auto a = contact->GetFixtureA()->GetBody()->GetUserData().pointer;
|
||||
auto b = contact->GetFixtureB()->GetBody()->GetUserData().pointer;
|
||||
Body* bodyA = reinterpret_cast<Body*>(a);
|
||||
Body* bodyB = reinterpret_cast<Body*>(b);
|
||||
PyObject* self;
|
||||
PyObject* f;
|
||||
f = vm->get_unbound_method(bodyA->obj, name, &self, false);
|
||||
if(f != nullptr) vm->call_method(self, f, VAR_T(PyBody, bodyB));
|
||||
f = vm->get_unbound_method(bodyB->obj, name, &self, false);
|
||||
if(f != nullptr) vm->call_method(self, f, VAR_T(PyBody, bodyA));
|
||||
}
|
||||
|
||||
void BeginContact(b2Contact* contact) override {
|
||||
DEF_SNAME(on_contact_begin);
|
||||
_contact_f(contact, on_contact_begin);
|
||||
}
|
||||
|
||||
void EndContact(b2Contact* contact) override {
|
||||
DEF_SNAME(on_contact_end);
|
||||
_contact_f(contact, on_contact_end);
|
||||
}
|
||||
};
|
||||
|
||||
void PyBody::_register(VM* vm, PyObject* mod, PyObject* type){
|
||||
vm->bind_notimplemented_constructor<PyBody>(type);
|
||||
@ -221,100 +166,10 @@ public:
|
||||
});
|
||||
}
|
||||
|
||||
// This class captures the closest hit shape.
|
||||
class MyRayCastCallback : public b2RayCastCallback
|
||||
{
|
||||
VM* vm;
|
||||
public:
|
||||
List result;
|
||||
MyRayCastCallback(VM* vm): vm(vm) {}
|
||||
|
||||
float ReportFixture(b2Fixture* fixture, const b2Vec2& point,
|
||||
const b2Vec2& normal, float fraction)
|
||||
{
|
||||
auto userdata = fixture->GetBody()->GetUserData().pointer;
|
||||
Body* body = reinterpret_cast<Body*>(userdata);
|
||||
result.push_back(VAR_T(PyBody, body));
|
||||
// if(only_one) return 0;
|
||||
return fraction;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void PyWorld::_register(VM* vm, PyObject* mod, PyObject* type){
|
||||
vm->bind(type, "__new__(cls)", [](VM* vm, ArgsView args){
|
||||
b2World* w = new b2World(b2Vec2(0, 0));
|
||||
w->SetAllowSleeping(true);
|
||||
w->SetAutoClearForces(true);
|
||||
// the contact listener will leak memory after the world is destroyed
|
||||
// but it's not a big deal since the world is only destroyed when the game exits
|
||||
w->SetContactListener(new PyContactListener(vm));
|
||||
w->SetDebugDraw(new PyDebugDraw(vm));
|
||||
return VAR_T(PyWorld, w);
|
||||
});
|
||||
|
||||
// gravity
|
||||
vm->bind_property(type, "gravity", "vec2", [](VM* vm, ArgsView args){
|
||||
PyWorld& self = _CAST(PyWorld&, args[0]);
|
||||
return VAR(self->GetGravity());
|
||||
}, [](VM* vm, ArgsView args){
|
||||
PyWorld& self = _CAST(PyWorld&, args[0]);
|
||||
self->SetGravity(CAST(b2Vec2, args[1]));
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
// body
|
||||
vm->bind(type, "create_body(self, obj) -> Body", [](VM* vm, ArgsView args){
|
||||
PyWorld& self = _CAST(PyWorld&, args[0]);
|
||||
return VAR_T(PyBody, new Body(self.ptr, args[1]));
|
||||
});
|
||||
vm->bind(type, "get_bodies(self) -> list[Body]", [](VM* vm, ArgsView args){
|
||||
PyWorld& self = _CAST(PyWorld&, args[0]);
|
||||
List list;
|
||||
b2Body* p = self->GetBodyList();
|
||||
while(p != nullptr){
|
||||
Body* body = (Body*)p->GetUserData().pointer;
|
||||
list.push_back(VAR_T(PyBody, body));
|
||||
p = p->GetNext();
|
||||
}
|
||||
return VAR(std::move(list));
|
||||
});
|
||||
|
||||
// step
|
||||
vm->bind(type, "step(self, dt: float, velocity_iterations: int, position_iterations: int)",
|
||||
[](VM* vm, ArgsView args){
|
||||
PyWorld& self = _CAST(PyWorld&, args[0]);
|
||||
float dt = CAST(float, args[1]);
|
||||
int velocity_iterations = CAST(int, args[2]);
|
||||
int position_iterations = CAST(int, args[3]);
|
||||
|
||||
auto f = [](VM* vm, b2Body* p, StrName name){
|
||||
while(p != nullptr){
|
||||
Body* body = (Body*)p->GetUserData().pointer;
|
||||
vm->call_method(body->obj, name);
|
||||
p = p->GetNext();
|
||||
}
|
||||
};
|
||||
|
||||
DEF_SNAME(on_box2d_pre_step);
|
||||
DEF_SNAME(on_box2d_post_step);
|
||||
f(vm, self->GetBodyList(), on_box2d_pre_step);
|
||||
self->Step(dt, velocity_iterations, position_iterations);
|
||||
f(vm, self->GetBodyList(), on_box2d_post_step);
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
// raycast
|
||||
vm->bind(type, "raycast(self, start: vec2, end: vec2) -> list[Body]", [](VM* vm, ArgsView args){
|
||||
auto _lock = vm->heap.gc_scope_lock();
|
||||
PyWorld& self = _CAST(PyWorld&, args[0]);
|
||||
b2Vec2 start = CAST(b2Vec2, args[1]);
|
||||
b2Vec2 end = CAST(b2Vec2, args[2]);
|
||||
MyRayCastCallback callback(vm);
|
||||
self->RayCast(&callback, start, end);
|
||||
return VAR(std::move(callback.result));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -68,15 +68,12 @@ class World:
|
||||
def ray_cast(self, start: vec2, end: vec2) -> list['Body']:
|
||||
"""raycast from start to end"""
|
||||
|
||||
def box_cast(self, p0: vec2, p1: vec2) -> list['Body']:
|
||||
def box_cast(self, lower: vec2, upper: vec2) -> list['Body']:
|
||||
"""query bodies in the AABB region."""
|
||||
|
||||
def step(self, dt: float, velocity_iterations: int, position_iterations: int) -> None:
|
||||
"""step the simulation, e.g. world.step(1/60, 8, 3)"""
|
||||
|
||||
def destroy(self):
|
||||
"""destroy this world."""
|
||||
|
||||
# enum
|
||||
# {
|
||||
# e_shapeBit = 0x0001, ///< draw shapes
|
||||
|
Loading…
x
Reference in New Issue
Block a user