# Unity Which scripting language?

## Recommended Posts

I've been looking into implementing a scripting language into [url=http://scp.indiegames.us]fs2_open[/url], which is the engine of the game Freespace 2 (now open-source.) FS2 uses table files like this:
#Section
$Name: Object name$Variable 1: 10
$Variable 2: moo ;;etc etc... #End Now, what I'd like to do is make it possible to use a scripting language, using one of those variables. EG with Python: #Section$Name: Object name
$Variable 1: cmath.cos(35)$Trigger: {
if conditional:
do_something()
}
#End

The preference of the modding community, however, is Lua. Which is where I run into a problem; Lua doesn't seem to let you precompile code chunks on runtime. Since some of the code chunks may be executed per frame, obviously I don't want it to be parsing the file or some text buffer in memory. In addition, I understand that Python has large memory requirements. So, wish list here for a scripting language (in no particular order): - Precompile code chunks - Allow for object-oriented programming - Small and fast - EASY TO LEARN for non-coders - Lets you use named arrays, eg Array['element'] - Lets you extend variables, functions, classes from C/++ - Is cross-platform (fs2_open runs on Win32, OSX, Linux, and Linux64) - JIT compile to machine code, as long as it doesn't interfere with cross-platformability Thanks. :)

##### Share on other sites
Of course lua lets you precompile at runtime. Consider this code fragment:

ontrigger = function()     if active then print "I'm triggering" endendontrigger()ontrigger()ontrigger()ontrigger()ontrigger()

In that fragment, the ontrigger command is compiled exactly once. If Lua doesn't seem to precompile stuff, it's only because the precompilation is completely transparent.

##### Share on other sites
Indeed. Getting Lua to run a script happens in two stages. First, you load the script, at which point it will be compiled into a function, and second, you run that function. As long as you keep the function around to re-use, you won't have to compile it again.

Secondly, for JIT compilation, you could take a look at LuaJIT. It may or may not speed things up though, depending on what type of code you're running (there are some statistics on the LuaJIT site - take a look and see if it's appropriate).

For JIT compilation in Python, look at Psyco. I don't know how easy it is to set that up when you're got Python embedded in something though.

Python is beefier than Lua, and includes more language features, eg support for classes and so on - you can write Object Oriented code in Lua, but you have a bit more framework to write yourself, since Lua doesn't provide 'classes' as such built-in; it just provides tables and metatables, and you build everything up from those.

Lua and Python aren't the only options of course - you could check out Squirrel (a lot like Lua), AngelScript, Small, GameMonkey, or even something like Guile.

John B

##### Share on other sites
That's not exacly what I mean...I mean that, given a chunk of code, it may be executed at different places within the C code, or simply once a frame, or maybe multiple times per frame.

AFAIK the Lua API only provides functions that will run script from a text file, or buffer.

EG:
$Name: Homing Rocket$Damage: 25 * current_speed

Where "current_speed" is the speed that frame. It's not technically a function; but it still needs to be executed every frame that the weapon damage is needed.

##### Share on other sites
Quote:
 Original post by WMCoolmonThat's not exacly what I mean...I mean that, given a chunk of code, it may be executed at different places within the C code, or simply once a frame, or maybe multiple times per frame.AFAIK the Lua API only provides functions that will run script from a text file, or buffer.

No, as I said, the process happens in two stages. First you load from a text file or buffer (with lua_load), at which point it gets compiled into a function. Then, you call that function with lua_call (or one of the other call functions like lua_pcall). As long as you keep a copy of the function somewhere, you can keep calling it whenever you need it, without having to recompile everything.

John B

##### Share on other sites
In my inexperience with scripting languages, I see lua having the easiest syntax even for non coders. Squirrel, however, has native support for classes, and was made with lua's problems in minds. It, however, has a more C++'y syntax, though it's still easy to learn. Python is, like you've heard, very beefy with a lot of features, but very difficult to get going. In my opinion, squirrel is the best of both worlds. Like they said, you could check out other scripting languages, though I recommend squirrel.

##### Share on other sites
See lua_loadfile() (loads chunk from disk as function onto the stack: can be set to a table and called later at will) and lua_dofile() (executes a chunk from disk (elements defined on root table will be available for later use)):

See: Lua 5.0 Manual

If your fellow programmers are set on using Lua, you should have no problem given your requirements (not clear whether Lua will work OK in a 64 bit environment (support appears to be coming in Lua 5.1)).

