diff --git a/src/modules/physics/box2d/Physics.cpp b/src/modules/physics/box2d/Physics.cpp
index abf26e2da..5c3a134f9 100644
--- a/src/modules/physics/box2d/Physics.cpp
+++ b/src/modules/physics/box2d/Physics.cpp
@@ -63,9 +63,69 @@ Body *Physics::newBody(World *world, Body::Type type)
return new Body(world, b2Vec2(0, 0), type);
}
-CircleShape *Physics::newCircleShape(float radius)
+Body *Physics::newCircleBody(World *world, Body::Type type, float x, float y, float radius)
{
- return newCircleShape(0, 0, radius);
+ StrongRef
body(newBody(world, x, y, type), Acquire::NORETAIN);
+ StrongRef shape(newCircleShape(0, 0, radius), Acquire::NORETAIN);
+ StrongRef fixture(newFixture(body, shape, 1.0f), Acquire::NORETAIN);
+ body->retain();
+ return body.get();
+}
+
+Body *Physics::newRectangleBody(World *world, Body::Type type, float x, float y, float w, float h, float angle)
+{
+ StrongRef body(newBody(world, x, y, type), Acquire::NORETAIN);
+ StrongRef shape(newRectangleShape(0, 0, w, h, angle), Acquire::NORETAIN);
+ StrongRef fixture(newFixture(body, shape, 1.0f), Acquire::NORETAIN);
+ body->retain();
+ return body.get();
+}
+
+Body *Physics::newPolygonBody(World *world, Body::Type type, const Vector2 *coords, int count)
+{
+ Vector2 origin(0, 0);
+
+ for (int i = 0; i < count; i++)
+ origin += coords[i] / count;
+
+ std::vector localcoords;
+ for (int i = 0; i < count; i++)
+ localcoords.push_back(coords[i] - origin);
+
+ StrongRef body(newBody(world, origin.x, origin.y, type), Acquire::NORETAIN);
+ StrongRef shape(newPolygonShape(localcoords.data(), count), Acquire::NORETAIN);
+ StrongRef fixture(newFixture(body, shape, 1.0f), Acquire::NORETAIN);
+ body->retain();
+ return body.get();
+}
+
+Body *Physics::newEdgeBody(World *world, Body::Type type, float x1, float y1, float x2, float y2, bool oneSided)
+{
+ float wx = (x2 - x1) / 2.0f;
+ float wy = (y2 - y1) / 2.0f;
+ StrongRef body(newBody(world, wx, wy, type), Acquire::NORETAIN);
+ StrongRef shape(newEdgeShape(x1 - wx, y1 - wy, x2 - wx, y2 - wy, oneSided), Acquire::NORETAIN);
+ StrongRef fixture(newFixture(body, shape, 1.0f), Acquire::NORETAIN);
+ body->retain();
+ return body.get();
+}
+
+Body *Physics::newChainBody(World *world, Body::Type type, bool loop, const Vector2 *coords, int count)
+{
+ Vector2 origin(0, 0);
+
+ for (int i = 0; i < count; i++)
+ origin += coords[i] / count;
+
+ std::vector localcoords;
+ for (int i = 0; i < count; i++)
+ localcoords.push_back(coords[i] - origin);
+
+ StrongRef body(newBody(world, origin.x, origin.y, type), Acquire::NORETAIN);
+ StrongRef shape(newChainShape(loop, localcoords.data(), count), Acquire::NORETAIN);
+ StrongRef fixture(newFixture(body, shape, 1.0f), Acquire::NORETAIN);
+ body->retain();
+ return body.get();
}
CircleShape *Physics::newCircleShape(float x, float y, float radius)
@@ -76,16 +136,6 @@ CircleShape *Physics::newCircleShape(float x, float y, float radius)
return new CircleShape(s);
}
-PolygonShape *Physics::newRectangleShape(float w, float h)
-{
- return newRectangleShape(0, 0, w, h, 0);
-}
-
-PolygonShape *Physics::newRectangleShape(float x, float y, float w, float h)
-{
- return newRectangleShape(x, y, w, h, 0);
-}
-
PolygonShape *Physics::newRectangleShape(float x, float y, float w, float h, float angle)
{
b2PolygonShape *s = new b2PolygonShape();
@@ -109,54 +159,24 @@ EdgeShape *Physics::newEdgeShape(float x1, float y1, float x2, float y2, bool on
return new EdgeShape(s);
}
-int Physics::newPolygonShape(lua_State *L)
+PolygonShape *Physics::newPolygonShape(const Vector2 *coords, int count)
{
- int argc = lua_gettop(L);
-
- bool istable = lua_istable(L, 1);
-
- if (istable)
- argc = (int) luax_objlen(L, 1);
-
- if (argc % 2 != 0)
- return luaL_error(L, "Number of vertex components must be a multiple of two.");
-
// 3 to 8 (b2_maxPolygonVertices) vertices
- int vcount = argc / 2;
- if (vcount < 3)
- return luaL_error(L, "Expected a minimum of 3 vertices, got %d.", vcount);
- else if (vcount > b2_maxPolygonVertices)
- return luaL_error(L, "Expected a maximum of %d vertices, got %d.", b2_maxPolygonVertices, vcount);
+ if (count < 3)
+ throw love::Exception("Expected a minimum of 3 vertices, got %d.", count);
+ else if (count > b2_maxPolygonVertices)
+ throw love::Exception("Expected a maximum of %d vertices, got %d.", b2_maxPolygonVertices, count);
b2Vec2 vecs[b2_maxPolygonVertices];
- if (istable)
- {
- for (int i = 0; i < vcount; i++)
- {
- lua_rawgeti(L, 1, 1 + i * 2);
- lua_rawgeti(L, 1, 2 + i * 2);
- float x = (float)luaL_checknumber(L, -2);
- float y = (float)luaL_checknumber(L, -1);
- vecs[i] = Physics::scaleDown(b2Vec2(x, y));
- lua_pop(L, 2);
- }
- }
- else
- {
- for (int i = 0; i < vcount; i++)
- {
- float x = (float)luaL_checknumber(L, 1 + i * 2);
- float y = (float)luaL_checknumber(L, 2 + i * 2);
- vecs[i] = Physics::scaleDown(b2Vec2(x, y));
- }
- }
+ for (int i = 0; i < count; i++)
+ vecs[i] = Physics::scaleDown(b2Vec2(coords[i].x, coords[i].y));
b2PolygonShape *s = new b2PolygonShape();
try
{
- s->Set(vecs, vcount);
+ s->Set(vecs, count);
}
catch (love::Exception &)
{
@@ -164,72 +184,32 @@ int Physics::newPolygonShape(lua_State *L)
throw;
}
- PolygonShape *p = new PolygonShape(s);
- luax_pushtype(L, p);
- p->release();
- return 1;
+ return new PolygonShape(s);
}
-int Physics::newChainShape(lua_State *L)
+ChainShape *Physics::newChainShape(bool loop, const Vector2 *coords, int count)
{
- int argc = lua_gettop(L)-1; // first argument is looping
+ std::vector vecs;
- bool istable = lua_istable(L, 2);
-
- if (istable)
- argc = (int) luax_objlen(L, 2);
-
- if (argc == 0 || argc % 2 != 0)
- return luaL_error(L, "Number of vertex components must be a multiple of two.");
-
- int vcount = argc/2;
- bool loop = luax_checkboolean(L, 1);
- b2Vec2 *vecs = new b2Vec2[vcount];
-
- if (istable)
- {
- for (int i = 0; i < vcount; i++)
- {
- lua_rawgeti(L, 2, 1 + i * 2);
- lua_rawgeti(L, 2, 2 + i * 2);
- float x = (float)lua_tonumber(L, -2);
- float y = (float)lua_tonumber(L, -1);
- vecs[i] = Physics::scaleDown(b2Vec2(x, y));
- lua_pop(L, 2);
- }
- }
- else
- {
- for (int i = 0; i < vcount; i++)
- {
- float x = (float)luaL_checknumber(L, 2 + i * 2);
- float y = (float)luaL_checknumber(L, 3 + i * 2);
- vecs[i] = Physics::scaleDown(b2Vec2(x, y));
- }
- }
+ for (int i = 0; i < count; i++)
+ vecs.push_back(Physics::scaleDown(b2Vec2(coords[i].x, coords[i].y)));
b2ChainShape *s = new b2ChainShape();
try
{
if (loop)
- s->CreateLoop(vecs, vcount);
+ s->CreateLoop(vecs.data(), count);
else
- s->CreateChain(vecs, vcount, vecs[0], vecs[vcount-1]);
+ s->CreateChain(vecs.data(), count, vecs[0], vecs[count - 1]);
}
catch (love::Exception &)
{
- delete[] vecs;
delete s;
throw;
}
- delete[] vecs;
-
- ChainShape *c = new ChainShape(s);
- luax_pushtype(L, c);
- c->release();
- return 1;
+ return new ChainShape(s);
}
DistanceJoint *Physics::newDistanceJoint(Body *body1, Body *body2, float x1, float y1, float x2, float y2, bool collideConnected)
diff --git a/src/modules/physics/box2d/Physics.h b/src/modules/physics/box2d/Physics.h
index 6d3305dcd..9c81ffe41 100644
--- a/src/modules/physics/box2d/Physics.h
+++ b/src/modules/physics/box2d/Physics.h
@@ -23,6 +23,8 @@
// LOVE
#include "common/Module.h"
+#include "common/Vector.h"
+
#include "World.h"
#include "Contact.h"
#include "Body.h"
@@ -93,10 +95,15 @@ public:
Body *newBody(World *world, Body::Type type);
/**
- * Creates a new CircleShape at (0, 0).
- * @param radius The radius of the circle.
+ * Convenience functions for creating a Body, Shape, and Fixture all in one
+ * call. The body's world position is the center/average of the given
+ * coordinates, and the shape is centered at the local origin.
**/
- CircleShape *newCircleShape(float radius);
+ Body *newCircleBody(World *world, Body::Type type, float x, float y, float radius);
+ Body *newRectangleBody(World *world, Body::Type type, float x, float y, float w, float h, float angle);
+ Body *newPolygonBody(World *world, Body::Type type, const Vector2 *coords, int count);
+ Body *newEdgeBody(World *world, Body::Type type, float x1, float y1, float x2, float y2, bool oneSided);
+ Body *newChainBody(World *world, Body::Type type, bool loop, const Vector2 *coords, int count);
/**
* Creates a new CircleShape at (x,y) in local coordinates.
@@ -106,24 +113,6 @@ public:
**/
CircleShape *newCircleShape(float x, float y, float radius);
- /**
- * Shorthand for creating rectangular PolygonShapes. The rectangle
- * will be created at the local origin.
- * @param w The width of the rectangle.
- * @param h The height of the rectangle.
- **/
- PolygonShape *newRectangleShape(float w, float h);
-
- /**
- * Shorthand for creating rectangular PolygonShapes. The rectangle
- * will be created at (x,y) in local coordinates.
- * @param x The offset along the x-axis.
- * @param y The offset along the y-axis.
- * @param w The width of the rectangle.
- * @param h The height of the rectangle.
- **/
- PolygonShape *newRectangleShape(float x, float y, float w, float h);
-
/**
* Shorthand for creating rectangular PolygonShapes. The rectangle
* will be created at (x,y) in local coordinates.
@@ -148,12 +137,13 @@ public:
/**
* Creates a new PolygonShape from a variable number of vertices.
**/
- int newPolygonShape(lua_State *L);
+ //int newPolygonShape(lua_State *L);
+ PolygonShape *newPolygonShape(const Vector2 *coords, int count);
/**
* Creates a new ChainShape from a variable number of vertices.
**/
- int newChainShape(lua_State *L);
+ ChainShape *newChainShape(bool loop, const Vector2 *coords, int count);
/**
* Creates a new DistanceJoint connecting body1 with body2.
diff --git a/src/modules/physics/box2d/wrap_Physics.cpp b/src/modules/physics/box2d/wrap_Physics.cpp
index 29c3e2e62..7b755f92e 100644
--- a/src/modules/physics/box2d/wrap_Physics.cpp
+++ b/src/modules/physics/box2d/wrap_Physics.cpp
@@ -83,6 +83,177 @@ int w_newBody(lua_State *L)
return 1;
}
+int w_newCircleBody(lua_State *L)
+{
+ World *world = luax_checkworld(L, 1);
+
+ const char *typestr = luaL_checkstring(L, 2);
+ Body::Type btype = Body::BODY_STATIC;
+ if (!Body::getConstant(typestr, btype))
+ return luax_enumerror(L, "Body type", Body::getConstants(btype), typestr);
+
+ float x = (float)luaL_checknumber(L, 3);
+ float y = (float)luaL_checknumber(L, 4);
+ float radius = (float)luaL_checknumber(L, 5);
+
+ Body *body = nullptr;
+ luax_catchexcept(L, [&]() { body = instance()->newCircleBody(world, btype, x, y, radius); });
+
+ luax_pushtype(L, body);
+ body->release();
+ return 1;
+}
+
+int w_newRectangleBody(lua_State *L)
+{
+ World *world = luax_checkworld(L, 1);
+
+ const char *typestr = luaL_checkstring(L, 2);
+ Body::Type btype = Body::BODY_STATIC;
+ if (!Body::getConstant(typestr, btype))
+ return luax_enumerror(L, "Body type", Body::getConstants(btype), typestr);
+
+ float x = (float)luaL_checknumber(L, 3);
+ float y = (float)luaL_checknumber(L, 4);
+ float w = (float)luaL_checknumber(L, 5);
+ float h = (float)luaL_checknumber(L, 6);
+ float angle = (float)luaL_optnumber(L, 7, 0.0);
+
+ Body *body = nullptr;
+ luax_catchexcept(L, [&]() { body = instance()->newRectangleBody(world, btype, x, y, w, h, angle); });
+
+ luax_pushtype(L, body);
+ body->release();
+ return 1;
+}
+
+int w_newPolygonBody(lua_State *L)
+{
+ World *world = luax_checkworld(L, 1);
+
+ const char *typestr = luaL_checkstring(L, 2);
+ Body::Type btype = Body::BODY_STATIC;
+ if (!Body::getConstant(typestr, btype))
+ return luax_enumerror(L, "Body type", Body::getConstants(btype), typestr);
+
+ int argc = lua_gettop(L);
+
+ bool istable = lua_istable(L, 3);
+ if (istable)
+ argc = (int)luax_objlen(L, 3);
+
+ if (argc % 2 != 0)
+ return luaL_error(L, "Number of vertex components must be a multiple of two.");
+
+ int vcount = argc / 2;
+ std::vector coords;
+
+ if (istable)
+ {
+ for (int i = 0; i < vcount; i++)
+ {
+ lua_rawgeti(L, 3, 1 + i * 2);
+ lua_rawgeti(L, 3, 2 + i * 2);
+ float x = (float)luaL_checknumber(L, -2);
+ float y = (float)luaL_checknumber(L, -1);
+ coords.emplace_back(x, y);
+ lua_pop(L, 2);
+ }
+ }
+ else
+ {
+ for (int i = 0; i < vcount; i++)
+ {
+ float x = (float)luaL_checknumber(L, 3 + i * 2);
+ float y = (float)luaL_checknumber(L, 4 + i * 2);
+ coords.emplace_back(x, y);
+ }
+ }
+
+ Body *body = nullptr;
+ luax_catchexcept(L, [&]() { body = instance()->newPolygonBody(world, btype, coords.data(), (int)coords.size()); });
+
+ luax_pushtype(L, body);
+ body->release();
+ return 1;
+}
+
+int w_newEdgeBody(lua_State *L)
+{
+ World *world = luax_checkworld(L, 1);
+
+ const char *typestr = luaL_checkstring(L, 2);
+ Body::Type btype = Body::BODY_STATIC;
+ if (!Body::getConstant(typestr, btype))
+ return luax_enumerror(L, "Body type", Body::getConstants(btype), typestr);
+
+ float x1 = (float)luaL_checknumber(L, 3);
+ float y1 = (float)luaL_checknumber(L, 4);
+ float x2 = (float)luaL_checknumber(L, 5);
+ float y2 = (float)luaL_checknumber(L, 6);
+ bool oneSided = luax_optboolean(L, 7, false);
+
+ Body *body = nullptr;
+ luax_catchexcept(L, [&]() { body = instance()->newEdgeBody(world, btype, x1, y1, x2, y2, oneSided); });
+
+ luax_pushtype(L, body);
+ body->release();
+ return 1;
+}
+
+int w_newChainBody(lua_State *L)
+{
+ World *world = luax_checkworld(L, 1);
+
+ const char *typestr = luaL_checkstring(L, 2);
+ Body::Type btype = Body::BODY_STATIC;
+ if (!Body::getConstant(typestr, btype))
+ return luax_enumerror(L, "Body type", Body::getConstants(btype), typestr);
+
+ bool loop = luax_checkboolean(L, 3);
+
+ int argc = lua_gettop(L) - 3;
+
+ bool istable = lua_istable(L, 4);
+ if (istable)
+ argc = (int)luax_objlen(L, 4);
+
+ if (argc == 0 || argc % 2 != 0)
+ return luaL_error(L, "Number of vertex components must be a multiple of two.");
+
+ int vcount = argc / 2;
+ std::vector coords;
+
+ if (istable)
+ {
+ for (int i = 0; i < vcount; i++)
+ {
+ lua_rawgeti(L, 4, 1 + i * 2);
+ lua_rawgeti(L, 4, 2 + i * 2);
+ float x = (float)lua_tonumber(L, -2);
+ float y = (float)lua_tonumber(L, -1);
+ coords.emplace_back(x, y);
+ lua_pop(L, 2);
+ }
+ }
+ else
+ {
+ for (int i = 0; i < vcount; i++)
+ {
+ float x = (float)luaL_checknumber(L, 4 + i * 2);
+ float y = (float)luaL_checknumber(L, 5 + i * 2);
+ coords.emplace_back(x, y);
+ }
+ }
+
+ Body *body = nullptr;
+ luax_catchexcept(L, [&]() { body = instance()->newChainBody(world, btype, loop, coords.data(), (int)coords.size()); });
+
+ luax_pushtype(L, body);
+ body->release();
+ return 1;
+}
+
int w_newFixture(lua_State *L)
{
Body *body = luax_checkbody(L, 1);
@@ -103,7 +274,7 @@ int w_newCircleShape(lua_State *L)
{
float radius = (float)luaL_checknumber(L, 1);
CircleShape *shape;
- luax_catchexcept(L, [&](){ shape = instance()->newCircleShape(radius); });
+ luax_catchexcept(L, [&](){ shape = instance()->newCircleShape(0, 0, radius); });
luax_pushtype(L, shape);
shape->release();
return 1;
@@ -132,7 +303,7 @@ int w_newRectangleShape(lua_State *L)
float w = (float)luaL_checknumber(L, 1);
float h = (float)luaL_checknumber(L, 2);
PolygonShape *shape;
- luax_catchexcept(L, [&](){ shape = instance()->newRectangleShape(w, h); });
+ luax_catchexcept(L, [&](){ shape = instance()->newRectangleShape(0, 0, w, h, 0); });
luax_pushtype(L, shape);
shape->release();
return 1;
@@ -170,16 +341,91 @@ int w_newEdgeShape(lua_State *L)
int w_newPolygonShape(lua_State *L)
{
- int ret = 0;
- luax_catchexcept(L, [&](){ ret = instance()->newPolygonShape(L); });
- return ret;
+ int argc = lua_gettop(L);
+
+ bool istable = lua_istable(L, 1);
+
+ if (istable)
+ argc = (int)luax_objlen(L, 1);
+
+ if (argc % 2 != 0)
+ return luaL_error(L, "Number of vertex components must be a multiple of two.");
+
+ int vcount = argc / 2;
+ std::vector coords;
+
+ if (istable)
+ {
+ for (int i = 0; i < vcount; i++)
+ {
+ lua_rawgeti(L, 1, 1 + i * 2);
+ lua_rawgeti(L, 1, 2 + i * 2);
+ float x = (float)luaL_checknumber(L, -2);
+ float y = (float)luaL_checknumber(L, -1);
+ coords.emplace_back(x, y);
+ lua_pop(L, 2);
+ }
+ }
+ else
+ {
+ for (int i = 0; i < vcount; i++)
+ {
+ float x = (float)luaL_checknumber(L, 1 + i * 2);
+ float y = (float)luaL_checknumber(L, 2 + i * 2);
+ coords.emplace_back(x, y);
+ }
+ }
+
+ PolygonShape *shape = nullptr;
+ luax_catchexcept(L, [&](){ shape = instance()->newPolygonShape(coords.data(), (int)coords.size()); });
+ luax_pushtype(L, shape);
+ shape->release();
+ return 1;
}
int w_newChainShape(lua_State *L)
{
- int ret = 0;
- luax_catchexcept(L, [&](){ ret = instance()->newChainShape(L); });
- return ret;
+ int argc = lua_gettop(L) - 1; // first argument is looping
+
+ bool istable = lua_istable(L, 2);
+
+ if (istable)
+ argc = (int)luax_objlen(L, 2);
+
+ if (argc == 0 || argc % 2 != 0)
+ return luaL_error(L, "Number of vertex components must be a multiple of two.");
+
+ int vcount = argc / 2;
+ bool loop = luax_checkboolean(L, 1);
+ std::vector coords;
+
+ if (istable)
+ {
+ for (int i = 0; i < vcount; i++)
+ {
+ lua_rawgeti(L, 2, 1 + i * 2);
+ lua_rawgeti(L, 2, 2 + i * 2);
+ float x = (float)lua_tonumber(L, -2);
+ float y = (float)lua_tonumber(L, -1);
+ coords.emplace_back(x, y);
+ lua_pop(L, 2);
+ }
+ }
+ else
+ {
+ for (int i = 0; i < vcount; i++)
+ {
+ float x = (float)luaL_checknumber(L, 2 + i * 2);
+ float y = (float)luaL_checknumber(L, 3 + i * 2);
+ coords.emplace_back(x, y);
+ }
+ }
+
+ ChainShape *shape = nullptr;
+ luax_catchexcept(L, [&]() { shape = instance()->newChainShape(loop, coords.data(), coords.size()); });
+ luax_pushtype(L, shape);
+ shape->release();
+ return 1;
}
int w_newDistanceJoint(lua_State *L)
@@ -573,6 +819,11 @@ static const luaL_Reg functions[] =
{
{ "newWorld", w_newWorld },
{ "newBody", w_newBody },
+ { "newCircleBody", w_newCircleBody },
+ { "newRectangleBody", w_newRectangleBody },
+ { "newPolygonBody", w_newPolygonBody },
+ { "newEdgeBody", w_newEdgeBody },
+ { "newChainBody", w_newChainBody },
{ "newFixture", w_newFixture },
{ "newCircleShape", w_newCircleShape },
{ "newRectangleShape", w_newRectangleShape },