Blog de programación e ideas locas

Desarrollo: Programando con Lua

by on Ene.08, 2012, under Desarrollo, EGa2Dengine, Engine

Hoy dia, evitando mis quehaceres como siempre.
Me dedique a programar un ratito con Lua, no hice la gran cosa pero vamos bien encaminado.

template
class LuaType {
protected:
private:
    T valor; //!< Contiene el valor que estamos Wrappeando
public:
    /**
      * \brief Crea una nueva variable lista, para ser pasada a Lua
      */
    LuaType(const T t):valor(t) {};
    /**
      * \brief Extrae un valor en la pila, pero sin borrarlo
      */
    LuaType(lua_State *L,int i = -1);

    /**
      * \brief Pone este valor en la sima de la pila de Lua
      *
      * \param L estado actual de Lua
      */
    void pushValue(lua_State *L);

    /**
      * \brief Esta funcion permite recuperar el tipo original de la variable
      *
      * Ejemplo:

      * <code>
 * LuaType entero(5);
 * int variable_normal = (int)entero;
 * </code>
      * <code>
 * LuaType cadena("Hola Lua");
 * char *string = (char *)cadena;
 * </code>
      * \return el valor de la variable del tipo de este template
      */
    operator T() const {
        return valor;
    }

};

Primero lo que fue es crear una plantilla de una clase Wrapper, la cual me permitira extraer y colocar variables entre Lua y C++.

Usando especialización de templates (plantillas) podemos especificar como agregaremos cada tipo de variable en lua.

template<> LuaType::LuaType(lua_State *L,int i) {
    if(!lua_isnumber(L,i)) {
        luaL_error(L,"Argumento incorrecto");
    }
    valor  = lua_tointeger(L,i);
};

template<> LuaType::LuaType(lua_State *L,int i) {
    if(!lua_isnumber(L,i)) {
        luaL_error(L,"Argumento incorrecto");
    }
    valor  = static_cast(lua_tonumber(L,i)); // -1 top stack
};

template<> LuaType::LuaType(lua_State *L,int i) {
    if(!lua_isnumber(L,i)) {
        luaL_error(L,"Argumento incorrecto");
    }
    valor  = lua_tonumber(L,i); // -1 top stack
};

template<> LuaType::LuaType(lua_State *L,int i) {
    if(!lua_isstring(L,i)) {
        luaL_error(L,"Argumento incorrecto");
    }
    valor = const_cast(lua_tostring(L,i)); // -1 top stack
};

template<> LuaType::LuaType(lua_State *L,int i) {
    if(!lua_isuserdata(L,i)) {
        luaL_error(L,"Argumento incorrecto");
    }
    valor  = lua_touserdata(L,i);
};

Conviertiendo valores de la Pila de Lua a variables en C++

template<> void LuaType::pushValue(lua_State *L) {
    lua_pushinteger(L,valor);
}
template<> void LuaType::pushValue(lua_State *L) {
    lua_pushnumber(L,valor);
}
template<> void LuaType::pushValue(lua_State *L) {
    lua_pushnumber(L,valor);
}

template<> void LuaType::pushValue(lua_State *L) {
    lua_pushstring(L,valor);
}

template<> void LuaType::pushValue(lua_State *L) {
    lua_pushlightuserdata(L,valor);
}

Pasando las variables a Lua.

Parece que todo este código es muy engorroso, pero sin embargo nos facilitará más adelante para programar una clase proxy (la que nos facilitará el uso de estructuras o clases definidas en C++ en Lua)

Ejemplo:

#include <cstdio>
#include <cstdlib>
#include <EGa2D/Lua/Type.h>
#include <EGa2D/Lua/Member.h>

using namespace EGa2D;
using namespace Lua;

char *script = "print(string,entero)\nfuncion(entero,string)";

int funcion(lua_State *L){
    int n = lua_gettop(L);    /* number of arguments */
    LuaType<int> v1(L,1);
    LuaType<char *> v2(L,2);
    lua_settop(L,0); //borramos todo
    printf("%d %s",(int)v1,(char *)v2);
    return 0;
};

int main(int argc,char **argv){
    lua_State *L;
    L = lua_open();//abrimos lua
    luaL_openlibs(L); //con todas sus bibliotecas

    LuaType<int> entero = 5;
    entero.pushValue(L);
    lua_setglobal(L, "entero");

    LuaType<char*> string = "Holaaa";
    string.pushValue(L);
    lua_setglobal(L, "string");

    lua_pushcfunction(L,funcion);
    lua_setglobal(L, "funcion");

    if(luaL_dostring(L,script)){
        printf("Error %s\n",lua_tostring(L, -1));
    }

    if(L) {
        lua_gc(L, LUA_GCCOLLECT, 0);  // collected garbage
        lua_close(L);
    }

    return 0;
}

La idea de usar un Wrapper de los tipos de variables en C++ no es idea mía pero, lo vi programado en codigo que hacia lo mismo pero para una versión vieja de Lua. Así que quise probarlo y hasta el momento me ha traído algunos beneficios al programar (el código se vuelve más sencillo), y bueno espero poder terminar rápido, para poder implementarle scripting al juego y así volverlo más flexible a la hora de programar

Saludos

:, , , , , , , , , ,