I recently added AngelScript (2.29.1 WIP) to my engine. After getting it working and setting up some types and a few scripts, I then rebuilt everything in release mode to discover it wasn't working. I'm building the source files into static libraries using the provided VC10 project files.
Also the MessageCallback is not being called to display any error info. With some testing I noticed registering my objects and global functions compile in release mode but if they are used in a script, there will be a build error with no error info.
Below is the value type I made. It's my color class holding 4 floats and a bunch of overloaded operators.
/************************************************************************
* FILE NAME: scriptcolor.cpp
*
* DESCRIPTION: CColor script object registration
************************************************************************/
// Physical component dependency
#include <script/scriptcolor.h>
// Standard lib dependencies
#include <assert.h>
// AngelScript lib dependencies
#include <angelscript.h>
// Game lib dependencies
#include <common/color.h>
namespace NScriptColor
{
/************************************************************************
* desc: Constructor
************************************************************************/
static void Constructor(void * thisPointer)
{
new(thisPointer) CColor();
}
/************************************************************************
* desc: Copy Constructor
************************************************************************/
static void CopyConstructor(const CColor & other, void * pThisPointer)
{
new(pThisPointer) CColor(other);
}
static void ConstructorFromFloats(float r, float g, float b, float a, void * pThisPointer)
{
new(pThisPointer) CColor(r, g, b, a);
}
/************************************************************************
* desc: Destructor
************************************************************************/
static void Destructor(void * pThisPointer)
{
((CColor*)pThisPointer)->~CColor();
}
/************************************************************************
* desc: Register the type
************************************************************************/
void Register( asIScriptEngine * pEngine )
{
// Register type
assert( pEngine->RegisterObjectType("CColor", sizeof(CColor), asOBJ_VALUE | asOBJ_APP_CLASS | asOBJ_APP_CLASS_CONSTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_CLASS_DESTRUCTOR ) > -1 );
// Register the object operator overloads
assert( pEngine->RegisterObjectBehaviour("CColor", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(Constructor), asCALL_CDECL_OBJLAST) > -1 );
assert( pEngine->RegisterObjectBehaviour("CColor", asBEHAVE_CONSTRUCT, "void f(const CColor & in)", asFUNCTION(CopyConstructor), asCALL_CDECL_OBJLAST) > -1 );
assert( pEngine->RegisterObjectBehaviour("CColor", asBEHAVE_CONSTRUCT, "void f(float, float, float, float)", asFUNCTION(ConstructorFromFloats), asCALL_CDECL_OBJLAST) > -1 );
assert( pEngine->RegisterObjectBehaviour("CColor", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(Destructor), asCALL_CDECL_OBJLAST) > -1 );
// assignment operator
assert( pEngine->RegisterObjectMethod("CColor", "CColor & opAssign(const CColor & in)", asMETHODPR(CColor, operator =, (const CColor &), CColor &), asCALL_THISCALL) > -1 );
// binary operators
assert( pEngine->RegisterObjectMethod("CColor", "CColor opAdd ( const CColor & in )", asMETHODPR(CColor, operator +, (const CColor &) const, CColor), asCALL_THISCALL) > -1 );
assert( pEngine->RegisterObjectMethod("CColor", "CColor opSub ( const CColor & in )", asMETHODPR(CColor, operator -, (const CColor &) const, CColor), asCALL_THISCALL) > -1 );
assert( pEngine->RegisterObjectMethod("CColor", "CColor opMul ( const CColor & in )", asMETHODPR(CColor, operator *, (const CColor &) const, CColor), asCALL_THISCALL) > -1 );
assert( pEngine->RegisterObjectMethod("CColor", "CColor opDiv ( const CColor & in )", asMETHODPR(CColor, operator /, (const CColor &) const, CColor), asCALL_THISCALL) > -1 );
assert( pEngine->RegisterObjectMethod("CColor", "CColor opAdd ( float )", asMETHODPR(CColor, operator +, (float) const, CColor), asCALL_THISCALL) > -1 );
assert( pEngine->RegisterObjectMethod("CColor", "CColor opSub ( float )", asMETHODPR(CColor, operator -, (float) const, CColor), asCALL_THISCALL) > -1 );
assert( pEngine->RegisterObjectMethod("CColor", "CColor opMul ( float )", asMETHODPR(CColor, operator *, (float) const, CColor), asCALL_THISCALL) > -1 );
assert( pEngine->RegisterObjectMethod("CColor", "CColor opDiv ( float )", asMETHODPR(CColor, operator /, (float) const, CColor), asCALL_THISCALL) > -1 );
// compound assignment operators
assert( pEngine->RegisterObjectMethod("CColor", "CColor opAddAssign ( const CColor & in )", asMETHODPR(CColor, operator +=, (const CColor &), CColor), asCALL_THISCALL) > -1 );
assert( pEngine->RegisterObjectMethod("CColor", "CColor opSubAssign ( const CColor & in )", asMETHODPR(CColor, operator -=, (const CColor &), CColor), asCALL_THISCALL) > -1 );
assert( pEngine->RegisterObjectMethod("CColor", "CColor opMulAssign ( const CColor & in )", asMETHODPR(CColor, operator *=, (const CColor &), CColor), asCALL_THISCALL) > -1 );
assert( pEngine->RegisterObjectMethod("CColor", "CColor opDivAssign ( const CColor & in )", asMETHODPR(CColor, operator /=, (const CColor &), CColor), asCALL_THISCALL) > -1 );
assert( pEngine->RegisterObjectMethod("CColor", "CColor opAddAssign ( float )", asMETHODPR(CColor, operator +=, (float), CColor), asCALL_THISCALL) > -1 );
assert( pEngine->RegisterObjectMethod("CColor", "CColor opSubAssign ( float )", asMETHODPR(CColor, operator -=, (float), CColor), asCALL_THISCALL) > -1 );
assert( pEngine->RegisterObjectMethod("CColor", "CColor opMulAssign ( float )", asMETHODPR(CColor, operator *=, (float), CColor), asCALL_THISCALL) > -1 );
assert( pEngine->RegisterObjectMethod("CColor", "CColor opDivAssign ( float )", asMETHODPR(CColor, operator /=, (float), CColor), asCALL_THISCALL) > -1 );
// Class members
assert( pEngine->RegisterObjectMethod("CColor", "void Set( float r, float g, float b, float a )", asMETHOD(CColor, Set), asCALL_THISCALL) > -1 );
// Register property
assert( pEngine->RegisterObjectProperty("CColor", "float r", asOFFSET(CColor, r)) > -1 );
assert( pEngine->RegisterObjectProperty("CColor", "float g", asOFFSET(CColor, g)) > -1 );
assert( pEngine->RegisterObjectProperty("CColor", "float b", asOFFSET(CColor, b)) > -1 );
assert( pEngine->RegisterObjectProperty("CColor", "float a", asOFFSET(CColor, a)) > -1 );
}
} // NScriptColor
This is my script class I'm using to pass in as a reference. This is how my scripts will affect my sprite class's behavior.
/************************************************************************
* desc: Register the class with AngelScript
************************************************************************/
void CScriptComponent2d::Register( asIScriptEngine * pEngine )
{
// Register CScriptComponent2d reference and methods
assert( pEngine->RegisterObjectType("CScriptComponent2d", 0, asOBJ_REF|asOBJ_NOCOUNT) > -1 );
assert( pEngine->RegisterObjectMethod("CScriptComponent2d", "void SetVisible(bool visible)", asMETHOD(CScriptComponent2d, SetVisible), asCALL_THISCALL) > -1 );
assert( pEngine->RegisterObjectMethod("CScriptComponent2d", "void SetColor(CColor & in)", asMETHOD(CScriptComponent2d, SetColor), asCALL_THISCALL) > -1 );
assert( pEngine->RegisterObjectMethod("CScriptComponent2d", "const CColor & GetColor()", asMETHOD(CScriptComponent2d, GetColor), asCALL_THISCALL) > -1 );
assert( pEngine->RegisterObjectMethod("CScriptComponent2d", "const CColor & GetDefaultColor()", asMETHOD(CScriptComponent2d, GetDefaultColor), asCALL_THISCALL) > -1 );
assert( pEngine->RegisterObjectMethod("CScriptComponent2d", "uint GetFrameCount()", asMETHOD(CScriptComponent2d, GetFrameCount), asCALL_THISCALL) > -1 );
assert( pEngine->RegisterObjectMethod("CScriptComponent2d", "void SetFrame(uint index)", asMETHOD(CScriptComponent2d, SetFrame), asCALL_THISCALL) > -1 );
} // Register
Here's my Global functions. Nothing too fancy. Just the bare basics.
/************************************************************************
* FILE NAME: scriptglobals.cpp
*
* DESCRIPTION: AngelScript global function registration
************************************************************************/
// Physical component dependency
#include <script/scriptglobals.h>
// Standard lib dependencies
#include <assert.h>
// AngelScript lib dependencies
#include <angelscript.h>
// Game lib dependencies
#include <utilities/highresolutiontimer.h>
#include <utilities/genfunc.h>
namespace NScriptGlobals
{
/************************************************************************
* desc: Suspend the script to the game loop
************************************************************************/
void Suspend()
{
asIScriptContext *ctx = asGetActiveContext();
// Suspend the context so the game loop can resumed
if( ctx )
ctx->Suspend();
} // Suspend
/************************************************************************
* desc: Register the global functions
************************************************************************/
void Register( asIScriptEngine * pEngine )
{
assert( pEngine->RegisterGlobalFunction("float GetElapsedTime()", asMETHOD(CHighResTimer, GetElapsedTime), asCALL_THISCALL_ASGLOBAL, &CHighResTimer::Instance()) > -1 );
assert( pEngine->RegisterGlobalFunction("void Print(string &in)", asFUNCTION(NGenFunc::PostDebugMsg), asCALL_CDECL) > -1 );
assert( pEngine->RegisterGlobalFunction("void Suspend()", asFUNCTION(Suspend), asCALL_CDECL) > -1 );
}
} // NScriptGlobals
Here's my test script.
void Fade( CScriptComponent2d @script )
{
Hold( 500 );
while( true )
{
Hold( 100 );
ColorTo( 1000, CColor(1,1,1,0), script );
Hold( 200 );
ColorTo( 1000, CColor(1,1,1,1), script );
}
}
void Animate( CScriptComponent2d @script )
{
while( true )
{
Play( 24, script );
}
}
And here's my utilities script that I'm building as a script library of general purpose functions.
/************************************************************************
* FILE NAME: utilities.ang
*
* DESCRIPTION: General purpose utility scripts
************************************************************************/
/************************************************************************
* desc: Color to the final color in time
************************************************************************/
void ColorTo( float time, CColor final, CScriptComponent2d & script )
{
CColor current = script.GetColor();
CColor inc = (final - script.GetColor()) / time;
while( true )
{
time -= GetElapsedTime();
current += inc * GetElapsedTime();
script.SetColor( current );
if( time < 0 )
{
script.SetColor( final );
break;
}
Suspend();
}
} // ColorTo
/************************************************************************
* desc: Play the animation
************************************************************************/
void Play( float fps, CScriptComponent2d & script )
{
float time = 1000.0 / fps;
uint frameCount = script.GetFrameCount();
for( uint i = 0; i < frameCount; ++i )
{
script.SetFrame( i );
Hold( time );
}
} // ColorTo
/************************************************************************
* desc: Hold the script execution in time
************************************************************************/
void Hold( float time )
{
while( true )
{
time -= GetElapsedTime();
if( time < 0 )
break;
Suspend();
}
} // Hold
As stated above, everything works in debug mode and the only thing that works in release mode is an empty do nothing function. Even that won't work if I add the global function Print("test");
AngelScript is so amazing.
Thanks for your help!