Advertisement

Passing script objects as base pointers?

Started by January 17, 2009 03:09 AM
20 comments, last by Wavesonics 15 years, 10 months ago
Well I had a huge long post here. But in writing the post, I worked through the problem and figured it out :) I must say, I don't totally grasp the difference between REF and VALUE. Are VALUE types only valid in the scripts, and REF types actual *real* objects? Anyway. I'm creating an object in my script which is a derived type. But I want to be able to pass it to the application as it's base type. Any ideas for how to accomplish this? I figure there is no direct way since I saw inheritance is on the road map.
==============================
A Developers Blog | Dark Rock Studios - My Site
The value types are allocated on the stack and never outlive the scope in which they were created. The reference types are allocated on the heap, and live on until all references to them have been removed.

Value types are used mainly for smaller, less complex types, e.g. 3D vectors. Reference types are used for all types that need dynamic memory management.




You can register the reference cast behaviour for the derived type. This will allow the script engine to cast the type to the base type.

There is an example for this in the manual: Type behaviours (look for cast operators further down on the page)

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
That clears up a whole lot, thanks.
==============================
A Developers Blog | Dark Rock Studios - My Site
Ok, I went ahead and implemented the implicit case behavior, and it *works.

* It works in every case but this obscure one:
When trying to call to a function using the implicit case, and the function is virtual, and only implemented in the base class of the object it is actually being called on.

It still compiles and runs, but the function is just never called.
==============================
A Developers Blog | Dark Rock Studios - My Site
Can you show me the script?

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

Sure can. Also, I did some checking, and the implicit conversion function I registered is definitely firing and succeeding.

