My approach has been to limit what is exposed to Lua as much as possible. I have never found a need for a "main" or other such function which is called every time the scene is rendered (or more). Some Lua engines (like LOVE) do this however. I prefer to define objects with optional callback functions for common events that you may want the object to respond to such as a collision, mouse click, entering or leaving the game world, etc..
The end result is very declarative, almost a config file for objects. I have a function for creating classes or types of objects and another for creating objects based on these types. The objects then have a collection of methods which can be called when responding to various events. All of these Lua methods map to C/C++ methods which in turn modify the object's private properties. Here is an example of a bucket object which can capture ball objects:
define {
name='ball';
texture=png('images/orb.png');
model='active';
shape='circle';
radius=16;
mass=1.0;
elastic=.7;
friction=.4;
}
define {
name='bucket';
model='active';
mass=1;
shape='rect';
width=60;
height=52;
texture=png('images/bucket.png');
elastic=.5;
friction=.4;
oncontact = function(self, data)
if data.subject:type() == 'ball' then
local a = data.subject:angleTo(self:getxy())
if a < 130 and a > 50 then
--update score etc..
end
end
end;
}
I would not take this as the "one true way" to implement your scripting API. One of the beauties of Lua is that it supports many different styles of API. This is just what I have found works well for the games that I make - 2D physics based games.