box2d_World.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. #include "box2dw.hpp"
  2. namespace pkpy{
  3. struct MyRayCastCallback: b2RayCastCallback{
  4. PK_ALWAYS_PASS_BY_POINTER(MyRayCastCallback)
  5. VM* vm;
  6. List result;
  7. MyRayCastCallback(VM* vm): vm(vm) {}
  8. float ReportFixture(b2Fixture* fixture, const b2Vec2& point, const b2Vec2& normal, float fraction){
  9. result.push_back(get_body_object(fixture->GetBody()));
  10. // if(only_one) return 0;
  11. return fraction;
  12. }
  13. };
  14. struct MyBoxCastCallback: b2QueryCallback{
  15. PK_ALWAYS_PASS_BY_POINTER(MyBoxCastCallback)
  16. VM* vm;
  17. List result;
  18. MyBoxCastCallback(VM* vm): vm(vm) {}
  19. bool ReportFixture(b2Fixture* fixture) override{
  20. result.push_back(get_body_object(fixture->GetBody()));
  21. return true;
  22. }
  23. };
  24. void PyContactListener::_contact_f(b2Contact* contact, StrName name){
  25. PyObject* a = get_body_object(contact->GetFixtureA()->GetBody());
  26. PyObject* b = get_body_object(contact->GetFixtureB()->GetBody());
  27. PyBody& bodyA = PK_OBJ_GET(PyBody, a);
  28. PyBody& bodyB = PK_OBJ_GET(PyBody, b);
  29. PyObject* self;
  30. PyObject* f;
  31. f = vm->get_unbound_method(bodyA.node_like, name, &self, false);
  32. if(f != nullptr) vm->call_method(self, f, b);
  33. f = vm->get_unbound_method(bodyB.node_like, name, &self, false);
  34. if(f != nullptr) vm->call_method(self, f, a);
  35. }
  36. /****************** PyWorld ******************/
  37. PyWorld::PyWorld(VM* vm): world(b2Vec2(0, 0)), _contact_listener(vm), _debug_draw(vm){
  38. _debug_draw.draw_like = vm->None;
  39. world.SetAllowSleeping(true);
  40. world.SetAutoClearForces(true);
  41. world.SetContactListener(&_contact_listener);
  42. world.SetDebugDraw(&_debug_draw);
  43. }
  44. void PyWorld::_register(VM* vm, PyObject* mod, PyObject* type){
  45. vm->bind(type, "__new__(cls)", [](VM* vm, ArgsView args){
  46. return vm->heap.gcnew<PyWorld>(PyWorld::_type(vm), vm);
  47. });
  48. // gravity
  49. vm->bind_property(type, "gravity: vec2", [](VM* vm, ArgsView args){
  50. PyWorld& self = _CAST(PyWorld&, args[0]);
  51. return VAR(self.world.GetGravity());
  52. }, [](VM* vm, ArgsView args){
  53. PyWorld& self = _CAST(PyWorld&, args[0]);
  54. self.world.SetGravity(CAST(b2Vec2, args[1]));
  55. return vm->None;
  56. });
  57. vm->bind(type, "get_bodies(self) -> list[Body]", [](VM* vm, ArgsView args){
  58. PyWorld& self = _CAST(PyWorld&, args[0]);
  59. List list;
  60. b2Body* p = self.world.GetBodyList();
  61. while(p != nullptr){
  62. list.push_back(get_body_object(p));
  63. p = p->GetNext();
  64. }
  65. return VAR(std::move(list));
  66. });
  67. vm->bind(type, "ray_cast(self, start: vec2, end: vec2) -> list[Body]", [](VM* vm, ArgsView args){
  68. auto _lock = vm->heap.gc_scope_lock();
  69. PyWorld& self = _CAST(PyWorld&, args[0]);
  70. b2Vec2 start = CAST(b2Vec2, args[1]);
  71. b2Vec2 end = CAST(b2Vec2, args[2]);
  72. MyRayCastCallback callback(vm);
  73. self.world.RayCast(&callback, start, end);
  74. return VAR(std::move(callback.result));
  75. });
  76. vm->bind(type, "box_cast(self, lower: vec2, upper: vec2) -> list[Body]", [](VM* vm, ArgsView args){
  77. auto _lock = vm->heap.gc_scope_lock();
  78. PyWorld& self = _CAST(PyWorld&, args[0]);
  79. b2AABB aabb;
  80. aabb.lowerBound = CAST(b2Vec2, args[1]);
  81. aabb.upperBound = CAST(b2Vec2, args[2]);
  82. MyBoxCastCallback callback(vm);
  83. self.world.QueryAABB(&callback, aabb);
  84. return VAR(std::move(callback.result));
  85. });
  86. vm->bind(type, "point_cast(self, point: vec2) -> list[Body]", [](VM* vm, ArgsView args){
  87. auto _lock = vm->heap.gc_scope_lock();
  88. PyWorld& self = _CAST(PyWorld&, args[0]);
  89. b2AABB aabb;
  90. aabb.lowerBound = CAST(b2Vec2, args[1]);
  91. aabb.upperBound = CAST(b2Vec2, args[1]);
  92. MyBoxCastCallback callback(vm);
  93. self.world.QueryAABB(&callback, aabb);
  94. return VAR(std::move(callback.result));
  95. });
  96. vm->bind(type, "step(self, dt: float, velocity_iterations: int, position_iterations: int)",
  97. [](VM* vm, ArgsView args){
  98. // disable gc during step for safety
  99. auto _lock = vm->heap.gc_scope_lock();
  100. PyWorld& self = _CAST(PyWorld&, args[0]);
  101. float dt = CAST(float, args[1]);
  102. int velocity_iterations = CAST(int, args[2]);
  103. int position_iterations = CAST(int, args[3]);
  104. auto f = [](VM* vm, b2Body* p, StrName name){
  105. while(p != nullptr){
  106. PyObject* body_obj = get_body_object(p);
  107. PyBody& body = _CAST(PyBody&, body_obj);
  108. if(!body._is_destroyed){
  109. if(body.node_like != vm->None){
  110. vm->call_method(body.node_like, name);
  111. }
  112. }
  113. p = p->GetNext();
  114. }
  115. };
  116. DEF_SNAME(on_box2d_pre_step);
  117. DEF_SNAME(on_box2d_post_step);
  118. f(vm, self.world.GetBodyList(), on_box2d_pre_step);
  119. self.world.Step(dt, velocity_iterations, position_iterations);
  120. f(vm, self.world.GetBodyList(), on_box2d_post_step);
  121. // destroy bodies which are marked as destroyed
  122. b2Body* p = self.world.GetBodyList();
  123. while(p != nullptr){
  124. b2Body* next = p->GetNext();
  125. PyBody& body = _CAST(PyBody&, get_body_object(p));
  126. if(body._is_destroyed){
  127. body.body->GetWorld()->DestroyBody(body.body);
  128. body.body = nullptr;
  129. body._fixture = nullptr;
  130. body.node_like = nullptr;
  131. }
  132. p = next;
  133. }
  134. return vm->None;
  135. });
  136. vm->bind(type, "debug_draw(self, flags: int)", [](VM* vm, ArgsView args){
  137. PyWorld& self = _CAST(PyWorld&, args[0]);
  138. int flags = CAST(int, args[1]);
  139. self._debug_draw.SetFlags(flags);
  140. self.world.DebugDraw();
  141. return vm->None;
  142. });
  143. vm->bind(type, "set_debug_draw(self, draw: _DrawLike)", [](VM* vm, ArgsView args){
  144. PyWorld& self = _CAST(PyWorld&, args[0]);
  145. self._debug_draw.draw_like = args[1];
  146. return vm->None;
  147. });
  148. // joints
  149. vm->bind(type, "create_weld_joint(self, a, b)", [](VM* vm, ArgsView args){
  150. PyWorld& self = _CAST(PyWorld&, args[0]);
  151. PyBody& bodyA = CAST(PyBody&, args[1]);
  152. PyBody& bodyB = CAST(PyBody&, args[2]);
  153. b2WeldJointDef def;
  154. def.Initialize(bodyA.body, bodyB.body, bodyA.body->GetWorldCenter());
  155. b2Joint* p = self.world.CreateJoint(&def);
  156. return VAR(p); // void_p
  157. });
  158. }
  159. } // namespace pkpy