Newbie needs some advices

Started by
11 comments, last by blubberbernd 12 years, 8 months ago
Hi,

I'm new to scripting and I figured out that AngelScript would be the best solutions for me, as it looks. I have it compiled and included in my project. I know how to start the AngelScript engine, and so on.

I'm programming in C++, so with classes and everything (the samples only have non-class code), some of them are singletons, some not, some have static methods, some not, etc. So, I want to extend the coodebase by AngelScript to allow some things to be flexible and easy changable.

What I want to do currently is the following: an ingame console. I want to have it behave like this:
- User enters "command arg1 arg2 arg3"
- if there is a function called "command", check how many and what arguments it need
- if user entered correct number and types odf arguments it will be execute with arguments "arg1 arg2 arg3"

My problem currently is: how do I evaluate the arguments before passing it to AngelScript? If I add a new command in the .as script file by writing a "void newcommand(int arg1, bool arg2)" function, then my C++ code won't know the types of arg1 and arg2. So, I donT' know what and how often to call the SetArg..() functions.

Or if I rephrase this: I don't know how to prepare my C++ code so that I can add new AngelScript functions that can be called from C++ without changing the C++ for each new .as script function.

Did I missed or missunderstod some basic concept here?

And some general questions:
I'D like to see some "real world" code (big projects) using AngelScript. Are there any open source projects?
What are good practices (in C++ when working with the API)?
Advertisement
You can get the typeId of each parameter from the asIScriptFunction object using the GetParamCount() and GetParamTypeId() functions, and ultimately look up those types and work out what they are. If only primitives are allowed, you can look up the type Ids of each primitive beforehand using asIScriptEngine's GetTypeIdByDecl() function. So you should be able to handle this with a loop over each parameter and a switch statement or function map or similar.

I agree. The samples are not very extensive. I plan on adding a better more game-like sample for the next release. It will be based on the code from my own game engine.

In the meantime, if you wish to look through the code of some big projects, I suggest the following:

Rigs of Rods

Warsow

Some of the other projects on the users list are also open source, and may be of interest.


If you want to parse the arguments yourself, and then call the script function manually you would ideally enumerate the available script functions with GetFunctionCount and GetFunctionDescriptorByIndex. As there might be more than one function that matches, you'll start by matching the name and number of arguments. Then if there are still multiple functions that are potential matches, then you'll have to determine which of them best matches what the user wanted by the types of argument.

However, why not let AngelScript do the evaluation of the command itself? The console sample shows how that could be done.


Regards,
Andreas

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Thanks for your answers. :)
I'll try this out and have a look at the source code and samples you suggested.

But I have some more question:
- I understood that AS code is loaded into "modules". But what are good practices on creating and using modules? Should I only have one huge central module that holds all available script code? Or should I have a module for each .as file? Is one big module slower than many small modules?

- Same holds for "contexts": When to create a new one? Reuse only one central context? Or create new contextes for each function call? Any performance reasons?
You may think of modules as separate programs, or perhaps more appropriately, shared libraries. Modules are independent of each other, and each can be loaded separately.

Keeping the entire script in a single module, can have it's advantages, as all functions/classes can see each other, but on the other hand you will have longer compilation times and will also not be able to load parts of the script on demand.

It is my recommendation to use separate modules for separate functionalities. For example, in a game you may use one module for the GUI, another for the level scripting, and one module for each entity type (AI controllers). However, you may have different needs for your game, so you'll have to evaluate what is best for you.

Contexts are really just a callstack for an execution. There is no need to have more contexts than the number of scripts you have running in parallel. The context object is quite heavy, and you should avoid recreating new ones for each execution. Instead use memory pooling so you reuse already allocated contexts where possible.

Regards,
Andreas

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Thanks, I slowly get the hang on AngelScript. :)

But some more question, just to get this right:
In my C++ programm I have a lot of classes. If I want to register all of them to AngelScript, I have to do the following for all classes (some comments containing questions in the code snipped)?

//QUESTION: does the name have to be exactly the name of the C++ class?
int r = engine->RegisterObjectType("MyClass", 0, asOBJ_REF); assert( r >= 0 );

//QUESTION: is this also needed for singleton classes?
//QUESTION: does the name in the third parameter have to be "f()"?
r = engine->RegisterObjectBehaviour("MyClass", asBEHAVE_FACTORY, "MyClass@ f()", asFUNCTION(MyClass::asFactory), asCALL_CDECL); assert( r >= 0 );

