Proper way to update scripted objects?
Is there a proper way to script game objects? In my current system there is only one context and each object type has its own module. The problem is that each instance of an object type seems to share the same value of a global variable, but if I use a registered property the value would be different (as it should).
My current script structure:
[source lang="cpp"]
int rad;
void Create( Object @object)
{
object.sprite_index = 0;
rad = random(300);
}
void Update( Object @object)
{
if (object.angle > 360.0f)
{
object.angle = 0.0f;
}
object.angle += 0.2225f;
object.x = 400 + cos(object.angle) * rad;
object.y = 300 + sin(object.angle) * rad;
}
void Render( Object @object)
{
draw_sprite( object.sprite_index, 0, object.x, object.y);
}
[/source]
As you see I'm setting the value of the global variable rad to whatever random returns. When was debugging the app I saw that it was calling random each time, but only the value of the first call seemed to be the only one stored. Should I be using a new context for function?
My current script structure:
[source lang="cpp"]
int rad;
void Create( Object @object)
{
object.sprite_index = 0;
rad = random(300);
}
void Update( Object @object)
{
if (object.angle > 360.0f)
{
object.angle = 0.0f;
}
object.angle += 0.2225f;
object.x = 400 + cos(object.angle) * rad;
object.y = 300 + sin(object.angle) * rad;
}
void Render( Object @object)
{
draw_sprite( object.sprite_index, 0, object.x, object.y);
}
[/source]
As you see I'm setting the value of the global variable rad to whatever random returns. When was debugging the app I saw that it was calling random each time, but only the value of the first call seemed to be the only one stored. Should I be using a new context for function?
You should use script classes for this. Your script might look like this:
Then you would instantiate one script class for each of your game objects. The application's Object class would preferably keep a pointer to the corresponding asIScriptObject, and the script class can also store a pointer to the application's Object.
The global variables are stored in the module, so they will be shared by all contexts that call functions on the same module. You do not need multiple contexts, except if you have a situation where more than one script function is being executed at the same time, e.g. if a script function calls an application function that in turn calls another script function.
ObjectController @Create( Object @object)
{
return ObjectController(object);
}
class ObjectController
{
int rad;
Object @object;
ObjectController(Object @object)
{
@this.object = object;
object.sprite_index = 0;
rad = random(300);
}
void Update()
{
if (object.angle > 360.0f)
{
object.angle = 0.0f;
}
object.angle += 0.2225f;
object.x = 400 + cos(object.angle) * rad;
object.y = 300 + sin(object.angle) * rad;
}
void Render()
{
draw_sprite( object.sprite_index, 0, object.x, object.y);
}
}
Then you would instantiate one script class for each of your game objects. The application's Object class would preferably keep a pointer to the corresponding asIScriptObject, and the script class can also store a pointer to the application's Object.
The global variables are stored in the module, so they will be shared by all contexts that call functions on the same module. You do not need multiple contexts, except if you have a situation where more than one script function is being executed at the same time, e.g. if a script function calls an application function that in turn calls another script function.
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game
Thanks! It works perfect now.
How do you register the script class from the C++ part of the application? and Instantiate it?
-Jawshttp://uploading.com/files/eff2c24d/TGEpre.zip/
[quote name='justin12343' timestamp='1312294171' post='4843609']
Thanks! It works perfect now.
How do you register the script class from the C++ part of the application? and Instantiate it?
[/quote]
You read the documentation?
I don't mean to be rude, but this truly is a 'Read the Fine Manual' question.
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game
[quote name='Xaer0' timestamp='1312450066' post='4844415']
[quote name='justin12343' timestamp='1312294171' post='4843609']
Thanks! It works perfect now.
How do you register the script class from the C++ part of the application? and Instantiate it?
[/quote]
You read the documentation?
I don't mean to be rude, but this truly is a 'Read the Fine Manual' question.
[/quote]
your not being rude, just realistic
indeed I did read the manual (which for the most part is awesome) but I ended up getting caught up where you instanciate the script Object,
more specifically here,
// Get the factory function id from the object type
int factoryId = type->GetFactoryIdByDef("MyClass @MyClass()");
This caused the script to crash when I tried to get the return object's pointer here,
// Get the object that was created
asIScriptObject *obj =*(asIScriptObject**)ctx->GetAddressObReturnValue();
Now I renamed the 'MyClass' to the name of my entities class before hand, but after this crash and some reading on the forums
I realized that the factory function is not supposed to be the constructor (makes sense actually ) but a global function returning
a newly created script object. Alright, Cool, Progress!
so I made a function like
CPlayer @Create(Entity @obj)
{
return CPlayer(obj);
}
With CPlayer taking a object handle to the C++ Entity Object,
however, this crashed as the returned object was also invalid,
After a few (A Lot) more views of the good manual, i found a nice
helper function for creating Script Objects
int typeId = module->GetTypeIdByDecl( className );
sDriver = ( asIScriptObject*) engine->CreateScriptObject( typeId );
Now this is a bit less flexible, because I cant' pass in the Entity Object
to the script by its constructor, however I alleviated this issue by
requiring script Classes to Implement an 'OnStart(Entity @obj)'
function that runs once, when the Entity is first created, At the minimum,
it just has to set an internal handle to the C++ Entity Object equal to obj,
but can be used for whatever.
So I more or less solved the issue, but im still curious as to how to properly
implement the Factory function to keep the 'OnStart' from being
mandatory.
When all said and done, this is an awesome script engine/language WitchLord, thank you!
-Jawshttp://uploading.com/files/eff2c24d/TGEpre.zip/
Not sure why you're having trouble with calling the factory function. Here's an excerpt from my own game engine for creating a script object
PrepareContext, just takes an asIScriptContext from a pool of available context's and calls Prepare on it. ExecuteCall calls the context's execute and also handles possible exceptions or other unwanted returns.
Here's how I get the id of the factory function:
type is the asIObjectType interface for the class.
I hope that may shed some light on your trouble.
asIScriptObject *CScriptMgr::CreateScriptObject(SEntityController *type, CGameObjectLink *link)
{
// Call the factory function to create the engine
asIScriptObject *ctrl = 0;
asIScriptContext *ctx = PrepareContext(type->factoryFuncId);
if( ctx )
{
*((CGameObjectLink**)ctx->GetAddressOfArg(0)) = link;
link->AddRef();
int r = ExecuteCall(ctx);
if( r == asEXECUTION_FINISHED )
{
// Get the newly created object and return it
ctrl = *((asIScriptObject**)ctx->GetAddressOfReturnValue());
ctrl->AddRef();
}
ReturnContextToPool(ctx);
}
return ctrl;
}
PrepareContext, just takes an asIScriptContext from a pool of available context's and calls Prepare on it. ExecuteCall calls the context's execute and also handles possible exceptions or other unwanted returns.
Here's how I get the id of the factory function:
... other code
// Find the factory function
string s = string(type->GetName()) + "@ " + string(type->GetName()) + "(CEntity @)";
ctrl->factoryFuncId = type->GetFactoryIdByDecl(s.c_str());
if( ctrl->factoryFuncId < 0 )
{
LOG(("Can't find '%s'", s.c_str()));
app->console->WriteLine("Couldn't find proper class constructor");
delete ctrl;
return 0;
}
... other code
type is the asIObjectType interface for the class.
I hope that may shed some light on your trouble.
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game
I was having the same problem but I bypassed it by getting the function id from the module itself. It always fails if I try to get a Factory Id from the type.
Now the only problem is when I close the game, it crashes when the garbage collector does a final clean up.
EDIT:
Simple change made it work:
But it still crashes on exit though.
int id = module->GetFunctionIdByDecl( "ObjectController @Create( Object @object)");
Now the only problem is when I close the game, it crashes when the garbage collector does a final clean up.
int asCScriptEngine::CallObjectMethodRetInt(void *obj, int func)
{
asCScriptFunction *s = scriptFunctions[func]; // <---- Crashes Here Because It Is A Null Pointer
asSSystemFunctionInterface *i = s->sysFuncIntf;
EDIT:
Simple change made it work:
int id = scrType->GetFactoryIdByDecl( "ObjectController @ObjectController( Object @object)");
But it still crashes on exit though.
Are you calling AddRef on the asIScriptObject that you create? If you don't the object will be destroyed before it is time, and this can very well crash the GC.
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
Popular Topics
Advertisement