Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411630 Posts in 69393 Topics- by 58447 Members - Latest Member: sinsofsven

May 12, 2024, 03:38:02 AM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)Scripting - Faster or Slower to Dev?
Pages: [1]
Print
Author Topic: Scripting - Faster or Slower to Dev?  (Read 3272 times)
iggie
Level 1
*



View Profile WWW
« on: November 22, 2009, 01:53:05 PM »

I am having battles over Lua again. In my heart I hope it will simplify my codebase and give me a clean way to add mission and story elements to my game - but in my head it is adding endless layers of indirection and complexity to straightforward tasks.

Has anyone who has written both pure c++ games and c++/lua games got experience of which is faster to develop?

In particular I am have a problem with identifiers, in c++ I would use enums for switches, types & ids - is there a simple way to use the same enums in Lua. (I have in mind some nasty #include and #define fakery to reuse the same file as Lua and c++ header... but there might be a better way!)
Logged

Triplefox
Level 9
****



View Profile WWW
« Reply #1 on: November 22, 2009, 07:23:56 PM »

Scripting has to be accomplished with a particular intent in mind for it to be worthwhile.

I did an Object Pascal/Lua game once. I had some fast render/collision code in Pascal, but pretty much everything else was Lua. It didn't help the way I had hoped because I was still writing roughly the same kind of code that I would have written in Pascal. Since then I've realized that I was trying to be too "pure" about using languages in this way - I expected Lua to be a magic wand just because it was "higher level." But really, languages are all stupid, leaky abstractions over the machine in the end, and what's important is what they let you express. You can give up fancy tools, checks, optimizations, safety and formality and still come out ahead in the end if you're working in a language that lets you be concise and clear about your statements. But if all you're making is a bigger mess, you've gone in the wrong direction and should back up and try again, focusing on more efficient ways to express the problem - to achieve more "declarative" and less "imperative." That may mean changing how you use Lua; it may mean dropping it in exchange for a more custom language, or it may mean resorting to small hacks on top of C++ rather than a full interpreter. That all depends on what you're doing.

To solve your particular problem of syncing constant values, I would maintain a Lua file for the constants and add a function to it that emits the header file from the data. Then batch in a step in your build process to run the function and autogenerate that header. I do this for all my game assets, as the constants in the autogenerated files become IDE/compiler-aware afterwards, helping to avoid mystery runtime errors. (It wouldn't scale too well for huge C++ projects with lots of data though.)
Logged

iggie
Level 1
*



View Profile WWW
« Reply #2 on: November 24, 2009, 03:28:52 PM »

Thanks, I think I was edging towards reproducing C++ in lua rather than creating a simple and specialised lua environment to help out where my other data structures were lacking.

I will probably go back to using C++ and csv exclusively until I am more advanced with the project and can separate out the scripted parts neatly.

The enum trick looks sensible, I guess a similar thing could work with localised text strings. I could even pre-process the lua file to replace enums and strings with int identifiers as they are loaded in.
Logged

LemonScented
Level 7
**



View Profile
« Reply #3 on: November 24, 2009, 04:05:17 PM »

I've worked on games with and without scripting systems, and in general unless your team contains a significant number of people who can write code but not in C++, I'm not convinced of the use of a scripting system. For very story/mission driven games perhaps, but even then I've known big game studios to throw out their scripting language and just teach the scripters to write in a subset of C which banned templates and pointer arithmetic and other stuff which could be "dangerous" in untrained hands.

What I prefer to do is to invest time building a decent event system, so that when a specific game event happens (a button press, the player entering a trigger area, a specific enemy dying), an event is fired through the event system to inform any other game objects which might be interested in such a thing happening, so they can run code to respond to it. You build up behaviour by building chains of callbacks. Then, instead of a scripting language with logic and control flow in it, you just have a data format which specifies the placement and properites of game entities, the events they fire when specific stuff happens to them, and the types of events they might listen for and react to.
Logged

Sar
Level 3
***


Likes Violins


View Profile WWW
« Reply #4 on: November 25, 2009, 03:25:43 AM »

What I prefer to do is to invest time building a decent event system, so that when a specific game event happens (a button press, the player entering a trigger area, a specific enemy dying), an event is fired through the event system to inform any other game objects which might be interested in such a thing happening, so they can run code to respond to it. You build up behaviour by building chains of callbacks. Then, instead of a scripting language with logic and control flow in it, you just have a data format which specifies the placement and properites of game entities, the events they fire when specific stuff happens to them, and the types of events they might listen for and react to.

Somewhat-related anecdote time: the last engine I made I forwent scripting in favour of just thinking "hey, I can code a bunch of generic configurable behaviours that respond to a bunch of generic configurable events and everything will be fine, you can just edit together the whole game in the data file and then if there's any need for more-specific behaviours I can just hard-code them as a new not-so-generic behaviour configurable from the data file...


...except in practice, it didn't work anything like that, and after a week of actual game development everyone had forgotten about the possibility of custom-coded behaviours and was putting together insanely-complex trees of generic behaviours all specified in an XML configuration that rapidly became too long and convoluted to actually read or find things in or debug, and the game ran probably an order of magnitude slower than it should have done because of the overheads of each of the small pieced-together behaviourettes.

So in the end, I wish I'd implemented some kind of scripting, even though the alternative is theoretically just as flexible and powerful and probably more efficient on time. Even if it might not have necessarily made the game run faster, it would have helped keep the files more manageable and eased debugging.
Logged

Currently working on: Chronicle of Mars
Previous Projects: [Käfer|Tristan and Iseult(TIGS)]
jeb
Level 5
*****


Bling bling


View Profile WWW
« Reply #5 on: November 25, 2009, 09:26:41 AM »

To answer your enum-related problem. We usually do something like this when we want to have a list of constants:
Code:
enumName = {
   constantOne = 1,
   constantTwo = 2,
   constantEtc = 3,
}
And then access them using enumName.constantOne and so on. Note that this is a lot slower compared to enums in C++, since the C++ compiler is able to replace the enum with a fixed integer while Lua needs to perform multiple hashmap lookups before it discovers that "enumName" is in the global namespace.

However, to answer your question about if it's faster to develop games using a scripting language I would say hell yes! We've made these prototypes in Lua, with the help of our Daisy Moon engine in the backend:
Horror Tactics
House Globe
Fillauth
Because It's Fun, Fay
... and some other unreleased games.

The thing is... usually when people talk about adding scripting to their engine, they say something like this:

"We have the game, but some things should be more dynamic, so we attach scripted behaviours to them."

What I'm trying to say is this:

"We are scripting a game, but some things are too slow for Lua, so we attach C++-coded 'helper' methods to speed them up."

Both versions are valid, it depends on what you are trying to do. Lua is a bit slow to make a full game, I guess, but when we switched to LuaJIT we more than doubled the FPS. Since we started working this way I have started to really dislike header files Smiley
Logged

LemonScented
Level 7
**



View Profile
« Reply #6 on: November 25, 2009, 04:34:26 PM »

...except in practice, it didn't work anything like that, and after a week of actual game development everyone had forgotten about the possibility of custom-coded behaviours and was putting together insanely-complex trees of generic behaviours all specified in an XML configuration that rapidly became too long and convoluted to actually read or find things in or debug, and the game ran probably an order of magnitude slower than it should have done because of the overheads of each of the small pieced-together behaviourettes.

Ah, okay, I want to be clear about this in case anybody has misunderstood me. Are we talking about a system where you code a bunch of behaviour components and then specify in data which of those components a given object has, with the intention that all of the components will work together to produce nice complex behaviours with lots of code re-use? Because, yeah, if that's what you're talking about, then (A) you learned the hard way that that doesn't work (as have I, in the past, on a project that was all but brought to its knees by a sloppy implementation of this approach), and (B) I want to be clear that I can in no way recommend doing this, and that what I was suggesting was considerably simpler.

This is just example stuff, but it demonstrates roughly the level of complexity I'd run to, and not much further.

Data:
Code:
<Entity type="TriggerBox" xPos="10" yPos="12" xSize="5" ySize="5" eventOutChannel="1" eventFilter="Player|Monster" />

<Entity type="Door" xPos="16" yPos="12" xSize="5" ySize="5" eventListenChannel="1" />

Code:
So the level loader/entity manager/whatever you call it looks at this data when it's specifying a level. It creates a trigger box (an invisible box which does nothing but fire events when certain types of other entities enter it). Events are sorted by type, so in this case it would be a TriggerBoxEntered event, which is a little structure containing maybe a reference to the thing that entered it, and the event channel, which is 1. Think of a channel as being like a radio channel or a TV channel: Event listeners only listen in on certain channels. The level loader also knows to tell the TriggerBox when it gets created that it should only send an event when a player or a monster enters it (crates, bullets etc don't set it off). Similarly it creates a Door which listens for events on channel 1.

The box checks every frame to see if a player or a monster has entered it, and if it has, it fires an event and then takes no further part in the process. The box doesn't care about the door (or the pit trap, or the monster spawner or whatever else might be listening for that event). The door gets passed an event on channel 1 (it doesn't even hear about events on other channels because it doesn't care), checks its state, and if it's closed, then it opens. Voila, one automatic door. If you want to, you could add a button entity on the other side, which transmits on channel 2, and tweak the door so that events on channel 2 close it again.

The point is, the behaviour of an entity is all contained in the code. It knows when to fire events, and it gets told what channel to fire them on, and that's all it does. Entities can also listen for events (they get told which channel they should listen on, and only register as a listener on those channels), but when the event arrives, it's all down to that entity to look at its current state and any other information it needs to make a decision on what to do in response (up to and including firing new events of its own). It keeps all of the game logic code-side, but if done properly can make for quite an adaptable plug & play type system. It's not a 100% perfect system, but for me it's preferable to a scripting approach (where you have to deal with writing code hooks for all the scripting stuff, and as well as debugging an object's behaviour at the code level, you also have to bulletproof what happens when a script is trying to fudge or interfere with it at a higher level too), and it's DEFINITELY preferable to a hooking-behaviour-components-together-to-make-entities type approach.
Logged

Glaiel-Gamer
Guest
« Reply #7 on: November 26, 2009, 12:02:00 AM »

Scripting is really useful if you have a team of 100 people and the people designing the game aren't the ones who are coding the core, and compiling the project takes a long time and the game is content heavy.

For a 1-3 person project? It can have its uses, but you'd be hard pressed to find a situation where spending the time integrating a scripting language with your engine would actually be worth the time in the end, when it's easier to keep all the code on the same level.

The exception, of course, is when using a prebuilt engine that only uses a scripting language (i.e. flash). In which case, there is quite a limiting cap on how much you can actually do with the game.
Logged
Sar
Level 3
***


Likes Violins


View Profile WWW
« Reply #8 on: November 26, 2009, 04:35:45 AM »

Are we talking about a system where you code a bunch of behaviour components and then specify in data which of those components a given object has, with the intention that all of the components will work together to produce nice complex behaviours with lots of code re-use?

Not quite - I'm talking about a system where you code a bunch of default simple behaviour components and specify in data which of those components a given object has, with the intention that this deals with any simple cases easily (it was a 2D-shooter engine, so there were lots of simple cases), and more-complex cases (e.g. bullet-hell boss patterns) would have been dealt with in a similar manner to that which you describe, simply by pointing to a custom-coded entity with a fixed interface to recieve events and change state.

It's just that the people doing the stages got very carried away with nesting the basic behaviours and forgot to ever ask for custom coding. I guess my point is that your audience is also important, and educating people is also important, because a lot of people will try to do hard things with easy-to-understand tools rather than trying to do easy things with not-so-easy-to-understand tools.
« Last Edit: November 26, 2009, 06:29:18 AM by Sar » Logged

Currently working on: Chronicle of Mars
Previous Projects: [Käfer|Tristan and Iseult(TIGS)]
Hima
Level 4
****


OM NOM NOM


View Profile WWW
« Reply #9 on: November 26, 2009, 05:05:36 AM »

I would have done something like jeb said but I'm used to OOP and OOP in lua seems a bit forced and confusing to me Sad So now I'm making a game in C++ and use scripting for the dynamic part.
Logged

Eraser
Guest
« Reply #10 on: November 26, 2009, 07:31:50 AM »

A scripting engine isn't exactly too easy to code, but if you don't need an overly complex one, you can add a simple one like I did: Just parse custom made strings, like:
[&]Cave[&]ifhasitem[&]dothisfunction|otherwisethisfunction[&]
Very rudimentary, but it gets the job done. I would say it's completely worth it as well. It allows for so much more customization, and once you implement the thing, you can really start developing content much faster.
Logged
Martin 2BAM
Level 10
*****


@iam2bam


View Profile WWW
« Reply #11 on: November 26, 2009, 11:32:37 AM »

I don't know much, I'm starting with scripting myself.

The best part of scripting is not recompiling. Even if the project is not that big, tweaking the slightest part will waste your time compiling, linking, loading stuff up and reaching the same test-state in which it was before.
And it adds up. 30 little tweaks can take you an hour away!
Also scripting with a nice reflective language can be a easy for prototyping a new functionalty ... and perhaps later on (when the logic works) translating it to C++ for performance.

Also the cool part is to let the users hack in their stuff: like mods or just messing around with stuff.
I like lua because it transparently loads either bytecode or text code, so you and the users can decide what to share it's source for and what not to.

A limitation I hate the most is not being able to use the STL directly with Lua, but it can be worked around.

I find SWIG really awesome for C++/<whatever> binding. It generates the appropiate proxy classes and you don't need to worry about (almost) anything about the binding but writting your code.

Regards
« Last Edit: November 26, 2009, 11:40:30 AM by nitram_cero » Logged

Working on HeliBrawl
andreas
Level 0
*



View Profile
« Reply #12 on: December 05, 2009, 04:43:12 AM »

Just a small comment on the subject.
I've done quite a few projects. Some small, some big. Coders always assume that scripting is one of the first things to implement in an engine - but more than once I have had to remove the scripting system again from a project: The main problem is that the scripting system is often used as a "magic black box" by the technical team. "Yes, we can do all the features you want - because you can just implement them yourselves  Wink" -Then the poor people you get to work as scripters gets to solve all your problems (which they don't have skill nor authority to do).

I've got alot on my heart about this subject Smiley, but I always advice people to start the simplest way they know and then introduce scripting when they need it. -And only introduce the amount of scripting they realy need (not just expose everything).

Just in case you wanted to hear my oppinion Smiley
Logged
PsySal
Level 8
***


Yaay!


View Profile WWW
« Reply #13 on: December 05, 2009, 12:28:53 PM »

Having done both, I can say: go for lua. In fact, as I move forward I am relegating less and less to C++. The next game I do (that isn't flash) will basically have C++ as a really basic rendering/audio/physics engine that knows nothing about game logic.

Mapping between C++ and LUA is some overhead. That's actually the reason for me to move more and more to LUA; that way the C++ has a very simplified interface (e.g., to add renderable objects, set movement parameters, that kind of thing) which reduces the overhead.

In the case of enums, what I normally do is store them as strings in lua. If you don't like this, you can always do something like:

walk_states = { still = 1, walking = 2, jumping = 3 }

And then reference them like walk_states.still. However I find just doing if (self.cur_state == "still") is just easier to manage.

How to map them between C++ and LUA, well, you have to have overhead somewhere. Since I handle enums as strings in LUA, for those enums that have to be known across boundaries I make a function in C++ that maps enums to strings and vice versa. Yep, it's annoying!
Logged
iggie
Level 1
*



View Profile WWW
« Reply #14 on: December 05, 2009, 01:32:38 PM »

I tried writing a game in lua with only render calls delegated to C++, it was fast to get a prototype up but after a point the amount of code got out of control and the debug support was not as easy for me to use.

Now this might be due to lack of experience in Lua - but as I know how to organise 100kloc programs in C++ I decided to move my main gameplay code back to C++ for other projects. Also I didn't get the hang of serialisation in Lua.

I understand trying to mirror all the C++ in Lua and visa versa is unhelpful, and it is best to keep the most of the gameplay on one side.

My main reason to use Lua is so I can release an exe and let other people write scenarios and missions for the game. I am currently thinking I would be better off making a simple data format for this instead of allowing full scripting - as exposing all the gameplay mechanics across the C++/Lua boundary would be too painful + complex for the time I have available.
Logged

Martin 2BAM
Level 10
*****


@iam2bam


View Profile WWW
« Reply #15 on: December 08, 2009, 08:16:44 AM »

What better that numbers for us tech freaks.
Here are some benchmarks: http://shootout.alioth.debian.org/u32/benchmark.php?test=binarytrees&lang=all&box=1 (... PHP Screamy)


Also I've been recommended to check out Squirrel. It's C++ish, arrays start from 0...etc.

Logged

Working on HeliBrawl
iggie
Level 1
*



View Profile WWW
« Reply #16 on: December 08, 2009, 12:15:43 PM »

I love seeing comparisons of the same algorithm in different languages (As on Project Euler) so that list is great. It is clear when you sort by code size that languages like Python/Ruby win for that - but with a massive speed penalty.

I am more interested in speed of writing the code than of execution, so code length is a good indicator that these languages are compact - but what would be really interesting would be to know how long the different programs took to write!
Logged

PsySal
Level 8
***


Yaay!


View Profile WWW
« Reply #17 on: January 19, 2010, 08:56:11 AM »

Did you try using classes in lua? When I started I didn't have that and it was kind of awkward, but once I got a library that let me do classes things went much more smoothly.
Logged
Martin 2BAM
Level 10
*****


@iam2bam


View Profile WWW
« Reply #18 on: January 19, 2010, 06:54:05 PM »

I'm using V8 (Google's JS engine) and it's totally tits. JavaScript is a pretty cool language, and the syntax (and nothing else) is C-like... so porting back to C++ for performance isn't that difficult.

The lack of documentation is astonishing though... it's really hard to learn, even if it's really simple.

The downside is that it compiles text javascript to machine-binary, there is no precompiling to in-between bytecode (which means you're actually distributing the text source code).

Logged

Working on HeliBrawl
iggie
Level 1
*



View Profile WWW
« Reply #19 on: January 20, 2010, 04:19:39 AM »

I was doing some class-like things and using several LuaBind created classes that mirrored my own classes. But a lack of decent programming environment (for me at the time) hurt the most. I think I have been spoiled by MSVC and Visual Assist - makes coding so much easier!
Logged

Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic