Advertisement

A couple of beginner's questions

Started by June 11, 2012 08:25 PM
0 comments, last by WitchLord 12 years, 3 months ago
Hello,
As I have few unrelated questions I picked generic topic instead of trying to divide these questions into more threads, hope its ok.

1) I'm using AngelScript for inline script events in libRocket UI library. This means that whenever there is event encountered in code (that looks like typical Javascript HTML event - onclick="dosomething()" etc.) I generate and compile function like this:
[source lang="cpp"]
std::string code = "void InlineEventFunc(Event @event) {\n" + m_ScriptSource + ";\n}";
r = m_Module->CompileFunction(section.c_str(), code.c_str(), -1, 0, &m_Func);
[/source]

This works well, but I want to achieve something that works like in Javascript where there is a special "scoped" variable this that holds element which just received this event. Is there a way to register such special variable not using global registration through asIScriptEngine, which will be global for all scripts and I don't want this. I just want it to be global for certain module and set it just before executing above function.

PS. While typing this question I suddenly realized I can pass this special variable to function when I call it, just by extending its argument list like this:
[source lang="cpp"]
std::string code = "void InlineEventFunc(Event @event, Element @this) {\n" + m_ScriptSource + ";\n}";
r = m_Module->CompileFunction(section.c_str(), code.c_str(), -1, 0, &m_Func);
[/source]
This should work I think in this case, but I still wonder if its possible to set module-scope variable and how is it done?

2) How do you solve problem of many similar value types in AngelScript? For example, I use std::string as my base string type and have it registered in AS, but library I mentioned above uses its own Rocket::Core::String type.

Every function I register that takes or returns this Rocket::Core::String requires me to wrap it with a function that will convert it on the fly from/to std::string/Rocket::String. This way I can stop worrying about converting back and forth between these two types (and Rocket::Core::String does not converter or constructor from std::string). I do it this way:
[source lang="cpp"]engine.RegisterObjectMethod(name, "void SetId(const string &in)", asFUNCTION(Element_SetId), asCALL_CDECL_OBJLAST);

void Element_SetId(const std::string& id, Core::Element* obj)
{
obj->SetId(id.c_str()); // SetId takes Core::String as an argument, but it also takes C string as constructor so it works
}[/source]

Is it the best way to solve problem with many different types introduced by various libraries? I will have the same problem with my vector class sad.png Its not that bad but I wonder if it adds some overhead versus registering class methods with asMETHOD? I checked how Python does it and there is something called "converter" that takes some type and converts it into Python's corresponding type. I don't think AS has it but maybe there is a good practice for solving this kind of problems?

3) Virtual methods - maybe I'm blind but I couldn't find how something like this would behave when registered in AS:
[source lang="cpp"]class A
{
virtual void Foo() { foo(); }
}

class B: A
{
virtual void Foo() { b_foo(); }
}
[/source]

Then do I do this to register class A:
[source lang="cpp"]
engine.RegisterObjectMethod("A", "void Foo()", asMETHOD(A, Foo), asCALL_THISCALL);
[/source]
but when I register B, do I have to do only this:
[source lang="cpp"]
engine.RegisterObjectMethod("B", "void Foo()", asMETHOD(B, Foo), asCALL_THISCALL);
[/source]
or this:
[source lang="cpp"]
engine.RegisterObjectMethod("B", "void Foo()", asMETHOD(A, Foo), asCALL_THISCALL);
engine.RegisterObjectMethod("B", "void Foo()", asMETHOD(B, Foo), asCALL_THISCALL);
[/source]
Will the second try to register "B", "void Foo()" override A's implementation, or it won't work? Should I only register B's implementation there? I ask mostly because if I template parent class so I can easily register its methods for children classes like this:
[source lang="cpp"]
// Register base class A
RegisterAMethods("A");

// Register child class B
RegisterAMethods("B");
RegisterBMethods();
[/source]
If RegisterAMethods already registers "Foo" for A's implementation, then RegisterBMethods registers it again, will the latter work? If not, I have to somehow pass info to RegisterAMethods to exclude its own Foo() when I use it to register child class.

I hope I make sense here, just trying to understand how virtual methods work in AS and how they are registered. If there is some page dedicated to this in manual, I'd gladly read it, but I just couldnt find anything specific on virtual methods.

Where are we and when are we and who are we?
How many people in how many places at how many times?
1)

In my opinion the easiest way is to pass it as a parameter like you already found out.

However, it is possible to register a global property that is only available for a specific module with the use of access masks. However, if you have two or more different modules that is supposed to access different properties with the same name, then this won't be possible, as the name will conflict. Namespaces may help a bit, but then the module needs to know in which namespace to look for the property, which is not ideal.

Virtual property accessors is probably the most flexible solution. With this you will be able to determine at the moment the get accessor is called which property to return to the script, and will thus be able to expose different properties to different modules, but all with the same name. Access masks can still be used to prevent modules that shouldn't see the property at all from using the property.

2)

You can register the different string versions with AngelScript as normal object types and let the script itself do the conversions. This may however be a bit confusing to the script writer so it is not recommended.

Writing thin proxy functions like you already do is in my opinion the best option. It will add a slight overhead, but probably less than if the conversion of the script type is done within the script itself.

If you do not want to write all the proxy functions yourself, you may be able to automatize it with templates. I'm not that good with templates myself, so I cannot explain how it might be done, but you can take a look at the auto wrapper add-on. It has some nifty templates to automatize the implementation of generic proxy methods for registering functions with the asCALL_GENERIC calling convention.

3)

You almost got it right. This article in the manual shows how to register class hierarchies and the example there registers the methods of the derived class in a pretty similar manner as to what you hinted at, i.e. RegisterAMethods("B"); RegisterBMethods(), however it uses templates to get the correct class type when registering A's members.

If you don't use multiple inheritances it doesn't really matter if you use A or B when registering B's member as the virtual method pointer is exactly the same, but if you do use multiple inheritance, then it is important that you use the type B when taking the address of B's members. Otherwise the pointer will not correctly encode the offset needed to get to B's virtual function table.


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

This topic is closed to new replies.

Advertisement