//QUESTION: again: is this also needed for singleton classes?
//QUESTION: can AddRef and Release be private or do they have to be public?
//QUESTION: again: does the name in the third parameter have to be "f()", and: why is it always the same name?
r = engine->RegisterObjectBehaviour("MyClass", asBEHAVE_ADDREF, "void f()", asMETHOD(MyClass, AddRef), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("MyClass", asBEHAVE_RELEASE, "void f()", asMETHOD(MyClass, Release), asCALL_THISCALL); assert( r >= 0 );


So, this code sets up the C++ class to be available for AngelScript, did I get this right? And after that I have to do the following for ALL member function that I want to have available in AngelScript?

r = engine->RegisterObjectMethod("MyClass", "void ClassMethod()", asMETHOD(MyClass, ClassMethod), asCALL_THISCALL); assert( r >= 0 );


Is there a way to simply say "AngelScript, please take the whole class!" , without having to add ALL single member functions separately?

Now something more specific:
I use getter and setter methods in my classes. Is it enough to register these to AngelScript in order make them work, or do I have to register the underlaying variables, too?
How does AngelScript handle access modifiers from C++ (private, public, protected, etc)?

Thanks in advance. :)
[color="#880000"]//QUESTION: does the name have to be exactly the name of the C++ class?
No, the name you register for the type in AngelScript doesn't have to match the C++ class.

[color="#880000"]//QUESTION: is this also needed for singleton classes?
No. For singletons you don't want to register the factory behaviour with the script engine, as the scripts will never instanciate them.

[color="#880000"]//QUESTION: does the name in the third parameter have to be "f()"?
No, the function name doesn't have to be f. The function name is just there to make the declaration comply with the expected syntax. It won't be used or referred to after that.

[color="#880000"]//QUESTION: again: is this also needed for singleton classes?
It depends. You may register the AddRef/Release behaviours for the singleton class, but it is not necessary if you register the type with the flag asOBJ_NOHANDLE. (See manual)

[color="#880000"]//QUESTION: can AddRef and Release be private or do they have to be public?
It doesn't matter to AngelScript. As long as you can get the method pointer, it is valid for AngelScript.
[color="#880000"]//QUESTION: again: does the name in the third parameter have to be "f()", and: why is it always the same name?
I just use 'f' out of habit, but it can really be any valid identifier.

[color="#8b0000"]//QUESTION: So, this code sets up the C++ class to be available for AngelScript, did I get this right? And after that I have to do the following for ALL member function that I want to have available in AngelScript?
Yes. You need to explicitly register all methods that will be available to the script.

[color="#8b0000"]//QUESTION: Is there a way to simply say "AngelScript, please take the whole class!" , without having to add ALL single member functions separately?
Unfortunately not. C++ doesn't provide any functionality to enumerate methods/properties of a class. It would be neat to be able to do that. It is quite possible to write a small program that parses a C++ header file and automatically generates the code for registering the class with AngelScript though. However, many times you don't actually want to register all methods/properties of the C++ class with AngelScript, so an automatic code generator would have to be able to ignore unwanted functions somehow, maybe by parsing code comments as well.

[color="#8b0000"]//QUESTION: I use getter and setter methods in my classes. Is it enough to register these to AngelScript in order make them work, or do I have to register the underlaying variables, too?
It is enough to register the getters and setters. You shouldn't register anything that the scripts shouldn't access directly. For getters and setters you may want to follow the get_/set_ prefix naming convention. This will allow AngelScript to treat the methods as if they were actual properties (See manual)

[color="#8b0000"]//QUESTION: How does AngelScript handle access modifiers from C++ (private, public, protected, etc)?
It doesn't. If you register the method with AngelScript, the script will be able to call it, regardsless of the method being private or public. You probably don't want to register the private and protected methods though. Unless you have a specific need to allow AngelScript to access a method that the rest of the application cannot.


AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Thanks, I think with these information I can start coding. You give really great support. :)

But one last thing (the the time being :D ):
Can the factory and release (and probably others, too) functions be templated? So that I don't have to add them for ALL classes, but only on one central place?
You can implement them with templates, but you need to register the template instantiation for each class where AngelScript should be able to call them.

Maybe the article on registering class hierarchies in the manual can give you some ideas on how to reduce the amount of work for registering your interface with AngelScript.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Hi, I have a new question.

If I register a SIngleton type, how do I get access to the singleton-instance from AngelScript? Do I have to register the getInstance() method from my C++ class and call it from AngelScript code?

This topic is closed to new replies.

Advertisement