Archived

This topic is now archived and is closed to further replies.

Biggles

Scripting System Basics

Recommended Posts

Apologies if this has been covered before, but I can''t seem to find any tutorials or threads that cover what I can''t figure out. Noone seems to cover the initial stuff. I''m trying to work out how to integrate a scripting system into my engine. At the moment the actual language used isn''t important (although FYI I''m considering python or lua). What I want to know is how the actual integration works. Here''s an example: I have a GUI system in the engine. I want to be able to create windows and menus using a config file (like xml or something, it doesn''t really matter what). I need to have the event functions for things like buttons execute user-defined (where user = game designer, not engine developer) code, and for that code to be executed when said button is clicked. The code would need to play with things in the engine (eg pop up a new (already defined in another config file) window, or change a graphics setting, or something like that) which means it needs to be able to change engine settings and interact with other objects in the system. Let''s say I have a window for configuring the video options. I would need the scripting code to be capable of populating certain parts of the window like list boxes (for resolution changes) and sliders and so forth. I would also need the code for the OnClick event of the OK button to be able to get the values of the list boxes, sliders, etc from them and update game settings with them. Another example would be when the user does something in the game world, like "use" an object. I would need to be able to run a block of code that would alter the game world in the way desired for when said object is used, which means the scripting system needs to be able to affect these objects in some way. So my question is (after that rather long winded paragraph) how does all this work? How exactly do I expose the required functionality in my (C++) engine? How do I run a block of code taken from a config file that says "when the object defined by this config file does this or is interacted with do this"? Links to tutorials/threads that I missed explaining this are welcome. Thanks in advance for any help. -------------------- Never eat anything bigger than your own head.

Share this post


Link to post
Share on other sites
Hi,

I don't understand (probably because of my coursed english) if you have already implemented a scripting engine or not.

You could save in the object rappresenting your window a reference to compiled or source code. When the OnClick event is encoutered iside the events queque, you have only to call a simple function that executes the user defined code. Probably you have to start the scripting engine at the application initialization, and then you have only to add refernce to already generated objects inside your simble table and run the script.

For example:

Your window is defined in this way:

<App>
<scripts>
<script id="ID1234">
<![CDATA[
#here you can store the bytecode if you want.
#this is only an example
print this.label+" pressed"
PARENT.destroy()
]]>
</script>
</scripts>
<Window size="100,200" title="Hi! :)">
<Button pos="10,20" label="press me" onclick="ID1234" />
</Window>
</App>

this should show a simple window with a button. When clicked, it should print to stdout "press me pressed" and then the main window should close.

Now your code should looks like this (pseudo-like code ):
if button.pressed:
script := button.code
symtab := scripting_engine.symble_table
symtab.store("PARENT", button.parent)
scripting_engine.run(script)

Now your scripting engine simply takes the code and runs it following your script definition.

Implementing a scripting engine is not so simple, but there are some tutorials on the net you can follow to start.

I hope this words will help you. bye

[edited by - darkbard on January 7, 2004 10:51:18 AM]

[edited by - darkbard on January 7, 2004 10:51:54 AM]

[edited by - darkbard on January 7, 2004 10:52:42 AM]

Share this post


Link to post
Share on other sites
Jan Neistadt''s series on Flipcode

There''s also info on YACC and LEX (Lexical analysis and syntax validation) here

Look also at my thread about GameMonkey and integration on their forums

And of course there''s some tutorials on VMs and basic parsing on Gamedev

Take it from me, creating a scripting language is a bitch. Don''t expect people to use it either - there seems to be hundreds floating around now.

I''m trying as hard as I can to avoid writing my own and integrate an existing language - but I KNOW that building it into my engine and have it behaving the way I want is going to be hard. Perhaps not as hard or complex as making my own language, but it''s a chore none the less.

Share this post


Link to post
Share on other sites
I''m not interested in writing my own scripting language. I''ve written compilers before, and I know that it''s far too much work to be worth doing when there are existing solutions around. What I want to know is how to integrate an existing language into my system such that I can call user defined code when necessary and have it work with existing objects in the engine like windows and entities in the game world.

--------------------
Never eat anything bigger than your own head.

Share this post


Link to post
Share on other sites
Biggles,

On the same search as you''re on about half an hour ago, I came across the following, and it looks like just the ticket

Download the "lua scripting" link on http://www.gametutorials.com/CodeDump/CodeDump_Pg1.htm.

Cheers,
I.

www.coldcity.com
code, pics, life

Share this post


Link to post
Share on other sites
quote:
Original post by Biggles
What I want to know is how to integrate an existing language into my system such that I can call user defined code when necessary and have it work with existing objects in the engine like windows and entities in the game world.



Many existing scripting languages can do that for you. In
particular, Tcl is very suitable for GUI controls, especially
when used with Tk. But you can use Tcl with your own GUI stuff.



Kami no Itte ga ore ni zettai naru!

Share this post


Link to post
Share on other sites
I''m currently looking at the GameMonkey source. The implementation is nice, it''s not as annoying as LUA to pass parameters and has a more C-style syntax.

One thing I''m *not* sure on however is the annoying ''feature'' that makes you pass C-style function pointers - this is present in every scripting language I''ve seen. I''m looking to modify the GM code base to encapsulate the calling of C++ functions from the script and vice-versa.

Share this post


Link to post
Share on other sites
That link was quite helpful, IainC. Thanks.

Now, let me see if I''ve got this right. Working from the example of the GUI component:

I would create some functions in C++ that could be called from the script to retrieve a pointer to a GUI object (like a label or a button). Then, in the script, I would call the function necessary to get the object I want. Once I have a pointer to it in the script, I can do things like set and retrieve values on it as long as I also provide functions to do that in the class for that object.
For handling something like user defined code when a button is clicked, I would store the code with the button and then the OnClick function for the button (in C++) would feed that code into the script VM where it is run.

I''m still a little confused about how object scoping would work in the script, and the functions that are accessed by the script. It looks like these functions will have to be C functions, but they also need to be able to access the instances of classes in my engine (for example, a C function used by the script to draw a rectangle on the screen would need to be able to access the display object, eg Display::DrawRect), which have been encapsulated inside the main engine class. How do I get around this problem without breaking encapsulation? Is it even possible?

Share this post


Link to post
Share on other sites
quote:
Original post by Biggles
for example, a C function used by the script to draw a rectangle on the screen would need to be able to access the display object, eg Display::DrawRect), which have been encapsulated inside the main engine class. How do I get around this problem without breaking encapsulation? Is it even possible?


Well, duh, you have to decide on whether you want the script system to be able to acces those classes and manipulate the entities they represent, or if they should be locked away.

Breaking encapsulation means you provide an access that can let a third party programmer leave your objects in invalid states (violate their invariant), for example, by changing values of internal pointers, without code that manages those pointers being notified (like the ''next'' pointers in a linked list). What you are doing is to add new functions that can manipulate the object, but which are still expected to leave the objects in a valid state (assuming they were in a valid state to start with, which is what encapsulation is intended to ensure). So your are just exposing a new (scripting) interface.

Implementation note: extern "C" static member functions can be useful when you need to write functions callable from C, that access private members of a class, without violating encapsulation. Obviously, being static, they need an object pointer (C doesn''t have references) among their arguments.

Share this post


Link to post
Share on other sites
OK, I think I understand how it all fits together now. Thanks for the help, everyone

--------------------
Never eat anything bigger than your own head.

Share this post


Link to post
Share on other sites