How do you get the value of properties from script classes? My Object class needs access to XY coordinates to pass to other parts of my game engine. My script class looks like this:
As you see, I have to do "object.WHATEVER" to access anything from the object class in the script class. Instead I want to define the properties in the script class and make the object class access the values of those properties through some sort of proxy function like, float GetX(). This really makes things simple in the scripting side. Is there a way to check if a property exists before I try to get the value?
If you use a proxy you could try to receive the function from the context i guess. If it returns 0 there is no such function. If it returns a function you have your proxy.
...i guess.
I'd rather not have to do that in the script itself even though that would be the easiest way. I tried this but it doesn't seem to work:
float Object::GetX() const
{
if (!createCalled)
return x;
for (int i = 0; i < scrType->GetPropertyCount(); ++i)
{
const char *decl = scrType->GetPropertyDeclaration( i);
if (decl == "float x");
{
float value = *static_cast<float*>(scrObj->GetAddressOfProperty( i));
return value;
}
}
return x;
}
float Object::GetY() const
{
if (!createCalled)
return y;
for (int i = 0; i < scrType->GetPropertyCount(); ++i)
{
const char *decl = scrType->GetPropertyDeclaration( i);
if (decl == "float y");
{
float value = *static_cast<float*>(scrObj->GetAddressOfProperty( i));
return value;
}
}
return y;
}
If it finds x or y in the script, then it is supposed to return that value, otherwise default to the value that object class has. I'm sure there is a simpler way to do this.
And you are not sure, wether the asIScriptObject* you have has the ProxyMethod getName(), right?
You can simply check that. The proxys all have the same declarationpattern, have they?
get[PropName](void)
So you could try to retrieve the method get[PropName]() from the scriptcontext by declaration. If it returns 0 there is no such method in the scriptclass, otherwise you can simply call the function you received and get the return value.
Here you would try to get the "string getName()" method.
I realized a similar matter with a template method in my "angelscript handler".
Or did i misudnerstood your problem?
Im quite new to angelscript myself, so i would rather listen to the older members here than to my poor advice. ^^
1. You compare the pointer of the returned decl, rather than the value of the string.
2. You have a ; after the if condition.
3. A reinterpret_cast is more appropriate than a static_cast. Though I suppose in the end C++ end up doing the same thing for both in this case.
Also, rather than getting the property declaration and then comparing the string it is better to compare the property name and type separately to get a little better performance.
Here's what I suggest:
float Object::GetY() const
{
if (!createCalled)
return y;
for (int i = 0; i < scrObj->GetPropertyCount(); ++i)
{
const char *name = scrObj->GetPropertyName(i);
int type = scrObj->GetPropertyTypeId(i);
if( strcmp(name, "y") == 0 && type == asTYPEID_FLOAT )
{
float value = *reinterpret_cast<float*>(scrObj->GetAddressOfProperty(i));
return value;
}
}
return y;
}
If this is something you'll do a lot, you'll probably want to cache the offset of the property, so you don't have to search for it for each access.
float Object::GetY() const
{
if (!createCalled)
return y;
if( not in cache )
{
for( int i = 0; i < srcType->GetPropertyCount(); ++i )
{
const char *name;
int type;
int offset;
srcType->GetProperty(i, &name, &type, 0, &offset);
if( strcmp(name, "y" == 0) && type == asTYPEID_FLOAT )
{
store offset in cache for the 'y' property
break;
}
}
}
if( in cache )
{
float value = *reinterpret_cast<float*>(srcObj + offset);
return value;
}
return y;
}
If you decide to go with using the offset instead of GetAddressOfProperty() you need to remember that object types are not stored inline, so you'll have to dereference the pointer twice to get to the value. Of course, if you only plan to access primitive values, then you don't have to worry about this.
class OBJECT_NAME
{
Object @object;
float x; // These will be used instead of the object's x and y
float y;
OBJECT_NAME(Object @object)
{
@this.object = object;
}
void Update()
{
}
void Render()
{
draw_sprite( object.mask_index, 0, x, y);
}
}
From the script side it will be easier to access the object's position this way. But from the application side he'll have to look up the properties in the script class instead, if they are really there.
There are 3 errors in your code: 1. You compare the pointer of the returned decl, rather than the value of the string. 2. You have a ; after the if condition. 3. A reinterpret_cast is more appropriate than a static_cast. Though I suppose in the end C++ end up doing the same thing for both in this case. Also, rather than getting the property declaration and then comparing the string it is better to compare the property name and type separately to get a little better performance. Here's what I suggest: float Object::GetY() const { if (!createCalled) return y; for (int i = 0; i < scrObj->GetPropertyCount(); ++i) { const char *name = scrObj->GetPropertyName(i); int type = scrObj->GetPropertyTypeId(i); if( strcmp(name, "y") == 0 && type == asTYPEID_FLOAT ) { float value = *reinterpret_cast(scrObj->GetAddressOfProperty(i)); return value; } } return y; } If this is something you'll do a lot, you'll probably want to cache the offset of the property, so you don't have to search for it for each access. float Object::GetY() const { if (!createCalled) return y; if( not in cache ) { for( int i = 0; i < srcType->GetPropertyCount(); ++i ) { const char *name; int type; int offset; srcType->GetProperty(i, &name, &type, 0, &offset); if( strcmp(name, "y" == 0) && type == asTYPEID_FLOAT ) { store offset in cache for the 'y' property break; } } } if( in cache ) { float value = *reinterpret_cast(srcObj + offset); return value; } return y; } If you decide to go with using the offset instead of GetAddressOfProperty() you need to remember that object types are not stored inline, so you'll have to dereference the pointer twice to get to the value. Of course, if you only plan to access primitive values, then you don't have to worry about this.
I tried the cache technique you described above and it works perfect! Now lets say I would want to change the value of the property from the C++ object class. I want to set the script class's x and y initial values in the object class since now they are not being placed correctly (they all are placed at (0,0) unless I explicitly set them to whats in @object). How would that work?