Brainstorming: refactoring classes/inheritances

Brainstorming: refactoring classes/inheritances

Postby StefanP.MUC » 14 Sep 2011, 18:43

Today I had some time to scroll and think through some of our class definitions and inheritances. Here is my thought of some cleaning things up and make them more logical. Currently we have a lot of stuff implemented several times unneccessarily (like a lot of getters and setter for always the same members, like name, hp, color, ...) And the more the code grows the harder it will be to clean this up.

{l Code}: {l Select All Code}
         Object (holding all global commons, like name, meshName, ...)
              /   \
              |    ---> inherit all objects not directly on the map (Weapon, RoomObject, ...)
              |
         MapObject (holding all interactable map object commons like hp, color, ...)
              |
  ----------------------------------------
  |(virtual)          |(virtual)         |(virtual)
AttackableObject    AnimatedObject     ActiveObject

//must-have methods like doUpkeep() from ActiveObject will be pure virtual
//From these three the actual instantiable classes are inherited
//virtual inheritance from MapObject prevents constructor conflitcs
- Creature (merged with CreatureClass), Trap, Room, ... (whatever game objects there will be)

Some questions to think about: Do you think this structure is good? Where are possible flaws? What could be improved with this structure? Can you think of completly different structures that are better than this? Is anything missing? Should some of the classes be split up or merged? ...
StefanP.MUC
 

Re: Brainstorming: refactoring classes/inheritances

Postby oln » 14 Sep 2011, 19:07

I have had the same idea, and thought of something similar to what you have proposed here.
CreatureClass definetly needs to be changed. I think we could still keep the class, but more as an object that a creature object is constructed from.
Not sure if all data should be kept in creature, and creatureclass would just contain a "description" of the base stats a creature should have, or if the creature class should have a creatureclass object. At least it should not be an inherited object as it is now, which is not very logical, and also leads to duplicated data.

Animatedobject as it is now, actually means "object that can move around the map", not just an object that has an animation. So we might want to change the name of this class.

AttackableObject, AnimatedObject, ActiveObject don't have to inherit from MapObject, as they are not accessing anything that would be in the MapObject class.

I think we should use something else that "Object", for the base object name, but I am not sure what. Maybe GameEntity or something.

Also, I think we should consider grouping the source files into folders, like "graphics", "ai", "util".
User avatar
oln
 
Posts: 1020
Joined: 26 Oct 2010, 22:16
Location: Norway

Re: Brainstorming: refactoring classes/inheritances

Postby StefanP.MUC » 15 Sep 2011, 16:26

Yes, sounds good. I also just realized that for example MissileObject is also an AnimatedObject (but it's not directly on the map). What about this:

{l Code}: {l Select All Code}
       GameEntity (holding all global commons, like name, meshName, ...)
              /   \
              |    \ --- inherit all "simple" objects (Weapon, RoomObject, ...)
              |
  ----------------------------------------
  |(virtual)          |(virtual)         |(virtual)
AttackableObject    MovableObject     ActiveObject

//All other classes can now be subclasses dirctly of GameEntity or
//(if they don't simply "exist", but need common properties) indirectly
//by being combinations of AttackableObject, MovableObject and ActiveObject


Sorry for the slow understanding, but I still don't get the need for the CreatureClass. A Creature is a Creature and should hold all its properties. Why should some properties be laid out in another class (no matter if it's inherited, instanciated or whatever)? People don't walk around carrying a box with some of their properties (hair color, length of toenail, ...) in it. :D

About the subfolder, I think I agree. When merging src/ and include/ I still was in doubt that it is useful, but after working some weeks with it, I agree that some rough categorisation is really useful.

{l Code}: {l Select All Code}
ai/
goal/
trap/
graphics/
network/
util/
base/
[any more?]
main.cpp
StefanP.MUC
 

Re: Brainstorming: refactoring classes/inheritances

Postby svenskmand » 15 Sep 2011, 17:01

StefanP.MUC {l Wrote}:Sorry for the slow understanding, but I still don't get the need for the CreatureClass. A Creature is a Creature and should hold all its properties. Why should some properties be laid out in another class (no matter if it's inherited, instanciated or whatever)? People don't walk around carrying a box with some of their properties (hair color, length of toenail, ...) in it. :D

Well actually People extends HomoSapiens which define their appearance :P but lets forget bad analogies and look at the practicalities. Having a CreatureClass will remove allot of duplicate code, so I think that is a good argument for having it. What arguments are there not to have a CreatureClass?
Jamendo.com - The best music store on the net, uses CC licenses.
User avatar
svenskmand
OD Moderator
 
Posts: 1850
Joined: 09 Dec 2009, 00:07
Location: Denmark

Re: Brainstorming: refactoring classes/inheritances

Postby StefanP.MUC » 15 Sep 2011, 18:45

