Polymorphism in Angelscript
SummaryNatively, Angelscript does not support inheritance. This article shows a method that can be used with Angelscript that allows virtual function overrides to be written in Angelscript, effectively allowing you to create derived classes in script. It is assumed the reader is familiar with the basics of Angelscript, and can register objects and functions with the Angelscript engine. This article was written for Angelscript v1.7. Proper support for objects is planned for later versions, so with any luck this article will one day become obsolete. As good a place as anyIn our game we have a player that can collide with items. Each item will affect the player in a different way. For simplicity, our player class will only have one variable: health. We could conceivably use the following classes: // C++ class CPlayer { public: float health; }; class CItem { public: virtual void collidePlayer(CPlayer *p); }; In C++ it would be trivial to derive classes from CItem for each item type. But say we wanted the item behaviours to be defined in script. We are unable to use derived classes, so we must find another method. Let's work backwards and start with what we would like the script to look like: // Angelscript bool item_init() { registerItemType("health"); return true; } void health_collidePlayer(CPlayer *p) { p->health += 15; } That looks peachy. Obviously, we will need a static variable to hold the item types, and a member variable to hold the type of the item. The collidePlayer function will look at the itemType and call the appropriate function in script. Note that it is not actually necessary to register the item types, but this allows us to implement some sort of error checking (ie. Forbid creation of non-existent item types). // C++ class CItem { public: static void registerItem(const char *itemName); static string itemTypes; string type; virtual void collidePlayer(CPlayer *p); } void CItem::registerItem(const char *itemName) { CItem::itemNames.push_back(itemName); } void CItem::collidePlayer(CPlayer *p) { string func; list<asDWORD *> args; CItem *thisPtr; thisPtr = this; func = itemType + "_collidePlayer"; // Function to call args.push_back((asDWORD *)&thisPtr); args.push_back((asDWORD *)&p); eng.callScript(func, &args); } CItem::registerItem("health"); // Or we could just call the item_init() function in script a = new CItem("health"); // See example code for this constructor p = new CPlayer; p->health = 100; a->collidePlayer(p); // p->health will now be 115 Members Eat FreeThat's all well and great, but Bob the stingy level designer desires to add health items that only give 5 health. He could create a new item type, but Bob also happens to be lazy. If the health item could have a member variable "amount", Bob could create as many different health types as pleased him without ever having to create an item type of his own. For this we are going to use an STL map. In the item type constructor, it will "register" its member variables, similar to how Javascript objects work. For simplicity, we will just allow variables of type "float". // Angelscript // Called from the CItem constructor void health(CItem *this) { this->registerFloat("health"); } void health_collidePlayer(CItem *this, CPlayer *p) { p->health += this->getFloat("health"); } // C++ class CItem { public: /* as before */ map<string, float> vars; // See sample code for implementations of the following functions void registerFloat(const char *varname); // Adds key to vars void setFloat(const char *varname, float value); float getFloat(const char *varname); } CItem::registerItem("health"); // Or we could just call the item_init() function in script a = new CItem("health"); // See example code for this constructor p = new CPlayer; a->setFloat("health", 10); p->health = 100; a->collidePlayer(a, p); // p->health will now be 110 Note that now we are using object specific variables, we must now pass a "this" pointer to our functions so that we can access member functions. Stepping Stones
Have a look at the sample code for additional insights. A MSVC 6.0 project file is included, but it should be portable. You will require the angelscript library. Xavier Shay
Discuss this article in the forums
See Also: © 1999-2011 Gamedev.net. All rights reserved. Terms of Use Privacy Policy
|