Skip to main content
gamedev.net
🔒 Locked 🎯 Unreal

LUA: (Derived) objects: lua to C++ and back

Started by sordid Sep 20, 2005 at 4:43 AM 0 replies 2.8k views
Original Post
sordid
sordid
Ok, so I've been plugging away catching up on LuaBind for the last few days, and my main hang up is the usage of C++ and Lua objects together. I've read and reread the luabind docs and mailing list and I believe I've come up with a solution to my problem, albeit it appears to be an "ugly" one. It also requires the lua/luabind headers, and subsequently the necessary boost headers as well, to be included in every header that contains a class declaration I wisht o expose to Lua. At any rate, my goal is as follows: - The ability to create a derived class from a bound C++ class (easy) - The ability to pass an object created within Lua (from an exposed C++ class 'template') to a bound C++ function or member function as a parameter and have the C++ code be able to modify its member variables (easy) - The ability to have this Lua-created object passed back to a script and have any variables or lua-derived class methods still exist (hard) My first take on it was a severe miss.. what I did was create the object normally in Lua, and pass it to a bound C++ class member function. The parameter in C++ was, naturally, its own C++ class name (ie. void some_member(TestClass *self)). This did work, but when I passed it back to Lua, all the added variables and stuff I did in script disappeared. As soon as this happened, I knew exactly why. What I needed to do was, within the C++ object instance, be able to record any changes/additions to the lua version of the object within C++ itself. Why? Well, I plan on having all Entity/Actor creation done within the scripts. However, my scene manager and spatial partitioner are in C++ for speed. This means I need to have functions available to the script to add/remove objects from the scene manager, which is the simple part. At the same time, since the C++ Actor class will be the base class and the script will contain the derived versions used in-game (Vessels, Planets, etc in my case), all this extra information must be retained when the scene manager "Ticks" the entity per update and calls the object's scripted Tick class member function. (ie. an extra luabind::object must exist in C++ to record this derived/added data, or atleast it appears that way to me) So this is the best I could come up with at 4AM. I consider it a personal breakthrough in my adventures with scripting, yet I can't help but wonder if there's an easier way to do this. I don't like the build times of source files that include LuaBind. I've tried to do my homework, but I've found the public Lua/LuaBind embedding knowledge base to be kind of sketchy at best. Either that, or I'm looking for the wrong keywords. The C++ code:

   class TestClass
   {
   public:
      TestClass(luabind::object b, int a)
      {
         this->a = a;

// get our lua-derived object instance for record
         m_self = b;
      }
      int get() const
      {
         return a;
      }
      void set(int a)
      {
         this->a = a;
      }
      // retrieve the interface to the derived lua object instance
      luabind::object getSelf()
      {
         return m_self;
      }

      // this would be called by the SceneManager
      void Tick()
      {
         luabind::call_member<int>(m_self, "Tick");
      }

   private:
      int a;

      luabind::object m_self;
   };

   int Cpassthrough(luabind::object b)
   {
      TestClass *C;

      C = luabind::object_cast<TestClass*>(b);
      C->set(2);

      luabind::call_member<int>(b, "member_func");

      return FALSE;
   }

...(in main())
     module(L, "my_namespace")
      [
         class_<TestClass>("Test")
            .def(constructor<luabind::object, int>())
            .def("get", &TestClass::get)
            .def("set", &TestClass::set)
            .def("getSelf", &TestClass::getSelf),
         def("Cpassthrough", &Cpassthrough)
      ];

      if (lua_dofile(L, SCRIPT_DIR"/test.lua") == FALSE)
      {
         try {
            call_function<int>(L, "main");
...











The Lua code:

class 'test_derived' (my_namespace.Test)

function test_derived:__init(v)
-- Record our derived instance of this object in the C++ instance.         
	super(self, v)
end

function test_derived:Tick()
    -- do nothing at the moment
end

function test_derived:test_function()
	print('derived class function')
end

-- this is called from C++
function test_derived:member_func()

-- this should print 2
	print(self:get())

-- this should print 200
	print(self.blah)

-- this should print 'derived class function'
	self:test_function()
end

function main()
	a = test_derived(10)
-- this should print 10
	print(a:get())

-- I want to retain the added methods and this variable
	a.blah = 200
	a:test_function()

	my_namespace.Cpassthrough(a)

	return 0
end











The output:

10
derived class function
2
200
derived class function
So, yeah, it works.. but it looks dirty to me. The biggest caveat is that a luabind::object takes the place as a parameter where I would normally have Actor* (ie. in my SceneNode::addActor) which requires massive luabind includes in a bunch of places, and a "luabind::object_cast(LUA_OBJ)" when I want to access the C++ interface for that lua-created object. Is there a better way? [Edited by - sordid on September 20, 2005 1:31:22 PM]

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.