However (IMO), Squirrel is easier to use (both script side and C/C++ side (binding/class handling)), and was developed as an improvement to Lua specifically for use in commercial game applications. Those with experience with Lua will have no problem using Squirrel. Lua compared to Squirrel.

Both Squirrel and SqPlus compile and run with gcc. There is an ongoing effort to get Squirrel 100% compatible with 64 bit environments (see the Squirrel forum): it appears a few base typedefs must be changed and Squirrel and SqPlus will compile and run OK in 64 bit.

[Edited by - John Schultz on October 29, 2005 1:12:22 PM]

##### Share on other sites
(I apologize in advance if this post is hideous, I'm trying to finish quickly)

I'm considering Lua 5.1 at the moment (just to learn, don't have any projects going).

I liked Python a lot but, as you've definitely heard, it's *beefy*. But so far it seems that it's already "prettified" a lot of the solutions to problems I'm already starting to see in Lua (for instance, I much prefer Python strings to Lua strings, because there's quite a lot more functionality as soon as the builtins are imported).

An advantage of Lua is that, if a feature you want doesn't exist (read: it exists, but you haven't found it yet), you can build it yourself. Python (I'll assume) is the same way, but is quite a bit more to read before you're really comfortable.

I think Python looks prettier, as well, and, if you're trying to embed it, boost.python makes it much easier than with the native embedding API (?).

Someone above mentioned LuaJIT, which I hadn't even heard of until a month or so ago, so I suppose you can look into that for JIT compiling.

...Did I mention that I think Lua is ugly? In a way, though, I like that Lua doesn't look too much like C/++ -- Python is a little harder to work with for me sometimes (but not by much) because of carry-over C-isms, which Lua's sometimes-foreign syntax avoids.

Python has much better documentation, and it seems like builtin commands connotate well (the words that I would think to use for a situation often are, and I like that).

Embedding python with boost.python is actually a little bit *more* enjoyable than embedding lua, because you avoid the "stack" idea. It's not a huge problem, though, because much of the work is done through the scripts regardless (both languages).

And then, I never did find a good Python debugger. Admittedly, I didn't look very hard, and my code problems came from syntactical errors (again, the C-isms), which were easily solved with the interpreter's help.

This post came out differently than I'd planned -- but I guess a personal comparison won't hurt *too much*.

##### Share on other sites
To either of the two Johns: I understand the lua_load* functions, but how do I get something off the stack, or keep the stack from getting extremely large from loading minor chunks from everywhere?

Edit: And the current status is that three of the principal coders are against it, but a number of modders seem interested, and the project head (who actually runs a game dev company) is definitely for it.

The reasons being that there's a scripting language (SEXPs) implemented for mission scripting, which could conceivably be expanded to support floats and strings. But, it doesn't allow you to define new functions, doesn't support functions that both change something and return a value, doesn't allow classes, and doesn't support floating point values, as well as being a PITA to code for as it requires you to add code in 6 different places to add a function for it. It's also LISP-based, which at least one strongly feels is a better syntax than Lua. (I'd never heard of LISP until it was mentioned in passing ~3-4 months ago)

But the biggest reason for their disagreement that they feel that any scripting language will be much slower and cause massive memory overhead or leaks than what reworking the SEXP system would do.

The SEXP source code files can be found here (.cpp, .h):
http://fs2source.warpcore.org/cgi-bin/cvsweb/cvsweb.cgi/fs2_open/code/parse/sexp.cpp?rev=2.179&content-type=text/x-cvsweb-markup
http://fs2source.warpcore.org/cgi-bin/cvsweb/cvsweb.cgi/fs2_open/code/parse/sexp.h?rev=2.98&content-type=text/x-cvsweb-markup

##### Share on other sites
Quote:
 Original post by WMCoolmonTo either of the two Johns: I understand the lua_load* functions, but how do I get something off the stack, or keep the stack from getting extremely large from loading minor chunks from everywhere?

The entire contents of the file are returned as a single function (closure) on the stack. The closure (effectively a pointer; does not take up much "stack space"; the stack won't grow, as you'll store the result in a table somewhere, then pop the stack) can be called/saved, etc. I use this methodology in Squirrel to compile and load a script for later execution (and done in such a way to to put everything declared in the script file in a specific table (not the root table)):

// Squirrel script:// ...  try {    game.init <- loadfile("levels/game.nut",true);  } catch (e) {     return 0;  } // catch  game.init(); // Everything in game.nut is defined in the table 'game'// ...  game.update(); // Calls update(), defined in game.nut.// Or called from C/C++:// gameObject is a SquirrelObject (the 'game' table)  res = SquirrelFunction<int>(gameObject,"update")();

You can do similar operations with Lua (see the Lua docs, perhaps google for Lua examples).

##### Share on other sites
Quote:
Original post by Name_Unknown
Quote:
 Original post by WMCoolmonThe reasons being that there's a scripting language (SEXPs) implemented for mission scripting, which could conceivably be expanded to support floats and strings. But, it doesn't allow you to define new functions, doesn't support functions that both change something and return a value, doesn't allow classes, and doesn't support floating point values, as well as being a PITA to code for as it requires you to add code in 6 different places to add a function for it. It's also LISP-based, which at least one strongly feels is a better syntax than Lua. (I'd never heard of LISP until it was mentioned in passing ~3-4 months ago)

Lisp doesn't really have syntax. I don't know what SEXPs is you mean, but if it doesn't
have those features it's not a lisp.

Most people around here run away screaming from Scheme so a small lisp-like interpreter
would be more ideal for them. Lisps aren't as anal about looping as Scheme is.

If you mean Lisp in the general sense when you refer to "lisps" (which I assume you are because you are using plural form), Scheme is a Lisp.

##### Share on other sites
@John:

I understand what you're getting at. Here's what I've been trying:

	luaL_loadfile(Ssn, "test.lua");	if(lua_isfunction(Ssn,-1))	{		LFunc = (lua_CFunction)lua_topointer(Ssn,-1);		lua_remove(Ssn,-1);	}	else	{		Warning(LOCATION, "Couldn't load lua");		lua_stackdump();	}	if(LFunc != NULL)	{		lua_pushlightuserdata(Ssn, LFunc);		lua_pcall(Ssn, 0, 0, 0);		lua_stackdump();		lua_remove(Ssn, -1);	}

But pcall doesn't seem to like that because I'm using the userdata type to get the pointer back onto the stack.

##### Share on other sites
To hold on to Lua objects from C/C++ code, use the registry. Try something like this:

luaL_loadfile(L, file); // loads the function, sticks it on the stackint funcref = luaL_ref(L, -1); // pops the value off, sticks it in the registry, returns the key under which it's storedwhile(true) // per frame{    lua_getref(L, funcref); // puts the function on the stack (though it's still in the registry)    lua_call(L, 0, 0); // calls the function}

##### Share on other sites
Not quite working, it gives me:
Unhandled exception at 0x00ac792e in fs2_open_ex_d.exe: 0xC0000005: Access violation reading location 0x531c46a1.

from inside luaH_getnum().

In the meantime, I've been trying to get OOP working for custom userdata. I've gotten to the point of member functions, where I've run into a problem...I can't figure out how to get the userdata itself. Occording to the online version of 'Programming in Lua', the userdata should be the first object on the stack; am I missing something?

##### Share on other sites
See
http://www.gamedev.net/community/forums/topic.asp?topic_id=312216
http://blog.lab49.com/?author=10

You'll also want to store the closure in a table for later use (if you are going to remove it from the stack). If you remove it from the stack, it will get freed upon the next GC cycle (probably not what you want). I would guess that you need to get a pointer to the lua object/closure that you could push on the stack (getting a pointer may not be what you need) [edit: Sneftel's registry comment]. Please keep in mind that I don't use Lua anymore (I use Squirrel; though you should be able to store the closure in a lua table for later use/recycling (see below)).

Also note that you can load the script and call any functions as shown in the lab49 and debian links (you don't have to store the closure). I store the closure (keep separate from the root table) so that it's easy to reload an entire gameplay script without having to reload the level/asset scripts (useful for prototyping games on the fly, without stopping the game engine).

##### Share on other sites
Thanks, I'll take a look at those links later. :)

The object problem turned out to be as simple as me forgetting to use : instead of .

Now, it seems that the userdata type pushed onto the stack doesn't seem to be registered as having the same metatable as the userdata returned by the new function.

Metatable get code, userdata set code:

*(va_arg(vl, script_udata).buf) = luaL_checkudata(L, nargs, va_arg(vl, script_udata).meta);

Metatable set code:

if(libraries->library_objects != NULL)			{				for(sol = (script_object_list*)libraries->library_objects; sol->object_funcs != NULL; sol++)				{					luaL_newmetatable(Ssn, sol->object_name);					lua_pushstring(Ssn, "__index");					lua_pushvalue(Ssn, -2);  // pushes the metatable					lua_settable(Ssn, -3);  // metatable.__index = metatable					luaL_openlib(Ssn, NULL, sol->object_funcs, 0);				}			}

Userdata set code:
lua_ship *lsp = (lua_ship*) lua_newuserdata(L, sizeof(lua_ship));		luaL_getmetatable(L, "ship");		lua_setmetatable(L, -2);		lsp->shipp = NULL;		lsp->shipp = &Ships[s_idx];		return 1;

##### Share on other sites
Quote:
 Original post by WMCoolmonIn the meantime, I've been trying to get OOP working for custom userdata. I've gotten to the point of member functions, where I've run into a problem...I can't figure out how to get the userdata itself. Occording to the online version of 'Programming in Lua', the userdata should be the first object on the stack; am I missing something?

You might want to check out luabind, toLua or other binding utils/libraries to see what it takes for class support in Lua (even if you intend to write your own from scratch).

Quote:
 Original post by WMCoolmonThe object problem turned out to be as simple as me forgetting to use : instead of .

That's one of the reasons I switched to Squirrel (C/C++ style syntax).
I recently ported SqPlus to gcc: you might want to compare ease of use compared to Lua (you won't have to write any binding code for OOP with SqPlus).

##### Share on other sites
Quote:
 Original post by Name_UnknownYes Scheme is a lisp but it's a special kind of lisp that enforces recursion for loopingand has a minimal standard.

Hum... no it doesn't. Read about do, it's in R5RS. Not the cutest syntax, but it's nothing a little macrology couldn't fix.

##### Share on other sites
Quote:
 Original post by Name_UnknownIt's just sugar for tail-recursion calls.Look at lisp's LOOP macro.

So? Tail-recursion is always optimized in Scheme, so it becomes a simple JMP instruction, just like for or while in C.

##### Share on other sites
Quote:

You said that Scheme forces the programmer to do everything with recursion. I said that it was wrong, that there existed a construct called do that was like looping constructs in other languages. You then said it was just syntactic sugar for recursion, but that's not really important, because the user of the language doesn't see it.

Quote:
 The kid wants to use Lua anyways, not Lisp or Scheme so let's not start a troll-fest overminor issues here.

Sure. Back to regular programming

##### Share on other sites
Lisp/scheme are fair game for this discussion: Halo used Lisp as its scripting language (one of the most popular games of all time). I last used Lisp circa 1988 (back when Prolog was also popular for AI) and would not recommend it given the OP's requirement list:
1. Polish Notation (not hard, but different from C/C++ notation).
2. Completely different syntax/keywords (car/caar/caaar/cdr/cddr/cadr, etc.).
3. (()()()(((((())))))))((((())()(((((((((((((())))))))))))))()))()((((): I don't think I balanced that correctly (to be fair, Lisp-aware editors make that a non-issue).
4. Like Forth, Lisp allows the language to be extended: while this can be useful/cool, learning Lisp and figuring out what everything does (and where it was defined) can be challenging (similar issue with operator overloading in C++).
5. Huge flame wars develop between pro-Lisp and con-Lisp programmers (see the above link).

I can say the Lisp programming will help one develop excellent paren/brace matching skills.

As for ease of use, the programmers will end up helping the script writers, and the programmers are typically more experienced with procedural languages such a C/C++, Java, C#, etc. Languages such a Python (used in many games) and Perl (not recommened for games) are very powerful, but require yet another syntax/skillset to be learned (not necessarily an issue for a single programmer, small teams, but may be an issue for larger projects/teams).

However, if the entire team is comprised of emacs users, Lisp would be the natural choice. ;-)

[Edited by - John Schultz on October 24, 2005 12:15:21 PM]

##### Share on other sites
Quote:
 Original post by John Schultz1. Reverse Polish Notation (not hard, but different from C/C++ notation).

Not that this makes any difference, but Lisp doesn't use Reverse Polish Notation.
Lisp is prefix (the operator comes first, then the arguments)
"Normal" programming languages (and algebra and so on) are infix (operators are put between the arguments that they operate on)
Reverse polish notation is postfix (the operator comes after the arguments).

Reverse polish notation has the advantage that you don't need any brackets at all (as long as each operator takes a constant and known number of arguments). RPN was used in some HP calculators (it may still be used, I'm not sure).

Prefix notation wouldn't need brackets either. Lisp does require brackets, of course, because they're a visual aid to grouping, and they're needed to deal with operators for which the number of arguments isn't known in advance (and because it always has used them)

John B

##### Share on other sites
Quote:
Original post by JohnBSmall
Quote:
 Original post by John Schultz1. Reverse Polish Notation (not hard, but different from C/C++ notation).

Not that this makes any difference, but Lisp doesn't use Reverse Polish Notation.
Lisp is prefix (the operator comes first, then the arguments)
"Normal" programming languages (and algebra and so on) are infix (operators are put between the arguments that they operate on)
Reverse polish notation is postfix (the operator comes after the arguments).

Reverse polish notation has the advantage that you don't need any brackets at all (as long as each operator takes a constant and known number of arguments). RPN was used in some HP calculators (it may still be used, I'm not sure).

Prefix notation wouldn't need brackets either. Lisp does require brackets, of course, because they're a visual aid to grouping, and they're needed to deal with operators for which the number of arguments isn't known in advance (and because it always has used them)

John B

You're right, though Lisp is generally Reverse Reverse Polish Notation ;-), or just Polish Notation (AKA Prefix). I'll delete Reverse from the earlier post (interestingly, a Reverse Polish Notation 'Lisp' exists (refs HP calculators: I had an HP-16C, it never powered up again after the batteries died. Fortunately, it can now be simulated (image)).

http://mail.python.org/pipermail/python-list/2003-October/187669.html

[Edited by - John Schultz on October 25, 2005 12:15:19 PM]

##### Share on other sites
Okay, I've gotten OOP going for the most part, however, I've run into a problem whilst trying to make it easy to use functions with the special operators (eg [], +, -, etc)

Specifically, with this portion of code:

else if(lof->type == i)						{							lua_pushstring(L, Lua_opers[i]);							lua_pushcfunction(L, lof->func);							lua_settable(L, -2);						}

What I'm trying to do, is set the function into the metatable without actually registering it. I don't want it to be callable for the library; and it doesn't seem to work if I try and register it within a metatable at the __index position of the object's metatable, so it's basically a method of the object. (Lua_opers is basically an array that's indexed using the lof->type variable, so that I can toss around an int instead of "__newindex" or whatever)

I'm not entirely sure why this isn't working, although I'm getting a better grasp of understanding how metatables work. The online book (http://www.lua.org/pil/28.4.html) doesn't seem to have this in mind.

## Create an account

Register a new account

• ### Forum Statistics

• Total Topics
628291
• Total Posts
2981862
• ### Similar Content

• My first mobile game made by unity

iphone: https://itunes.apple.com/us/app/aa-countdown/id1314223584?ls=1&mt=8

I appreciate every suggestion
• By Simplepg
• By Simplepg

• Who We Are
We are Forged Interactive, a small team of like-minded game developers with the sole purpose of making games we love! We're a team of artists, animators, programmers, level designers, writers, composers, producers, and other creative minds. We want to make games that you, the modern gamer want to play! We hope to build a community that enjoys our games as much as we love creating them. With your feedback and support we will be able to achieve that.

GAME NAME is a fun, action-packed army builder with unique characters, challenges and engaging levels. Set forth on an adventure to protect friends, family and countrymen from new adversaries. Once defeated your enemies turn coat and join you in your adventures. Players can enjoy a range of troops and abilities based on their gameplay style which become more important as maps introduce more challenging terrain, enemies and bosses. Strong orc knights, dangerous shamans, and even a dragon are out on the prowl. Knowing when to fight and when to run, and how to manage your army is essential. Your actions alone decide the fate of this world.

Previous Work by Team
Although we are working towards our first game as a team, our team members themselves have past experience in the industry.
This includes members who have worked on titles including:
Final Fantasy Kingsglaive, FIFA, Xcom 2 and Civilization.

Who are we looking for? 3D Modellers Concept Artists Marketing Specialists Level Designer

What do we expect? Reference work or portfolio. Examples what have you already done and what projects you have worked on academic or otherwise. The ability to commit to the project on a regular basis. If you are going on a two-week trip, we don't mind, but it would be good if you could commit 10+ hours to the project each week. Willingness to work with a royalty based compensation model, you will be paid when the game launches. Openness to learning new tools and techniques
What can we offer? Continuous support and availability from our side. You have the ability to give design input, and creative say in the development of the game. Shown in credits on websites, in-game and more. Insight and contacts from within the Industry.
Contact
If you are interested in knowing more or joining. Please email or PM us on Skype. Myself or Colin will reply to you within 48 hours.

E-mail: Recruitment@ForgedInteractive.com
Skype: ForgedInteractive

Regards,
David and Colin