Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Box2d Lua module #8712

Merged
merged 15 commits into from Apr 3, 2024
1 change: 1 addition & 0 deletions engine/engine/src/engine.cpp
Expand Up @@ -1305,6 +1305,7 @@ namespace dmEngine
script_lib_context.m_HidContext = engine->m_HidContext;
script_lib_context.m_GraphicsContext = engine->m_GraphicsContext;
script_lib_context.m_JobThread = engine->m_JobThreadContext;
script_lib_context.m_ConfigFile = engine->m_Config;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To allow for reading game properties, like physics.scale


if (engine->m_SharedScriptContext) {
script_lib_context.m_ScriptContext = engine->m_SharedScriptContext;
Expand Down
25 changes: 24 additions & 1 deletion engine/gamesys/src/gamesys/components/comp_collision_object.cpp
Expand Up @@ -931,7 +931,7 @@ namespace dmGameSystem
dmMessage::ResetURL(receiver);
receiver->m_Socket = dmGameObject::GetMessageSocket(collection);
receiver->m_Path = dmGameObject::GetIdentifier(sender_instance);

dmPhysics::RayCastRequest request;
request.m_From = ddf->m_From;
request.m_To = ddf->m_To;
Expand Down Expand Up @@ -2139,4 +2139,27 @@ namespace dmGameSystem
pit->m_Next = 0;
pit->m_FnIterateNext = CompCollisionIterPropertiesGetNext;
}

b2World* CompCollisionObjectGetBox2DWorld(void* _world)
{
CollisionWorld* world = (CollisionWorld*)_world;
if (world->m_3D)
return 0;
return (b2World*)dmPhysics::GetWorldContext2D(world->m_World2D);
}

b2Body* CompCollisionObjectGetBox2DBody(void* _component)
{
CollisionComponent* component = (CollisionComponent*)_component;
if (component->m_3D)
return 0;
return (b2Body*)dmPhysics::GetCollisionObjectContext2D(component->m_Object2D);
}

// We use this to determine if a physics object is still alive, by determinig if the game object is still alive
dmGameObject::HInstance CompCollisionObjectGetInstance(void* _user_data)
{
CollisionComponent* component = (CollisionComponent*)_user_data; // See SetCollisionObjectData and dmPhysics::NewCollisionObject2D
return component->m_Instance;
}
}
9 changes: 9 additions & 0 deletions engine/gamesys/src/gamesys/components/comp_collision_object.h
Expand Up @@ -26,6 +26,9 @@

template <typename T> class dmArray;

class b2World;
class b2Body;

namespace dmGameSystem
{
dmGameObject::CreateResult CompCollisionObjectNewWorld(const dmGameObject::ComponentNewWorldParams& params);
Expand Down Expand Up @@ -102,6 +105,12 @@ namespace dmGameSystem
bool GetShapeIndex(void* _component, dmhash_t shape_name_hash, uint32_t* index_out);
bool GetShape(void* _world, void* _component, uint32_t shape_ix, ShapeInfo* shape_info);
bool SetShape(void* _world, void* _component, uint32_t shape_ix, ShapeInfo* shape_info);


// For script_box2d.cpp
b2World* CompCollisionObjectGetBox2DWorld(void* _world);
b2Body* CompCollisionObjectGetBox2DBody(void* _component);
dmGameObject::HInstance CompCollisionObjectGetInstance(void* _user_data);
}

#endif // DM_GAMESYS_COMP_COLLISION_OBJECT_H
1 change: 1 addition & 0 deletions engine/gamesys/src/gamesys/gamesys.h
Expand Up @@ -156,6 +156,7 @@ namespace dmGameSystem
dmGraphics::HContext m_GraphicsContext;
dmJobThread::HContext m_JobThread;
dmScript::HContext m_ScriptContext;
dmConfigFile::HConfig m_ConfigFile;
};


Expand Down
3 changes: 3 additions & 0 deletions engine/gamesys/src/gamesys/gamesys_script.cpp
Expand Up @@ -38,6 +38,7 @@
#include "scripts/script_sys_gamesys.h"
#include "scripts/script_camera.h"
#include "scripts/script_http.h"
#include "scripts/box2d/script_box2d.h"

#include "components/comp_gui.h"

Expand Down Expand Up @@ -138,6 +139,7 @@ namespace dmGameSystem
ScriptParticleFXRegister(context);
ScriptTileMapRegister(context);
ScriptPhysicsRegister(context);
ScriptBox2DInitialize(context);
ScriptFactoryRegister(context);
ScriptCollectionFactoryRegister(context);
ScriptSpriteRegister(context);
Expand All @@ -159,6 +161,7 @@ namespace dmGameSystem
ScriptCollectionProxyFinalize(context);
ScriptLabelFinalize(context);
ScriptPhysicsFinalize(context);
ScriptBox2DFinalize(context);
ScriptResourceFinalize(context);
ScriptWindowFinalize(context);
ScriptSysGameSysFinalize(context);
Expand Down
167 changes: 167 additions & 0 deletions engine/gamesys/src/gamesys/scripts/box2d/script_box2d.cpp
@@ -0,0 +1,167 @@
// Copyright 2020-2024 The Defold Foundation
// Copyright 2014-2020 King
// Copyright 2009-2014 Ragnar Svensson, Christian Murray
// Licensed under the Defold License version 1.0 (the "License"); you may not use
// this file except in compliance with the License.
//
// You may obtain a copy of the License, together with FAQs at
// https://www.defold.com/license
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

#include <stdio.h>

#include <Box2D/Dynamics/b2Body.h>
#include <Box2D/Dynamics/Joints/b2Joint.h>

#include <dlib/log.h>
#include <gameobject/script.h>

#include "gamesys.h"
#include "gamesys_private.h"

