Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm struggling to get Lua implemented into my game engine. I've read dozens of blogs and articles revolving around how to wrap C++ classes and I seem to have hit a wall. No matter how I structure the code I can't figure out a logic path that doesn't involve creating global variables in my project so the Lua helper functions can access the core of my engine.

Let me start off by explaining the end goal. I want to have an entities folder which holds scripts that describe unique spawnable entities within the game. A typical file would look like this:

function ENTITY:Initialize()
    --Do stuff when the entity is initialized
    self:SetModel("models/2x2x2-plate.obj")
    self:SetPosition(Vector3D(100,100,100))
end

function ENTITY:Think()
    --Do stuff every time the entity thinks
    self:SetVelocity(Vector3D(0,0,100))
end

The file name of this .Lua file would be a unique identifier to create an entity of this type from within other scripts.

local MyEnt = Entities.Create("MyCustomEntity")
MyEnt:Spawn()

What would seem like an easier way to accomplish this task would be to set it up so scripts look like this:

Entities.Add( "MyCustomEntity", {
    PrintName = "My Custom Entity",

    Initialize = function( self )
        --Do stuff when the entity is initialized
        self:SetModel("models/2x2x2-plate.obj")
        self:SetPosition(Vector3D(100,100,100))
    end,

    Think = function ( self )
        --Do stuff every time the entity thinks
        self:SetVelocity(0,0,100)
    end
} )

However I feel like I would loose some functionality if it were setup like that.

On the C++ side of things a class called BaseEntity would be where these entity scripts would inherit all their functions from.

I've been able to figure out the following on my own so far

#include <lua.hpp>
#include "LuaActor.h"
#include "BaseActor.hpp"

BaseActor* Check_BaseActor(lua_State* L)
{
    luaL_checktype(L, 1, LUA_TUSERDATA);
    return (BaseActor*)reinterpret_cast<BaseActor*>(lua_touserdata(L, 1));
}

int LuaActor_Create(lua_State* L)
{
    BaseActor** Actor = (BaseActor**)lua_newuserdata(L, sizeof(BaseActor*));
    *Actor = new BaseActor();
    luaL_getmetatable(L, "Actors");
    lua_setmetatable(L, -2);

    return 1;
}

int LuaActor_Destroy(lua_State* L)
{
    // Do something when Actor is removed from the lua environment
    BaseActor* Actor = Check_BaseActor(L);
    return 0;
}

int LuaActor_SetIndex(lua_State* L)
{
    BaseActor* Actor = Check_BaseActor(L);

    luaL_checktype(L, 2, LUA_TNUMBER);
    const int Index = lua_tointeger(L, 2);
    Actor->SetIndex(Index);

    return 0;
}

int LuaActor_GetIndex(lua_State* L)
{
    BaseActor* Actor = Check_BaseActor(L);

    lua_pushnumber(L, Actor->GetIndex());

    return 1;
}





static const luaL_reg LuaActor_Funcs[] =
{
    { "Create", LuaActor_Create },
    { NULL, NULL }
};

static const luaL_reg LuaActor_Methods[] =
{
    { "__gc", LuaActor_Destroy },
    { "SetIndex", LuaActor_SetIndex },
    { "GetIndex", LuaActor_GetIndex },
    { NULL, NULL }
};

void Register_LuaActor(lua_State* L)
{
    luaL_newmetatable(L, "Actors");
    lua_pushstring(L, "__index");
    lua_pushvalue(L, -2);
    lua_settable(L, -3);

    luaL_openlib(L, 0, LuaActor_Methods, 0);
    luaL_openlib(L, "Actors", LuaActor_Funcs, 0);
}

This gives me the ability to do things such as local MyActor = Actors.Create()

I can't find any information about doing what I described in the 2nd paragraph. I also understand that I should let the garbage collector manage deletion of any C++ objects created through Lua which confuses me on how I should track my entities on the C++ side. I have an ActorHandler class which holds a std::vector of all my entities. This class loops through each entity every game tick calling their Update() functions, the entities are also accessed from other classes such as physics and networking via their unique entity id's to apply positional and collision updates. I am very confused on how I should keep track of entities on the C++ side which were created on the Lua side and still be able to call their Lua callback functions from within C++.

I've found out that you can create references to your Lua objects within C++ to quickly access the Lua object again but I can't find any articles describing how to advantageously use this feature.

Any help would be greatly appreciated and I can give more information if needed.

share|improve this question
    
Not a real answer, but have you tried looking at existing implementations? For example LuaBridge? It might provide useful hits to how things can/should be done. –  Martinsh Shaiters Jul 20 at 10:36
    
I was looking through LuaWrapper which didn't help for going from C++ back into lua. I'm looking at LuaBridge now, hopefully it can shed some light while waiting for more information here. Thank you. –  KKlouzal Jul 20 at 10:43
    
Not really an answer since it doesn't use Lua but since I had some time on my hands and I was curious about how it would look exactly in code, I tried to implement a part of your system using my scripting engine - SGScript (sgscript.org). You can download the code (precompiled Windows x86 binaries are included) here: sgscript.org/files/sgs-entities.zip P.S. Please let me know if there's anything important missing from the example or just anything else that you'd like to see there. I'm looking for as many use cases for testing as I can get my hands on. :) –  snake5 Jul 20 at 12:47

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.