Question about inheritance

Started by
3 comments, last by WitchLord 8 years, 9 months ago

I haven't had too much experience with AngelScript, so forgive me if I'm off about something.

But anyways, to explain my question/situation I basically have a class that fundementally is something like this (of course, this is just an example):


class Behaviors
{
    public:
        void Behavior1(int v)
        {
            val *= v;
        }

        int Behavior2()
        {
            return val;
        }
    
    private:
        int val;
};

Now, the class is getting really messy (and there's behavior that it contains that I'd prefer scripted anyways) so I'm trying to get the class to work off of components instead.

So I'm effectively trying to achieve something like this:


struct IBehavior1
{
    virtual void Behavior1(int v)=0;
};

struct IBehavior2
{
    virtual int Behavior2()=0;
};

struct Behavior1Impl : IBehavior1
{
    Behavior& behavior;
    Behavior1Impl(Behavior& b) : behavior(b) { }
    void Behavior1(int v) { behavior.val *= v; }
};

struct Behavior2Impl : IBehavior1
{
    Behavior& behavior;
    Behavior2Impl(Behavior& b) : behavior(b) { }
    int Behavior2() { return behavior.val; }
};

class Behavior
{
    friend struct Behavior1;
    friend struct Behavior2;

    public:
        Behavior() { behavior1 = static_cast<Behavior1*>(new Behavior1Impl(*this)); behavior2 = static_cast<Behavior2*>(new Behavior2Imp(*this)); }
        ~Behavior() { delete behavior1; delete behavior2; }
        void Behavior1(int v) { behavior1->Behavior1(v); }
        int Behavior2() { return behavior2->Behavior2(); }

    private:
        int val;

        IBehavior1 *behavior1;
        IBehavior2 *behavior2;
};

What I want to do is replace, what is equivalent to this example's "Behavior1Impl" and "Behavior2Impl", with a scripted class, that implements the behavior of the components but is invisible to the container that it's scripted. Sorry if the example I gave is confusing.

I looked at the AngelScript documents and it has not made it clear to me what's required in order achieve something like this. Or even what I want to do is possible.

Any information regarding this would be appreciated.

Advertisement

If I understood you correctly, you want to implement a way to allow individual components to be implemented through script, but have this implemented abstracted in a way that it is transparent to the container that holds those components. Am I right?

There are many ways in which you can accomplish this, but on a high level you'd need something like this:

  • Register the interface that the script should be allowed to use to implement the behavior, e.g. application functions that can be called, properties of the component inspected and manipulated, etc.
  • Implement a behavior class deriving IBehavior1 or IBehavior2.
  • When the behavior class is instantiated it should make preparations that will be needed to respond to calls later on, for example, compile the script (if it is the first time), cache the script function pointers, instantiate the script class, etc.
  • When the behavior class is invoked by the container, the behavior class should forward the call to the corresponding script function (either a global function or member of a script class), and then return the result to the caller.

Take a look at the game sample in the SDK. While it doesn't work exactly as you want, it comes quite close. You might think of the CGameObj that is in the code as the behavior class that uses scripts to implement the actual logic of the behavior.

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

Having been trying to get it to work (thanks for the info, btw) it raised two more questions:

1. According to the docs, to create a class instance I should be able to simply call asIScriptFunction *factory = type->GetFactoryByDecl("MyClass @MyClass()"); (with MyClass being replaced with whatever script class I have) prepare and execute the function, then I can retrieve it as an asIScriptObject*. Unfortunately, it fails to find the factory function (returns NULL). My script class doesn't have any special constructors. I'm not quite sure what I'm doing wrong.

2. How do you register a C++ constructor for a value/pod type? I need a type from another library to be able to used but I'd like to use the various constructors the type has in the script.

I'm sure andreas will give a better answer but:

1. You have to create the class instance using asIScriptEngine::CreateScriptObject, you pass it a copy of asIScriptObject that you can obtain by using GetObjectType functions. Then you can prepare a method inside of the class for execution, then use SetObject in asIScriptContext before executing:


asIObjectType *objType  = module->GetObjectTypeByName("MyClass");
asIScriptFunction *func = objType->GetMethodByDecl("void foo()");

void *obj = context->CreateScriptObject(objType);
context->Prepare(func);
context->SetObject(obj);
context->Execute();

context would be a instance of asIScriptContext.

2. This is explained and has examples in the documentation, see http://angelcode.com/angelscript/sdk/docs/manual/doc_register_val_type.html#doc_reg_val_1

GetFactoryByDecl("MyClass @MyClass()"); should work even if you don't declare any constructors in your script class. The default constructor is generated automatically if is not implemented explicitly. Did you perhaps type the name of the script class incorrectly?

Since you do not have any specific constructor anyway, you can also follow dkrusu's tip and use the asIScriptEngine::CreateScriptObject(objType) to create the script class.

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