box2d_World.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. #include "box2d/b2_world.h"
  2. #include "box2d/b2_world_callbacks.h"
  3. #include "box2d_bindings.hpp"
  4. using namespace pkpy;
  5. namespace imbox2d{
  6. struct MyRayCastCallback: b2RayCastCallback{
  7. PK_ALWAYS_PASS_BY_POINTER(MyRayCastCallback)
  8. VM* vm;
  9. List result;
  10. MyRayCastCallback(VM* vm): vm(vm) {}
  11. float ReportFixture(b2Fixture* fixture, const b2Vec2& point, const b2Vec2& normal, float fraction){
  12. result.push_back(get_body_object(fixture->GetBody()));
  13. // if(only_one) return 0;
  14. return fraction;
  15. }
  16. };
  17. struct MyBoxCastCallback: b2QueryCallback{
  18. PK_ALWAYS_PASS_BY_POINTER(MyBoxCastCallback)
  19. VM* vm;
  20. List result;
  21. MyBoxCastCallback(VM* vm): vm(vm) {}
  22. bool ReportFixture(b2Fixture* fixture) override{
  23. result.push_back(get_body_object(fixture->GetBody()));
  24. return true;
  25. }
  26. };
  27. /****************** PyWorld ******************/
  28. PyWorld::PyWorld(VM* vm): world(b2Vec2(0, 0)), _contact_listener(vm), _debug_draw(vm){
  29. _debug_draw.draw_like = vm->None;
  30. world.SetAllowSleeping(true);
  31. world.SetAutoClearForces(true);
  32. world.SetContactListener(&_contact_listener);
  33. world.SetDebugDraw(&_debug_draw);
  34. }
  35. void PyWorld::_register(VM* vm, PyObject* mod, PyObject* type){
  36. vm->bind(type, "__new__(cls)", [](VM* vm, ArgsView args){
  37. return VAR_T(PyWorld, PyWorld(vm));
  38. });
  39. // gravity
  40. vm->bind_property(type, "gravity: vec2", [](VM* vm, ArgsView args){
  41. PyWorld& self = _CAST(PyWorld&, args[0]);
  42. return VAR(self.world.GetGravity());
  43. }, [](VM* vm, ArgsView args){
  44. PyWorld& self = _CAST(PyWorld&, args[0]);
  45. self.world.SetGravity(CAST(b2Vec2, args[1]));
  46. return vm->None;
  47. });
  48. vm->bind(type, "get_bodies(self) -> list[Body]", [](VM* vm, ArgsView args){
  49. PyWorld& self = _CAST(PyWorld&, args[0]);
  50. List list;
  51. b2Body* p = self.world.GetBodyList();
  52. while(p != nullptr){
  53. list.push_back(get_body_object(p));
  54. p = p->GetNext();
  55. }
  56. return VAR(std::move(list));
  57. });
  58. vm->bind(type, "ray_cast(self, start: vec2, end: vec2) -> list[Body]", [](VM* vm, ArgsView args){
  59. auto _lock = vm->heap.gc_scope_lock();
  60. PyWorld& self = _CAST(PyWorld&, args[0]);
  61. b2Vec2 start = CAST(b2Vec2, args[1]);
  62. b2Vec2 end = CAST(b2Vec2, args[2]);
  63. MyRayCastCallback callback(vm);
  64. self.world.RayCast(&callback, start, end);
  65. return VAR(std::move(callback.result));
  66. });
  67. vm->bind(type, "box_cast(self, lower: vec2, upper: vec2) -> list[Body]", [](VM* vm, ArgsView args){
  68. auto _lock = vm->heap.gc_scope_lock();
  69. PyWorld& self = _CAST(PyWorld&, args[0]);
  70. b2AABB aabb;
  71. aabb.lowerBound = CAST(b2Vec2, args[1]);
  72. aabb.upperBound = CAST(b2Vec2, args[2]);
  73. MyBoxCastCallback callback(vm);
  74. self.world.QueryAABB(&callback, aabb);
  75. return VAR(std::move(callback.result));
  76. });
  77. vm->bind(type, "step(self, dt: float, velocity_iterations: int, position_iterations: int)",
  78. [](VM* vm, ArgsView args){
  79. PyWorld& self = _CAST(PyWorld&, args[0]);
  80. float dt = CAST(float, args[1]);
  81. int velocity_iterations = CAST(int, args[2]);
  82. int position_iterations = CAST(int, args[3]);
  83. auto f = [](VM* vm, b2Body* p, StrName name){
  84. while(p != nullptr){
  85. PyObject* body_obj = get_body_object(p);
  86. PyBody& body = _CAST(PyBody&, body_obj);
  87. if(body.node_like != vm->None){
  88. vm->call_method(body.node_like, name);
  89. }
  90. p = p->GetNext();
  91. }
  92. };
  93. DEF_SNAME(on_box2d_pre_step);
  94. DEF_SNAME(on_box2d_post_step);
  95. f(vm, self.world.GetBodyList(), on_box2d_pre_step);
  96. self.world.Step(dt, velocity_iterations, position_iterations);
  97. f(vm, self.world.GetBodyList(), on_box2d_post_step);
  98. return vm->None;
  99. });
  100. vm->bind(type, "debug_draw(self, flags: int)", [](VM* vm, ArgsView args){
  101. PyWorld& self = _CAST(PyWorld&, args[0]);
  102. int flags = CAST(int, args[1]);
  103. self._debug_draw.SetFlags(flags);
  104. self.world.DebugDraw();
  105. return vm->None;
  106. });
  107. vm->bind(type, "set_debug_draw(self, draw: _DrawLike)", [](VM* vm, ArgsView args){
  108. PyWorld& self = _CAST(PyWorld&, args[0]);
  109. self._debug_draw.draw_like = args[1];
  110. return vm->None;
  111. });
  112. }
  113. } // namespace imbox2d