#include "components/comp_collision_object.h"

#include "script_box2d.h"

extern "C"
{
#include <lua/lauxlib.h>
#include <lua/lualib.h>
}

namespace dmGameSystem
{
//////////////////////////////////////////////////////////////////////////////

static float g_PhysicsScale = 1.0f;
static float g_InvPhysicsScale = 1.0f / g_PhysicsScale;

//////////////////////////////////////////////////////////////////////////////
// b2Vec2

b2Vec2 CheckVec2(lua_State* L, int index, float scale)
{
dmVMath::Vector3* v = dmScript::CheckVector3(L, index);
return b2Vec2(v->getX() * scale, v->getY() * scale);
}

dmVMath::Vector3 FromB2(const b2Vec2& p, float inv_scale)
{
return dmVMath::Vector3(p.x * inv_scale, p.y * inv_scale, 0);
}

void PushWorld(struct lua_State* L, class b2World* world)
{
lua_pushlightuserdata(L, world);
}

void SetPhysicsScale(float scale)
{
g_PhysicsScale = scale;
g_InvPhysicsScale = 1.0f / g_PhysicsScale;
}

float GetPhysicsScale()
{
return g_PhysicsScale;
}

float GetInvPhysicsScale()
{
return g_InvPhysicsScale;
}

//////////////////////////////////////////////////////////////////////////////

static void GetCollisionObject(lua_State* L, int index, dmGameObject::HCollection collection, dmMessage::URL* url, void** comp, void** comp_world)
{
dmGameObject::GetComponentUserDataFromLua(L, index, collection, COLLISION_OBJECT_EXT, (uintptr_t*)comp, url, comp_world);
}

static int B2D_GetWorld(lua_State* L)
{
DM_LUA_STACK_CHECK(L, 1);

dmGameObject::HCollection collection = dmGameObject::GetCollection(CheckGoInstance(L));
uint32_t component_type_index = dmGameObject::GetComponentTypeIndex(collection, COLLISION_OBJECT_EXT_HASH);
void* comp_world = dmGameObject::GetWorld(collection, component_type_index);
b2World* world = dmGameSystem::CompCollisionObjectGetBox2DWorld(comp_world);

if (world)
PushWorld(L, world);
else
lua_pushnil(L);
return 1;
}

static int B2D_GetBody(lua_State* L)
{
DM_LUA_STACK_CHECK(L, 1);

dmGameObject::HCollection collection = dmGameObject::GetCollection(CheckGoInstance(L));
dmMessage::URL url;
void* component = 0;
GetCollisionObject(L, 1, collection, &url, &component, 0);

b2Body* body = dmGameSystem::CompCollisionObjectGetBox2DBody(component);

if (body)
PushBody(L, body, collection, url.m_Path);
else
lua_pushnil(L);
return 1;
}

static const luaL_reg BOX2D_FUNCTIONS[] =
{
{"get_world", B2D_GetWorld},
{"get_body", B2D_GetBody},

{0, 0}
};

void ScriptBox2DInitialize(const ScriptLibContext& context)
{
float physics_scale_default = 1.0f;
float physics_scale = context.m_ConfigFile ? dmConfigFile::GetFloat(context.m_ConfigFile, "physics.scale", physics_scale_default) : physics_scale_default;
SetPhysicsScale(physics_scale);

lua_State* L = context.m_LuaState;

luaL_register(L, "b2d", BOX2D_FUNCTIONS);

ScriptBox2DInitializeBody(L);

lua_pop(L, 1); // pop the lua module
}

void ScriptBox2DFinalize(const ScriptLibContext& context)
{
(void)context;
}
}


/*# Box2D documentation
*
* Functions for interacting with Box2D.
*
* @document
* @name b2d
*/

/** Get the Box2D world from the current collection
* @name b2d.get_world
* @return world [type: b2World] the world if successful. Otherwise `nil`.
*/

/*# Get the Box2D body from a collision object
* @name b2d.get_body
* @param url [type: url] the url to the game object collision component
* @return body [type: b2Body] the body if successful. Otherwise `nil`.
*/

48 changes: 48 additions & 0 deletions engine/gamesys/src/gamesys/scripts/box2d/script_box2d.h
@@ -0,0 +1,48 @@
// Copyright 2020-2024 The Defold Foundation
// Copyright 2014-2020 King
// Copyright 2009-2014 Ragnar Svensson, Christian Murray
// Licensed under the Defold License version 1.0 (the "License"); you may not use
// this file except in compliance with the License.
//
// You may obtain a copy of the License, together with FAQs at
// https://www.defold.com/license
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

#ifndef DM_GAMESYS_SCRIPT_BOX2D_H
#define DM_GAMESYS_SCRIPT_BOX2D_H

#include <dmsdk/dlib/hash.h>
#include <dmsdk/dlib/vmath.h>
#include <Box2D/Common/b2Math.h>

namespace dmGameObject
{
typedef struct CollectionHandle* HCollection;
}

namespace dmGameSystem
{
void ScriptBox2DInitialize(const struct ScriptLibContext& context);
void ScriptBox2DFinalize(const struct ScriptLibContext& context);

// internal

float GetPhysicsScale();
float GetInvPhysicsScale();

b2Vec2 CheckVec2(struct lua_State* L, int index, float scale);
dmVMath::Vector3 FromB2(const b2Vec2& p, float inv_scale);

void PushWorld(struct lua_State* L, class b2World* world);

void PushBody(struct lua_State* L, class b2Body* body, dmGameObject::HCollection collection, dmhash_t gameobject_id);
class b2Body* CheckBody(lua_State* L, int index);

void ScriptBox2DInitializeBody(struct lua_State* L);
}

#endif // DM_GAMESYS_SCRIPT_BOX2D_H