Lua Scripting Just Have Been Added

While I was doing the porting, I have found SWIG, a very useful tool for Lua integration. Actually it supports so many other languages and interfaces, but I was interested only in game scripting so far.

Why scripting? Scripting is an important feature of a typical game engine, and Merlin3D is not an exception. Prototyping, game and GUI coding is much more easy if I do not have to recompile the whole game engine or DLL. With SWIG adding scripting to the engine is quite easy, so it seemed to worth a try.

Why Lua? There were some other options like GameMonkey, AngelScript or Pawn, but finally I have chosen Lua because it is widespread, well supported, fast, easy to learn and SWIG makes integration easy. Obviously it is not the perfect choice. For example AngelScript has simpler C++ interface, it has static type system and it is truly object-oriented, but not as fast as Lua, it has less support and SWIG does not know it at all.

The language is dynamically typed and it is a drawback from the user’s point of view. The scripting interface has to check parameter types on each call to engine functions. With a statically typed language those checks are performed at compile time, only few type checks are performed at runtime. This is why I thought of using static typed AngelScript, maybe I would switch on it some day… 🙂

After some interface definition and C++ template hacking, the scripting seems to work now. All important scene, game and UI classes are exposed in the Lua interface. I can create scene and game objects, register UI and game event handlers, execute engine startup scripts, etc. In this picture, the “CLICK ME!” button is created and inserted by a script. The click event is also handled by a script, this inserts new labels under the button on each click.

I have replaced the static XML config file processing too with a single Lua script that initialize the engine, register console variables, loads the initial scene, UI, HUD and so on. I can get rid of the XML processing on this part of the code now. This is a part of the initialization script:

M3D.Console_RegisterVariable("LockViewFrustum", "Disables view frustum updates.", false);

M3D.Console_WriteLine("Starting up engine...")
engine = M3D.Engine()

engine:LoadCompositorGraph("Data/Config/DeferredTest.xcg")
engine:LoadUISkin("Data/UI/Default.xskin")
engine:LoadUI("Data/Test/Menu.xui")
engine:LoadHUD("Data/Test/HUD.xui")
engine:LoadWorld("Data/Test/Test.xscn")

engine:GetDesktop():SetVisible(false)

button = M3D.Button()
button:SetName("TestButton1")
button:SetText("CLICK ME!")
button:SetSize(M3D.V2f(10, 24))
button:SetLayoutMode(M3D.LayoutItem_DockTop);
button:SetVisible(true)
button:SetClickAction("ButtonClick()")
engine:GetDesktop():FindElement("SimOptionsPanel"):AddChild(button)

engine:Run()

Lua has own object lifetime management, so I should take extra care about the classes those are managed by the engine. By default, Lua manages its own objects, so I have to tell Lua interpreter to not delete objects I want to create and pass to the engine from a script but it seems to be a quite small cost for a working scripting system in return.

There is only one more small thing remaining for me. Maybe I could create a language pack for Notepad++ to support highlighting and autocompleting for my own engine objects, but I do not know how much work needed to complete this.

Advertisements

Posted on October 27, 2011, in C++, game engine, scripting and tagged , , , . Bookmark the permalink. 4 Comments.

  1. The more I code in Ruby and Lua the more I dislike ‘done’ and ‘end’ for making me type what should be implicit

  2. Hi!

    Indeed SWIG it’s a very viable choice for implementing scripting with ease.

    About this last part in which you mention managing objects, have you considered exposing your instances as boost::shared_ptr’s?

    You need to add this snippet to your .i file in order to have them in lua

    namespace boost
    {
        template<class T>
        class shared_ptr
        {
            public:
                T *     operator-> () const;
                void    reset();
                T *     get() const;
        };
    }
    

    Cheers!

    PS: Do we know eachother from gamedev?

    • Hi,

      Thanks for replying, yes, I have very similar solution, but I have my own set of smart pointers for object management, and of course, I have added them to the interface as well as my string and other container templates. This was the more time consuming part of the implementation, otherwise the SWIG made the whole thing very easy. The generated C++ wrapper file contains more than 25 000 lines, this is much more than I would like to write by hand…. 🙂

      Cheerio!

      PS: I think we met here on WordPress.com, I am following your blog. Anyway, I have difficulties with gamedev, some features aren’t working for me, maybe due to some browser incompatibility problems or something like that, so I can not do much things on that site. |:-/

  1. Pingback: Scripting is Fully Functional « Merlin3d

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: