   OO design issues
  Okay, I'm having an issue with my design. I've got my enemies moving around with some basic AI but, I know my design is not optimal.What I want to do is make the the room class have a list of NPC Characters that are in the room. The problem I'm having is that when I want the NPC to do some pathfinding they need to have the room information, and if I have them as part of the room and also have the room information my compiler complains that it about circular inclusion. Should I make the room do the path finding, or make a AI Class that knows about all the characters and maps and does the pathfinding for the NPCs?I'm just not sure how I should organise the classes. Right now the room and the characters are separate and I just pass them to each other in parameters when needed. But this gets messy when I'm sending map, players, items, containers, etc.   
  You could give each enemy a pointer to its current room, and each room a bunch of pointers to the enemies it holds.   ;  Which language are you using? If c++ then you need to separate class definition (.h) to implementation (.cpp). Suppose you have two header files: the first one defines the Character class, and the second the Room class. You can't include Room.h in Character.h and Character.h in Room.h. What you can do is to include Character.h in Room.h, and in the beginning of Character.h write:class Room;then you can declare pointers to instances of Room. You can access to the members only in the cpp files though (if you include Room.h). That because the compiler does not know what Room is without the header included, but it knows the size of a pointer to Room objects.   ;Quote:Original post by Turt99my compiler complains that it about circular inclusion.Presumably this is C++ then: Proper use of forward declarations and header/source file separation tend to fix this in most cases; when that fails various idioms, e.g. pimpl, can solve it entirely. Whilst you can get the code to compile, this doesn't solve is the fundamental design problem...Quote:make a AI Class that knows about all the characters and maps and does the pathfinding for the NPCs?Do that. Don't call the class AI though, that's a terribly generic name, call it PathFinder or something. Basically the world (or "room") collects the entities then, for any entity that needs to do some pathfinding on the world, the world can setup a PathFinder passing it any relevant data about the world/room to its constructor and finally passing that object to the entity (perhaps through the entity's constructor or update method/member-function).Depending on how you design this, each pathfinding entity might want to keep its own unique PathFinder instance, keep reference to a shared instance or just make temporary use of an instance given to them in update. They may be pros and cons to each solution, you'll need to decide which is the most appropriate.   ;  Is it acceptable to use pre-compiler conditionals to avoid double inclusion?in Room_Class.h:#if !defined ROOM_CLASS #define ROOM_CLASS#include "NPC_Class.h"class RoomClass{....}#endifin NPC_Class.h#if !defined NPC_CLASS#define NPC_CLASS#include "Room_Class.h"class NPC_Class{...}#endifOr is this indicative of sloppy design?-Kirk   ;  Yes this is C++, and I believe I tried the trick above with only declaring the class when needed (cignox), but I might have done something wrong when trying that, it could be something to look into.dmatter, I think you might have the solution, creating a pathfinding object to give the NPC's sounds like it might be the best way, it might also mean the least amount of recoding instead of taking in the parameters just use the pathfinder object it already has.   ;Quote:Original post by kirkdIs it acceptable to use pre-compiler conditionals to avoid double inclusion?Yes inclusion guards are perfectly acceptable (and recommended) for solving double inclusion, but the OP's problem - and your example - are that of recursive ("cyclic" or "two-way") inclusion which they do not solve.   ;  dmatter - Interesting.  I had to stop and think about it for a moment but now I see the recursive inclusion problem.  Does this, then, solve that problem adequately?<<room_class.h>>#define ROOM_CLASS#if !defined NPC_CLASS#include "NPC_Class.h"#endifclass RoomClass{....}<<NPC_Class.h>>#define NPC_CLASS#if !defined ROOM_CLASS#include "Room_Class.h"#endifclass NPC_Class{...}EDIT:  I'm guessing that yes, this solves the problem - in this case.  A more complex case may require a combination of include guards and forward declaration.  Is it possible, through proper design, to avoid recursive inclusion from ever becoming an issue, or is it impossible to avoid 100% of the time?[Edited by - kirkd on August 28, 2009 11:14:45 AM];  Well you should never have recurrisve includes (inclusion guards prevent that).Whats with everyones hideous #def guards, why not just#pragma once?Quote:#if !defined NPC_CLASS#include "NPC_Class.h"#endifYou should never have that, if you just include it then the file itself will have those checks in anyway, just including it is enough. Expanding that and you get:#if !defined NPC_CLASS#if !defined NPC_CLASSclass npc{};#endif#endifTheres nothing wrong with cyclic classes but if you have cyclics just make sure you break the cycle of dependancy as far as the headers go (by making all uses of one class int he others header file into a pointer ro a reference).// class1.h#pragma onceclass class2; // forward declarationclass1 {public:class2 *test;};// class2.h#pragma onceclass class1; // forward declarationclass2 {public:class1 *test;};as long as class1.cpp and class2.cpp include both headers they will work just fine. Works the same for using references too.When ever I code anyhting now, unless I have a concrete cass in my header (as opposed to a pointer or reference) I will not include the header for it but instead just declare that the class exists.Its not always possibly but it keeps everything neat and tidy and if you have a very large project can keep build times down (if a includes b includes c includes d etc, changing the bottom causes them all to need rebuilding).   ;Quote:Whats with everyones hideous #def guards, why not just#pragma once?That's not standard C++, that's why.   