Hello Angelscript users,
I'm trying to downcast an object handle from an application registered interface to a script defined class. I'm wanting to do this as described in the 'Returning script classes' section on this page. But that page doesn't describe what you can/cannot do with the returned handle, and that's where it's going wrong for me.
My final goal is to be able to attach script instances to entities (as behaviours), but then i also want to get those script instances from inside other scripts. So for example i want the scene's main script be able to get a behaviour script that's attached to an entity in that scene. I've added relevant code below, i've provided quite alot to provide the entire context.
The application registers te interface i'm using to pass around the script instance like so:
engine->RegisterInterface( "Script" );
Then the behaviours that are attached to an entity are included by the script builder like so:
int IncludeCallback( const char* include, const char* from, CScriptBuilder* builder, void* userParam )
{
...(other predefined includes)
else if( std::string( include ).compare( "EntityBehaviour" ) == 0 )
{
static std::string entityBehaviourClass =
"class EntityBehaviour : Script\n\
{\n\
Entity@ entity;\n\
ComponentLight@ light;\n\
ComponentModel@ model;\n\
...(other components)
}";
return builder->AddSectionFromMemory( "EntityBehaviour", entityBehaviourClass.c_str() );
}
...(includes from files)
}
The final scripted behaviour includes and implements the EntityBehaviour.
#include "EntityBehaviour"
class TestAnimPlayer : EntityBehaviour
...(class implementation)
All of this is working fine by itself. But then when i try to add the functionality of getting the behaviours from an entity something is going wrong. I have added the function that should return the script class. This is registered outside the angelscript package so it's wrapped. The returned void* is actually an asIScriptObject*.
void* GetScriptBehaviour( Entity& entity, const std::string& typeName )
{
...(looks up the behaviour by it's name and returns an asIScriptObject*)
}
scriptManager.RegisterObjectMethod( "Entity", "Script@ GetScriptBehaviour( const string& in )", asFUNCTION( GetScriptBehaviour ), EECore::ScriptManager::CALL_CDECL_OBJFIRST )
And here's the final script where it's going wrong:
Entity@ lb = scene.GetEntity( "LB animated" ); //This handle is valid.
Script@ playerScript = lb.GetScriptBehaviour( "TestAnimPlayer" ); //This handle is valid.
//DebugScriptType( playerScript );
if( playerScript is null )
Print( "no player script found" );
else
Print( "Player script was found" ); //This is printed (since the andle is valid)
EntityBehaviour@ behaviour = cast< EntityBehaviour >( playerScript ); //Will be null
if( behaviour is null )
Print( "cast failed" ); //Prints this
else
Print( "cast succeeded" );
TestAnimPlayer@ animPlayer = cast< TestAnimPlayer >( playerScript ); //Will be null
if( animPlayer is null )
Print( "cast failed" ); //Prints this
else
Print( "cast succeeded" );
//animPlayer.animationClip = "dance";
The page on inheritance describes the '@handle_to_B = cast<B>(handle_to_A);' behaviour, which is what i'm wanting to do. Though i'm not sure, shouldn't it cast to B@?
For debugging purposes i've hadded the DebugScriptType function, if i enable this it calls this method:
void DebugScriptType( asIScriptObject* obj )
{
obj->Release();
}
engine->RegisterGlobalFunction( "void DebugScriptType( Script@ obj )", asFUNCTION( DebugScriptType ), asCALL_CDECL );
When inspecting the obj using the debugger it's filled in like this:
obj
-objType
-name
-dynamic: TestAnimPlayer
-interfaces
-[0].name
-local: Script
-derived from
-name
-dynamic: EntityBehaviour
-interfaces
-[0].name
-local: Script
This type hierarchy looks correct to me.
I hope somebody can help me out a bit with this, or would it be better to use the script handle add-on?
Thanks in advance.