CreatureClass inherits from AnimatedObject. And Creature inherits from CreatureClass (implicit AnimatedObject) and AttackableObject.
How is merging CreatureClass into Creature and making Creature directly inheriting from AttackableObject and Animated Object creating code duplication?

Or did I missunderstand something about this CreatureClass? Maybe this is just another naming problem (like with AnimatedObject, which does not make clear that it is actually even a MovableObject). Is CreatureClass a class for stuff that defines "Human", "Undead" and "Constructs"? If so, then I'm wonder why it has properties like meshName, sightRadius, creatureJob which are clearly properties of an individual Creature.
StefanP.MUC
 

Re: Brainstorming: refactoring classes/inheritances

Postby svenskmand » 15 Sep 2011, 19:46

From what I understood from oln's post and your reply to him, he wants to store basic creature stats e.g. health, mana, movespeeds, a container for attacks/spells and other stuff in the CreatureClass. And I think that is a good idea as they are common to all creatures. The name of the mesh and other stuff could also be included here.

StefanP.MUC {l Wrote}:Is CreatureClass a class for stuff that defines "Human", "Undead" and "Constructs"? If so, then I'm wonder why it has properties like meshName, sightRadius, creatureJob which are clearly properties of an individual Creature.

I have trouble following you here, why could meshName, sightRadius and creatureJob not be properties of CreatureClass (which all creatures inherits from)? It is a class not an instance/object, each instance/object get their own value here.
Jamendo.com - The best music store on the net, uses CC licenses.
User avatar
svenskmand
OD Moderator
 
Posts: 1850
Joined: 09 Dec 2009, 00:07
Location: Denmark

Re: Brainstorming: refactoring classes/inheritances

Postby oln » 15 Sep 2011, 20:29

svenskmand {l Wrote}:From what I understood from oln's post and your reply to him, he wants to store basic creature stats e.g. health, mana, movespeeds, a container for attacks/spells and other stuff in the CreatureClass. And I think that is a good idea as they are common to all creatures. The name of the mesh and other stuff could also be included here.

StefanP.MUC {l Wrote}:Is CreatureClass a class for stuff that defines "Human", "Undead" and "Constructs"? If so, then I'm wonder why it has properties like meshName, sightRadius, creatureJob which are clearly properties of an individual Creature.

I have trouble following you here, why could meshName, sightRadius and creatureJob not be properties of CreatureClass (which all creatures inherits from)? It is a class not an instance/object, each instance/object get their own value here.


That's not quite what I meant.
I think creatureclass should store information about the creature class( as in in-game class), such as stat increases per level, mesh filename, job, name of the class, sound filenames etc. I.e things that are static for the type of creature, basically what is stored in the creature class definition file. Which means this will really be a pure data object. Storing this information for each creature instance is redundant. (Unless one want's to be able to alter this for each individual instance.)
Then each creature would store a reference to the creature type object (which will be in a list somewhere) which describes the type of creature it is.
Values that are meant to change after the creature is created is stored in the creature object itself.

Currently it looks like this:
{l Code}: {l Select All Code}
class CreatureClass: public AnimatedObject
{
    public:
        enum CreatureJob
        {
            nullCreatureJob = 0,
            basicWorker = 1,
            advancedWorker,
            scout,
            weakFighter,
            weakSpellcaster,
            weakBuilder,
            strongFighter,
            strongSpellcaster,
            strongBuilder,
            guard,
            specialCreature,
            summon,
            superCreature
        };

        // Constructors and operators
        CreatureClass();

        static CreatureJob creatureJobFromString(std::string s);
        static std::string creatureJobToString(CreatureJob c);

        bool isWorker() const{return (creatureJob == basicWorker || creatureJob == advancedWorker);}
        std::string getOgreNamePrefix();

        // Class properties
        //NOTE: Anything added to this class must be included in the '=' operator for the Creature class.
        CreatureJob creatureJob;
        std::string className;
        std::string meshName;
        std::string bedMeshName;
        int bedDim1, bedDim2;
        Ogre::Vector3 scale;
        double sightRadius; // The inner radius where the creature sees everything
        double digRate; // Fullness removed per turn of digging
        double danceRate; // How much the danced upon tile's color changes per turn of dancing
        double hpPerLevel;
        double manaPerLevel;
        double maxHP, maxMana;

        // Probability coefficients to determine how likely a creature is to come through the portal.
        double coefficientHumans;
        double coefficientCorpars;
        double coefficientUndead;
        double coefficientConstructs;
        double coefficientDenizens;
        double coefficientAltruism;
        double coefficientOrder;
        double coefficientPeace;

        //std::vector<std::string> soundNames;
        static std::string getFormat();

        const std::string& getName() const
        {
            return name;
        }
        std::string name;

        friend std::ostream& operator<<(std::ostream& os, CreatureClass *c);

        friend std::istream& operator>>(std::istream& is, CreatureClass *c);
};

Besides needing some cleanup, I think the only variable here that will be changed after creature creating is scale, so it should be moved to Creature, also a bunch of variables have to be added. It should no longer inherit from animated object, as that part is taken care of in the creature class.
(Also, since we are going to change it to load from XML, this will require some changes as well.)
User avatar
oln
 
Posts: 1020
Joined: 26 Oct 2010, 22:16
Location: Norway

Re: Brainstorming: refactoring classes/inheritances

Postby StefanP.MUC » 15 Sep 2011, 20:46

Ah, now this clears the things up about purpose and intention of this class. :) Yes, now I fully agree on oln's idea here.

We will basically have a list of CreatureClasses (HumanWorker, HumanFighter, Horny, UndeadWorker, UndeadFighter, ...) that are read in from file and after that are readonly and each individal Creature is one of them (stored in a private field of type CreatureClass*).

But I still have the feeling that a name change to this class will make it even more clear. Ideas: CreatureDefinition, CreatureType, CreatureFamily.
StefanP.MUC
 

Re: Brainstorming: refactoring classes/inheritances

Postby svenskmand » 16 Sep 2011, 09:16

Ahh ok, sounds like a good idea. And yes then we should rename it to CreatureDefinition as Stefan suggested.

But then there is no need to program this class ourself as it should just be the root node of the DOM tree for the xml documents we load. So in other words this class is autogenerated by xeceres.
Jamendo.com - The best music store on the net, uses CC licenses.
User avatar
svenskmand
OD Moderator
 
Posts: 1850
Joined: 09 Dec 2009, 00:07
Location: Denmark

Re: Brainstorming: refactoring classes/inheritances

Postby StefanP.MUC » 16 Sep 2011, 17:25

I just pushed a first draft of the GameEntity.h file. It is still unused. But I think this is the way this absolute base class should take.

Any futher comments on this file and the second design I posted? Or any different approaches?

I think this task should have a rather high priority. I don't want to register everything now to AngelScript if it is likely to be changed soon after (this can be annyoing). And it will also attract new devs more easier if we have a clear class structure that doesn't need years of learning. ;)
StefanP.MUC
 

Re: Brainstorming: refactoring classes/inheritances

Postby oln » 16 Sep 2011, 17:51

StefanP.MUC {l Wrote}:I think this task should have a rather high priority. I don't want to register everything now to AngelScript if it is likely to be changed soon after (this can be annyoing). And it will also attract new devs more easier if we have a clear class structure that doesn't need years of learning. ;)

+1

Will have a look.
User avatar
oln
 
Posts: 1020
Joined: 26 Oct 2010, 22:16
Location: Norway

Re: Brainstorming: refactoring classes/inheritances

Postby oln » 16 Sep 2011, 18:14

It seems we need some changes to the render request as well when changing to this approach (ideally it should be simplified to a "createEntity" request rather, there is a lot of duplicate code in renderManager). Though, we could the structure change first and use switch statements on oject type (which we have to define) in the mesh creation functions untill the render part is sorted, making the two changes independent.

Your draft looks good, though I think you need createMesh, deleteMesh.
EDIT: Deleteyourself was there already.
User avatar
oln
 
Posts: 1020
Joined: 26 Oct 2010, 22:16
Location: Norway

Re: Brainstorming: refactoring classes/inheritances

Postby StefanP.MUC » 16 Sep 2011, 19:15

I just added create/deleteMesh.

Should we have protected member variables? Or should all variables be private so that derived classes are forced to use the getters and setters? I vote for private.

What other variables/function are common to each object?

This is more an idea for a feature:
Should we also introduce a "std::string nickname" variable to GameEntity? Currently the names are just numbered "Creature1", "Creature2", ... This way the player could give some of his objects (Creature, Room, Trap, ...) nicknames. If nickname is empty than the unique id name is displayed.
StefanP.MUC
 

Re: Brainstorming: refactoring classes/inheritances

Postby oln » 16 Sep 2011, 19:50

I agree with private.
Ideally as much as possible of the mesh-related code should be in gameEntity, the derived objects shouldn't be concerned with that. (Though the creature needs to for the pick up/drop function.)
Though having the mesh functions pure virtual untill we have done the fixes to renderManager is fine. (And someone can look at that after this is finished.)

I guess being able to give creatures nicks could be interesting, maybe it could also be used for "special characters" some time in the future. (Though it's not something that we should spend a lot of time implementing at this stage.)
User avatar
oln
 
Posts: 1020
Joined: 26 Oct 2010, 22:16
Location: Norway

Re: Brainstorming: refactoring classes/inheritances

Postby StefanP.MUC » 17 Sep 2011, 11:06

Yes, with the new class structure the nicknames can be added very easily later on.

About the naming:
1) Do we all agree that CreatureClass gets renamed to CreatureDefinition?