Here is the script it's self:
void fireEffects( TurretClient@ t, CreepClient@ c, WorldClient@ w ) {    if( c.health() != 0 ) {        // Create an explosion        OverlayExplosion@ o = OverlayExplosion( 1.0 );        // Add the explosion to the creep we fired on        c.addOverlay( o ); // This one doesn't ever fire off    }    else {        // Create an explosion        OverlayExplosion@ o = OverlayExplosion( 0.5 );        // Give the explosion the world coordinates where the creep died        float x = c.x();        float y = c.y();        o.position( x, y );        // Add the explosion to the world        w.addOverlay( o ); // This on works just fine    }}


Here is the offending class:
#ifndef CREEPCLIENT_H_INCLUDED#define CREEPCLIENT_H_INCLUDED#include "Creep.h"#include "Drawable.h"class CreepClient : public Creep, public Drawable {private:protected:public:    CreepClient( const class DescriptionCreep* description );    virtual ~CreepClient();};#endif // CREEPCLIENT_H_INCLUDED


And it's base class which is where the function is:
#ifndef GAMEOBJECTCLIENT_H_INCLUDED#define GAMEOBJECTCLIENT_H_INCLUDED#include <vector>#include <SFML/Graphics.hpp>class Drawable {private:    class GameObject& m_obj;    std::vector< class Overlay* > m_overlay;protected:    sf::Sprite m_sprite;public:    Drawable( GameObject& obj );    virtual ~Drawable();    virtual void addOverlay( Overlay* overlay );    sf::Int32 numOverlays();    Overlay& getOverlay( sf::Uint32 index );    bool removeOverlay( sf::Uint32 index );    virtual void setSprite( const sf::Sprite& s );    virtual sf::Sprite& getSprite();    virtual sf::Drawable& getDrawable();};#endif // GAMEOBJECTCLIENT_H_INCLUDED


And here is where I register the class:
// Here is where we register the class    // CreepClient    r = engine->RegisterObjectType("CreepClient", sizeof(CreepClient), asOBJ_REF ); assert( r >= 0 );    r = engine->RegisterObjectBehaviour("CreepClient", asBEHAVE_ADDREF, "void f()", asFUNCTION(DumbyAddRef), asCALL_CDECL_OBJFIRST); assert( r >= 0 );    r = engine->RegisterObjectBehaviour("CreepClient", asBEHAVE_RELEASE, "void f()", asFUNCTION(DumbyReleaseRef), asCALL_CDECL_OBJFIRST); assert( r >= 0 );    r = engine->RegisterObjectMethod("CreepClient", "void addOverlay( Overlay@+ overlay )", asMETHOD(CreepClient, addOverlay), asCALL_THISCALL); assert( r >= 0 );    r = engine->RegisterObjectMethod("CreepClient", "int16 health() const", asMETHODPR(CreepClient, health, (void) const, sf::Int16), asCALL_THISCALL); assert( r >= 0 );    r = engine->RegisterObjectMethod("CreepClient", "void health( int16 )", asMETHODPR(CreepClient, health, (sf::Int16), void), asCALL_THISCALL); assert( r >= 0 );    r = engine->RegisterObjectMethod("CreepClient", "float speed() const", asMETHODPR(CreepClient, speed, (void) const, float), asCALL_THISCALL); assert( r >= 0 );    r = engine->RegisterObjectMethod("CreepClient", "void speed( float )", asMETHODPR(CreepClient, speed, (float), void), asCALL_THISCALL); assert( r >= 0 );    r = engine->RegisterObjectMethod("CreepClient", "int8 reward() const", asMETHODPR(CreepClient, reward, (void) const, sf::Int8), asCALL_THISCALL); assert( r >= 0 );    r = engine->RegisterObjectMethod("CreepClient", "void reward( int8 )", asMETHODPR(CreepClient, reward, (sf::Int8), void), asCALL_THISCALL); assert( r >= 0 );    r = engine->RegisterObjectMethod("CreepClient", "float x() const", asMETHOD(CreepClient, x), asCALL_THISCALL); assert( r >= 0 );    r = engine->RegisterObjectMethod("CreepClient", "float y() const", asMETHOD(CreepClient, y), asCALL_THISCALL); assert( r >= 0 );    r = engine->RegisterObjectMethod("CreepClient", "void position( float, float )", asMETHODPR(CreepClient, position, (float, float), void), asCALL_THISCALL); assert( r >= 0 );    // Global object behavior    r = engine->RegisterGlobalBehaviour(asBEHAVE_IMPLICIT_REF_CAST, "Overlay@+ f( OverlayExplosion@+ )", asFUNCTION(castOverlayExplosionToOverlay), asCALL_CDECL); assert( r >= 0 );
==============================
A Developers Blog | Dark Rock Studios - My Site
Advertisement
How are you calling the 'fireEffects' function?

This isn't a problem with the implicit cast behaviour, because c is already a handle to a CreepClient, thus AngelScript won't cast it to anything else when calling the addOverlay method.

When you pass the pointer to the CreepClient to the context, is the pointer declared as a CreepClient or one of the Creep or Drawable classes? It's important that is a CreepClient, because the value of the pointer won't be the same if it is one of the other (due to 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

Damn, i thought thats what it was when I read it, but looking at my source, I am passing it as a CreepClient:

void ProcessFireTurretsClient::fireAction( Turret& t, Creep& c ) {    TurretClient& tc = dynamic_cast< TurretClient& >( t );    CreepClient& cc = dynamic_cast< CreepClient& >( c );    // Run the turrets "void fireEffects()" script    const DescriptionTurret* description = t.getDescription();    asIScriptContext* ctx = gScriptEngine.prepare( description->effectsScript, "void fireEffects( TurretClient@, CreepClient@, WorldClient@ )" );    ctx->SetArgObject( 0, &tc );    ctx->SetArgObject( 1, &cc );    ctx->SetArgObject( 2, &m_world );    gScriptEngine.execute( ctx );}
==============================
A Developers Blog | Dark Rock Studios - My Site
It could be a bug with how AngelScript handles virtual methods for classes with multiple inheritance. I'll have to look into this.

Could you make a quick test?

Instead of registering the addOverlay method directly, try registering the following wrapper function:

void CreepClient_addOverlay( Overlay* overlay, CreepClient *c ){  c->addOverlay(overlay);}r = engine->RegisterObjectMethod("CreepClient", "void addOverlay( Overlay@+ overlay )", asFUNCTION(CreepClient_addOverlay), asCALL_CDECL_OBJLAST); assert( r >= 0 );


If it is a problem with the way multiple inheritance is handled, the above should be a work around until I get the bug fixed. If the above doesn't work either, then the problem is another.

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

Yes, I actually made a proxy function as a member of CreepClient:

CreepClient::addOverlay( Overlay* o ) {    Drawable::addOverlay( o );}


And it works fine.
==============================
A Developers Blog | Dark Rock Studios - My Site

This topic is closed to new replies.

Advertisement