Advertisement

Registering native templated class as value type

Started by December 02, 2011 11:47 PM
4 comments, last by WitchLord 12 years, 11 months ago
THIS ISSUE IS PROBABLY SOLVED - CHECK THE EDIT AT THE BOTTOM

Hello,
I recently started thinking about scripting in our game engine and I looked what different scripting solutions have to offer. I found Angel Script cause it was mentioned on Wolfire's blog and I must say I really love it. I'm a Python guy so I thought LUA would be good, but after comparing those two I'm amazed how cool AS is. And how easy it was to implement basic functionality with it for a noob like me. I already have a GameEntity scripting proxy that allows me to control and extend in-game objects by AS scripts. I'm now adding some basic types like Vec3 for some math operations. Here where I got into some troubles.

I used Vector3 addon as reference on how to implement our own Vec3 class. We have that class as a template (VEC3<float>, VEC3<double> etc.) but I wanted to just register VEC3<float> version for now, as a non-template in AS, so I can use it as a basic "vec3" type. All went well with basic registration, property access, constructors but when I got to operators I couldn't make it work with addon sample code.

In Vector3 you do something like this:


r = engine->RegisterObjectMethod("vector3", "vector3 opAdd(const vector3 &in) const", asFUNCTIONPR(operator+, (const Vector3&,
const Vector3&), Vector3), asCALL_CDECL_OBJFIRST); assert( r >= 0 );


When I tried similar way for our VEC3:


r = engine->RegisterObjectMethod("vec3", "vec3 opAdd(const vec3 &in) const", asFUNCTIONPR(operator+, (const Vec3f&, const Vec3f&),
Vec3f), asCALL_CDECL_OBJFIRST); assert( r >= 0 );


I started getting compiler error: .\src\Managers\ScriptManager.cpp(54) : error C2065: '+' : undeclared identifier

This is part of my VEC3's operator overloading:


VEC3 operator + (const VEC3 &v) const;


VEC3<T> VEC3<T>::operator + (const VEC3<T> &v) const
{
return VEC3(x + v.x, y + v.y, z + v.z);
}


I noticed that second parameter to asFUNCTIONPR has 2 values in Vector3 sample, and I also used 2 but it seems like I should only use 1 looking at how our operator+ is overloaded. So I changed it, but it didn't fix the error:


r = engine->RegisterObjectMethod("vec3", "vec3 opAdd(const vec3 &in) const", asFUNCTIONPR(operator+, (const Vec3f&),
Vec3f), asCALL_CDECL_OBJFIRST); assert( r >= 0 );


This still continued to give undeclared identifier '+' error on compile. What is the reason for this? I tried to see what that asFUNCTIONPTR does but this:

#define asFUNCTIONPR(f,p,r) asFunctionPtr((void (*)())(static_cast<r (*)p>(f)))

looks to me like a BrainF.. language, I know nothing about function pointers in so advanced form. Could anyone please point me what may be the problem?

EDIT:
I think I found the reason, I was using asFUNCTIONPR when it was a class operator I was refering too. I looked at Vector3 addon code and found that it defines some of the operations (*, /, +, - etc.) as functions that are friended? (if I'm correct) by a Vector3 struct.



Vector3 operator*(const Vector3 &v, float s)
{
// Return a new object as a script handle
Vector3 res(v.x * s, v.y * s, v.z * s);
return res;
}



I changed the code to:


engine->RegisterObjectMethod("vec3", "vec3 opAdd(const vec3 &in) const", asMETHODPR(Vec3f, operator+, (const Vec3f &) const, Vec3f), asCALL_THISCALL); assert( r >= 0 );



and now it compiles and seem to work (add etc.) for now :) Can someone explain in simple words why Vector3 sample does that thing with defining function outside of struct for some of the operators, instead of doing it as other operators (with methods)? Even though it works for me, I like to understand why things were done one or other way. Thanks!

Where are we and when are we and who are we?
How many people in how many places at how many times?
You're absolutely correct.

Both ways work equally well. There is not really any particular benefit in doing it one way or the other, so it is mostly a matter of taste.



I'm happy to hear you like AngelScript, and find it so easy to work with. I look forward to seeing what you'll do with it.

I'm constantly making improvements, so if you have any suggestions don't hesitate to tell me.

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

Advertisement

You're absolutely correct.

Both ways work equally well. There is not really any particular benefit in doing it one way or the other, so it is mostly a matter of taste.


Ah, good to know, thanks!


I'm happy to hear you like AngelScript, and find it so easy to work with. I look forward to seeing what you'll do with it.

I'm constantly making improvements, so if you have any suggestions don't hesitate to tell me.
[/quote]

Its great to see that AS community is so alive and happy to help :) I will definately have more questions coming once I start doing more advanced stuff, but I'm amazed how quickly I was able to jump from "barely know about any scripting language" to "just implemented basic scripting in 3d game engine using AS" state :)

I'm using similar pattern you suggested in many posts - GameEntity in C++ engine linked through GameObjectLink thats registered in AS and passed by reference to constructor of basic entity which is AS Entity class. Then I'm planning to derive from it all sorts of objects (we're making kind of rpg/survival engine so there will be plenty of different objects, crafting etc.)

This is some lousy fraps from what I just got to work, I feel weird posting such silly thing here :)



Took me about 6 hours to get it working, sphere is just basic debug object.as script that sets position and color and then updates it through Update() event which all registered game objects receive from C++ engine.

Since we're here, and topic turned out to solve itself, I will try asking one thing - its about multiple inheritance. I wanted to do some kind of "characteristics" classes that would define behaviour of objects, things like Decaying, Flammable, Edible, Drinkable, such classes could be then inherited by some object like


class Meat: Entity, Edible, Decaying



this would add some default behaviour to the object (like, reacting on some events "OnDecay", "OnEat"). I could use interfaces but they wont do what I want, because I wanted these characteristic classes to actually define some default logic, not only tell us that that object implements some methods. So if I inherit OnDecay, class receives some set of methods that make it decay "out of the box", add some properties to inheriting class etc.

Now, that AS does not support multiple inheritance and is not going to, what would be a good way to implement such properties that instead of doing what interface do (only telling us this class should implement that behaviour itself), will also give us that base functionality that can be then either completly overriden or extended (by calling parent class + defining its own code).

Thanks for any support :)

Where are we and when are we and who are we?
How many people in how many places at how many times?
Right now there isn't a quick way out. The functions will have to be implemented for each object that needs them.

In a future version I'll most likely implement mix-ins, which would allow for code reusability without the complexity of multiple inheritance.

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


Right now there isn't a quick way out. The functions will have to be implemented for each object that needs them.

In a future version I'll most likely implement mix-ins, which would allow for code reusability without the complexity of multiple inheritance.


Wow, that would be fantastic. I'm very used to Ruby/Python, its great to see Angel Script going a bit more into direction of "programmer friendly" languages. For instance, Ruby doesn't have multiple inheritance either, but its mixins are making this language so great and flexible. Another thing I'd dream of would be some kind of closure implementation - some purists will probably disagree but I find closures a great thing for easy map/sort operations on some data structure, or defining events without defining separate functions for everything. Its that kind of thing that would really fit into a scripting language.

Where are we and when are we and who are we?
How many people in how many places at how many times?
closures is also on my to-do list, although as a C++ programmer, I haven't quite grasped the usefulness of them. There are several other steps to implement before I get to full closures, e.g. local function declarations, lambda functions (or anonymous functions), and delegates. Once I have these others implemented closures should be quite easy to implement.

You can check out the to-do list on the WIP page.

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