2) Currently we have AnimatedObject, AttackableObject and ActiveObject. Should we rename them to "Movable", "Attackable" and "Active" (without the "Object")? Alternative: "MovableEntity", "AttackableEntity" and "ActiveEntity" (replace Object with entity to be conform with the base class).

3) Do we all agree on renamimg "AnimatedWhatever" to "MovableWhatever"?

after this is decided I'll try to make the three classes children of GameEntity if there's no other things to be decided and done beforehand.
StefanP.MUC
 

Re: Brainstorming: refactoring classes/inheritances

Postby oln » 17 Sep 2011, 11:10

I agree with all of the points. I think we should use the entity post-fix on movable/attackable/active.
User avatar
oln
 
Posts: 1020
Joined: 26 Oct 2010, 22:16
Location: Norway

Re: Brainstorming: refactoring classes/inheritances

Postby svenskmand » 17 Sep 2011, 11:34

Sounds good.
Jamendo.com - The best music store on the net, uses CC licenses.
User avatar
svenskmand
OD Moderator
 
Posts: 1850
Joined: 09 Dec 2009, 00:07
Location: Denmark

Re: Brainstorming: refactoring classes/inheritances

Postby StefanP.MUC » 17 Sep 2011, 11:46

OK, renames are pushed. Thanks to Eclipse's refactoring utility. :D
StefanP.MUC
 

Re: Brainstorming: refactoring classes/inheritances

Postby StefanP.MUC » 17 Sep 2011, 12:48

Just pushed a commit that made Weapon a child of GameEntity, for testing it. Works perfectly fine.
StefanP.MUC
 

Re: Brainstorming: refactoring classes/inheritances

Postby StefanP.MUC » 17 Sep 2011, 14:18

Should ActiveEntity, MovableEntity and AttackableEntity be derived from GameEntity or should they exist paralelly?

Do we want this (implicit GameEntity through Attackable and Movable)?
Creature : AttackableEntity, MovableEntity

or that (explicit GameEntity)?
Creature : GameEntity, AttackableEntity, MovableEntity

I'm currently trying around with these three being derived from GameEntity and it's a real mess (basically everything breaks compiling an fixing would be a matter of reviewing almost the complete code base).

Also I often read that a diamond inheritance is considered bad in most cases and should only be used when not possible in a better way. So after testing and reading about such sitautions I'd vote for case two (parallel existance where AttackableEntity and so on do not derive from GameEntity).
StefanP.MUC
 

Re: Brainstorming: refactoring classes/inheritances

Postby oln » 17 Sep 2011, 14:58

I think it's best to have AttackableEntity and activeEntity not derive from gameEntity then, neither needs to access anything from gameEntity.
MovableEntity uses the entity name and this pointer several places, so it's easiest to have it inherit from GameEntity. (Maybe rename it to MovableGameEntity to make it more clear if we go with that approach.) If only movableEntity inherits, then there is no diamond inheritance.
User avatar
oln
 
Posts: 1020
Joined: 26 Oct 2010, 22:16
Location: Norway

Re: Brainstorming: refactoring classes/inheritances

Postby StefanP.MUC » 17 Sep 2011, 15:18

Yes, that sounds like the best plan. I'll try and see how this works.
StefanP.MUC
 

Re: Brainstorming: refactoring classes/inheritances

Postby StefanP.MUC » 17 Sep 2011, 18:24

On my local working copy I now have made Creature directly inherit from MovableGameEntity and removed derivation from CreatureDefinition and made CreatureDefinition a base class and fixed all syntax and reference errors so that the game compiles (however, there are two or three places where I had to write small hacks). However, the game crashes while reading in the level file - most likely this is because the = and >> operators depended on deriving Creature from CreatureClass.
I'm not sure if I'll be able to fix this alone.

Should I commit and push it anyways?

edit: I think I fixed the creature bug, but I now get an Assert from Ogre about the RoomObjects... (which is strange because I didn't change anything with RoomObjects...)
StefanP.MUC
 

Re: Brainstorming: refactoring classes/inheritances

Postby oln » 17 Sep 2011, 19:13

Maybe you could make a new branch? Otherwise just push.
Then I can look at it as well.
User avatar
oln
 
Posts: 1020
Joined: 26 Oct 2010, 22:16
Location: Norway

Re: Brainstorming: refactoring classes/inheritances

Postby StefanP.MUC » 17 Sep 2011, 19:16

Since I seem to have fixed the Creature bug, I'll push it now. The other bug seems to be related to some graphics loading.

If it's to hard to fix now we can revert the commit and then create a new branch.
StefanP.MUC
 

Who is online

Users browsing this forum: No registered users and 0 guests

cron