Advertisement

Why use scripting in games?

Started by June 29, 2004 07:00 PM
48 comments, last by TheQ 20 years, 4 months ago
Quote: Original post by teamonkey
Why bother restarting the game? Change the code and hit a button to reload the script. That's all.


That is not as easy as you think, especially if you have some initialization functions done in your scripting language, at start up.
Quote: Original post by Nemesis2k2
Quote: Well, this does depend on how far you want to go but you could as i say have a small inbuild system to edit scripts on the fly in the game and change things as they go, then its a small matter if writing that script back out to the file so that next time you run it again the change will have persisted (tbh, i'm not sure i'm spelling that right) between the runs.

Ah yes. Each instance of a Script object has its own memory pointer. Variables that are needed to remain persistant are defined in a struct, which that pointer referances. Any variables that are needed to remain persistant are defined in the struct. On an Initialise message, the memory is mapped back to the pointer if it is wanted for that script. Its neater than it sounds.


Yeah, saving varibles is easy [grin] i'm on about changing the script its self, what functions are called etc and saving that out to be reused later :)

(applogise if you already got that btw, i've only just woken up and i'm a bit slow atm [wink])
Advertisement
Reading that quote, I'm not sure how I got the idea you were talking about variables.

Anyway, making "on the fiy" tweaks to the script wouldn't realistically be possible using the DLL approach, no. Debugging and tweaking like this are the areas where you loose out most.
Nemesis -

i am working on a 2D rpg w / C++. ive done a lot of the game engine, and am ready to start adding content (a story line, NPC's, NPC interaction, world interaction...)

ive tried to embed Python into my C++ code but am having problems. worst of all, there doesnt seem to be many people here with experiance doing this, so i cant get any help. if you dont mind, could you please explain your method of using C++ for "scripting". i would absolutely LOVE to find out i could stick with my C++, and not have to use a new language, and go through the pain of having to figure out how to embed it into my game properly...

thanks for any help!!!
FTA, my 2D futuristic action MMORPG
Quote: Original post by Nemesis2k2
I'm making a large scale project. Quite large in fact. We're expecting another 2-3 years of development time. Still, I spent a long time thinking about this, and I couldn't see a good justification for a true scripting language over this system. I went through a whole notepad on this scripting thing alone, looking at it from as many angles as possible with as many cases as possible, using as many systems as possible. I settled on this one.


Your solid and well constructed ideas and comments caught my eye.

If we define a scripting system as: An external method of modifying a game database, and or making that database self modifying... Then you are actually using a scripting system.

A scripting system can take almost any form.
Consider:

1) In a message based environment where objects modify internal data structures (i.e. change states) upon recieving messages. A simple list (series) of messages could be considered the "script".

2) Theoretically, you can construct a gui based object scripting system. Watch this derivation tree:
(script object): base scripting object
(list object): contains other (script objects)
(if/else object): contains one or two (list objects)
(loop object): exectes (list objects) in loop
(property object): query or modify a game entity property
(assignment object): property to property assignment
These 6 (actually 5) little objects are then visually represented by cool little graphical windows. Their data values are saved to file and load/reconstructed as necessary.
Note: you probably need to implement some sort of handle system to access objects directly.

Voila! An easy to use end user scripting system that's fast and even has some neural net potential.

Pretty clear, or too out there?
AndrewAurora Interactivewww.aurora3d.com
Quote: if you dont mind, could you please explain your method of using C++ for "scripting".

Well here's the guts of it. I have a Script class, which is an object that entities in my scene graph hold if they want to have a script attached to them. In a bare bones form, it might look something like this:

class Script{public:	Script(char* fileName, char* funcName) :memory(0)	{		libHandle = LoadLibrary(fileName);		script = (Message& (*)(Message &message))GetProcAddress(libHandle, funcName);	}	~Script()	{		FreeLibrary(libHandle);		delete(memory);	}	HINSTANCE libHandle;	Message& (*script)(Message &message);	void* memory;};


This is very bare bones. It doesn't protect its members, and it doesn't do error checking. Its enough to demonstrate the idea though.

This class puts a wrapper over a function in an external DLL. The function returns a referance to a Message object, and takes a Message object as a parameter. How you define your messages is up to you. You could do it the way Windows does it, where you have an enumerated member that tells you what kind of message it is, and have some general memory afterwards that you squeeze the data you need into. You could also make Message a base class, and create child clases that inherit from it that define your actual messages. However you do it is irrelivent really, as long as it works.

libHandle is a handle to the DLL. Each instance of the script class has its own handle, which is allocated when the object is created, and freed when the object is deleted. The DLL is only ever bound to the program once. Allocating another handle just gives you another means to access it. When there are no more handles referancing a DLL, the DLL is unbound from the program automatically.

script is a function pointer to the desired function inside the specified DLL. You call this like an ordinary function pointer, the only difference is we obtain the address of the function through a call to GetProcAddress().

memory is a pointer to the persistant memory for that script object. I'll touch on that again later.


With this class, you set up the script through a call like this:
"Script myScript("dll.dll", "FunctionName");"

That will bind the DLL to the program and get the pointer to the function. You can then just call the function through the function pointer like so:
"returnMessage = one.script(message);

In reality, you'd have a member function (which you'd probably inline) that puts a wrapper over the script function.


Anyway, that's how you use it in the main application. The DLL's themselves are like this:
EXPORT Message& ItWorked(Message &message){}


That could define a script in your DLL. EXPORT is a macro which hides some of the verbosiy of declaring that function, and is defined as follows:
"#define EXPORT extern "C" __declspec(dllexport)"

The actual body of the script is totally up to you. You can also make local functions in this DLL that are not exported, and call them from your scripts. Basically just do whatever it is you need to do to process and repond to the messages you recieve. There might be an "UPDATE" message for example, which upon recieving, your script should perform whatever general updates it needs to do that happen with time. This might mean updating an animation pose, or moving an object.

In order to allow your scripts to interact with your engine however, they need a set of functions they can call that give them access to all the things they might need to influence. They might need to create or modify other objects in your scene for example. To do that, you create an SDK of sorts that provides all the functions you'd need. This can just be a static or dynamic library, with a set of header files which define all the structures and functions you want the scripts to be able to call. I won't go into too much more detail on that, but suffice to say, you can create a set of high level functions that perform tedious or technical work for you. You can make these functions as low-level or as abstract as you want.

Finally, each instance of your script clas needs its own persistant memory. To do that, you define a struct for each script that needs persistant memory. If the ItWorked() script needs two values to be persistant for example, it might have a structure like the following:
struct ItWorked_Mem{	int val1;	int val2;};


Because the Script class back in the engine has no idea about the size or contents of this structure, your script class has to be responsible for creating and deleting this block of memory. That can be accomplished quite easily. Pass your script Create and Delete messages, and upon reciecving them, it allocates and frees the memory as needed. The pointer to the memory is stored in the Script class, so it can be recalled when the script is next called through this->memory.

And that's about the guts of it.

Quote: Voila! An easy to use end user scripting system that's fast and even has some neural net potential.

Pretty clear, or too out there?

Sounds like it could work. It'd take a bit of getting used to, but theoretically it should be possible to use.
Advertisement
I wrote up a little article on this topic in the past.

*toots horn*

http://gamedev.net/reference/articles/article1974.asp

After all this debate, we're talking about the same thing.

The core piece of this argument is that you need both game data as well as game logic to be data driven. For any large game you need a spearate of game logic, and game engine code.

The data driven game logic can be reprented as python, LUA, ocamel, java, C++ DLL's etc. It honestly doesn't matter. Whatever floats your boat and works for your engine. Architect it well and you've got some gains either way.

Toes
Hi! How do you guys run your scripts? For instance, you have a script like this:

-- script is in lua
if player.position == vector(3,3) then
spawnEnemy(3,4)


Now, when would you run the script. Every frame or what?
Usually, scripts would be event-based and called by a certain action or situation detected in the host program.


Request to everybody: could we please ask new questions in new threads? By this I mean questions like:
- "How do you guys run your scripts?"
- "could someone explain to me the theory behind integrating scripting into the game?"
- "could you please explain your method of using C++ for "scripting"

This thread is primarily about the reasons behind choosing to use scripting. A little topic drift is fine, but if you have separate questions they should go in their own thread. Thanks. :)
I've actually been spending the last week building my engine more towards being scripter friendly. I have had a scripter since I did this code back in VBDOS over 10 years ago (now, of course, in C++ and DX).

Firstly, scripting allows you to avoid recompiles, it also allows for tweaking and hacking per the end user, which we/they love. At the same time it allows (if you kept the scripting system simple) non-programers to deal with allot of the grunt work - it also allows you to create game editors - you might get away with the last one witout a total scripting language, but hey, even a resource file (list of resources and what not, which is what my earliest scripting system was) is a script.

I made a program called RPGx which allows easy reproduction of RPGs - it's nice and all however, as advanced as it was I wanted and easy option for editors - so I looked back to VB4 (at the time) - the scripting langauge was the in-between - simply.

And last but not least, it's great for debuging through a console. I use a sort of database as the core data for the engine - I can now (as of jus a few days ago) create an destroy varaibles through the console - with a few security features like command levels, I still keep everything safe (though I've come to the decision that if the end user want's to crash they're computer by creating an array of objects beyond they're memory, or assign a string as a 3d object, have at it!)

Now whaqt I did is I plugged the scripter right into the console, or vice versa, and walla! I now can manipulate compex stuctures during run time without some fancy guie (though my next objective, which sould be not to difficult, is to incorperate a sort of a HTML/easy windows gui solution which will simply allow one to create a gui and set of interfaces from the command line/scripter - so then I will be able to create in game editors, or even create test interfaces on the fly - I can already load min-scripts from the command line so say I have a set of objects but I want to teak them, I'd simply type in the console "load "manipulate3d.scr"" and poof.

Scritpers are power! So is a console though.
-Q

This topic is closed to new replies.

Advertisement