Sign in to follow this  
kaveldun

Registering script entities

Recommended Posts

kaveldun    142

Hello!

 

I am new to Angelscript and I would like some clarifications.

 

What I am trying to do.

I am making a game where all the specific entity logic should be implemented script side using Angelscript. On the application side, there will only be a general entity type, but on the script side there will be different types of entities with each having specific behaviours. For instance, you could create these two files:

 

//cow.as

class Cow : Entity

{

    onFrame()

    {

          //cow log

    }

}

 

//duck.as

class Duck : Entity

{

    onFrame()

    {

         //duck logic

    }

}

 

All the application would do is to call onFrame on a general entity type, which would call corresponding onFrame function. 

It should also be possible to create entities from the script, like so:

Entity newCow = createEntity("Cow");

 

Me trying to solve this:

 

The application will be responsible for creating and entities since it has to do a lot with them application side too, like physics and such. So I figured I need to register a factory function which returns an Entity@ as explained in the manual and various demos. A lot of these resources seem to refer to a "f()" function which I don't understand. I thought it was just an example function, but looking around in the forum and at samples, it seems like the f() function is actually something which shows up now and then. This line is from the game sample:

r = engine->RegisterObjectBehaviour("CGameObj", asBEHAVE_ADDREF, "void f()", asMETHOD(CGameObj, AddRef), asCALL_THISCALL); assert( r >= 0 );

and it has that "f()" function that I jut can't figure out and I haven't seen an explanation in the manual. Do you guys mind demystifying this function for me?

 

Furthermore, I'm not entirely sure on how the application <-> script communications work. If I have a factory function Entity@ createEntity("cow") which is registered as a factory function handled by the application side, then as far as I've understood, I need to have the Entity type known by both the script and the application, is that correct?

And in that case, if I register an Entity type from the application, I cannot inherit that type in angelscript, since it doesn't support inheritance of registered classes afaik. In that sense my idea was to have on the application side, an EntityCore type which I register to the script, and then on the script end, I have a class Entity which internally is composed of an EntityCore and is then derived from. Is that a reasonable way to achieve what I want?

 

I also tried to implement this but there are many details I get stuck on, like since I am registering a reference type, I need to register reference counting functions. So I read about this in the manual, and look at other examples, and they show them as the example line I posted up there with the "f()" function. Does this mean that I don't need to implement any reference counting functions script side? Or what does it mean really?

 

I am sorry if my questions are rather lengthy and non straight forward to answer, but I feel like I'm entangled into confusion myself and even reading the manual doesn't straighten everything out so yeah. Any help or suggestions or examples to clear this up would be appreciated. :)

 

Thanks. (:

Share this post


Link to post
Share on other sites
WitchLord    4677
r = engine->RegisterObjectBehaviour("CGameObj", asBEHAVE_ADDREF, "void f()", ...);

The use of f() here is just to make the function declaration valid. The behaviours are never called by name, so it doesn't matter what name you give it in the declaration, as long as it is a valid identifier so the parser won't complain. smile.png

 

You're correct that script classes cannot inherit from application classes. This is why the Entity type should be registered as a script interface with

r = engine->RegisterInterface("Entity");

This is equivalent to declaring the type in the script as 'shared interface Entity {}', the only difference is that now it will be known by the script engine so you can refer to the type when registering further functions, i.e. "Entity @createEntity(const string &in)".

 

If you don't like the idea of registering an interface like this, you can also use the generic handle add-on and register the createEntity to return that instead of the Entity type, e.g. "ref @createEntity(const string &in)".

 

 

Your suggestion with EntityCore in C++ and Entity in AngelScript is one way to get around the inheritance dilemma (though I'm not sure why you need to have the script classes inherit from the C++ classes in the first place). The Entity type should then be declared as shared, so that all of your modules will see the exact same type rather than multiple types with teh same name.

 

 

 

 

The reference counting happens behind-the-scenes in the scripts, so the script writer never sees the calls to AddRef and Release, nor does he have to implement reference counting for the script classes as these are provided automatically.

 

 

The samples in the AngelScript SDK are a good start to learn. In your case, specifically the game sample should be of interest. It is a very simplified sample of a game engine, but it shows how you can implement the engine to allow each entity type to be controlled from different scripts.

 

If you want a more complete sample, you can have a look at my prototype game engine.

 

 

Regards,

Andreas

Share this post


Link to post
Share on other sites
kaveldun    142

Thanks so much for the quick reply!

 

Your clarifications made it make sense at last. :) I have now gotten the basics for it up and running. Ended up using an interface Entity as you suggested!

 

Perhaps the thingy about the "f()" function in the documentation could be clarified? Unless it is there and I just missed it of course. For me it was quite confusing indeed.

Share this post


Link to post
Share on other sites
kaveldun    142

Hmmmm, I have an additional question.

 

I have now registered the Entity interface and entities can inherit from it. I also added two global functions for removing and creating entities and this all works on both application side and the script side. What I also need however is calling member functions that are common for all Entity classes. Like, if i have:

 

class Cow : Entity

{}

 

class Dino : Entity

{}

 

Then I need to be able to do:

 

Entity@ dino = createEntity("Dino");

Entity@ cow = createEntity("Cow");

 

dino.setPosition(0.0f, 1.0f, 10.0f);

cow.setPosition(0.0f, 2.0f, 12.0f);

 

Without explicitly define these. And I need to handle the position setting on the application side, would work if I on the application could receive an asIScriptObject* to the caller, into a global function. Is it possible to register a member function for an interface which triggers a general function in the application, giving an object handle to it? Or am I thinking about this in the wrong way?

 

Thanks again. :)

Share this post


Link to post
Share on other sites
WitchLord    4677

You can only call methods on the Entity that are declared in the class (or inherited from a base class). 

 

If you wish to force the script class to implement the setPosition method then you can register the interface method with RegisterInterfaceMethod. 

 

 

I assume you have a C++ class representing the entity in the game engine. Why are you trying hide this? Why not register the C++ class too and allow the script class to manipulate it directly rather than trying to make it appear as if the script class is the only object?

Share this post


Link to post
Share on other sites
kaveldun    142

Well, I don't want the script to be forced to implement the setPosition function. I want the setPosition function correspond to a function on the application side, and it should be available on every entity type inheriting from Entity. So if I have:

 

Entity : Cow {}

Entity : Whale {}

 

By Cow and Whale inheriting from Entity, I can now call .setPosition on them which will be handled in the application. But perhaps it is in't possible with an interface.

 

Because as you said, I can register my application side entity class as Entity, and have it have a setPosition function, but then since you can't inherit from an application side registered class, I need to solve it in some other way. Perhaps I do need to use the method of making an EntityCore class which is registered and then have it in Entity after all?

 

Thanks again.

Share this post


Link to post
Share on other sites
WitchLord    4677

Yes, it sounds like you'll need the design pattern of the EntityCore class.

 

I suggest the following: The application registers the interface IEntity so that it can register further functions with this. A shared base class Entity that implements the IEntity interface is provided for the customizable script classes to inherit from. The Entity class provides the default implementation of common methods, such as setPosition.

 

As the Entity class is shared, it will reuse the same internal type and bytecode even though it is included in the script for all modules.

 

Your hierarchy will then look like this:

 

interface IEntity {} // Registered by the application

shared class Entity : IEntity { EntityCore @m_core; void setPosition(int x, int y) { m_core.setPosition(x,y); } // Included from a common script file

class Cow : Entity {} // Custom script for the Cow entity type

 

 

Regards,

Andreas

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this