Sign in to follow this  
KnTenshi

How would I structure these classes to work in the way I would like them to?

Recommended Posts

I want to make a group of classes that can interact with a main 'parent' class, but I am not sure how to get this to work. Here's a rough brainstorm of what I would like for these to do:
class Civ()
{
	vector villageList;
	vector wanderersList;

	class village();
	class wanderers();

	//holds overarching data
}

class village()
{
	//can read variables from parent class Civ()
	//can read variables from Resources()
	//can create a wanderers() and modify wanderersList
	//when destroyed, can modify villageList in Civ()
}

class wanderers()
{
	//can read variables from parent class Civ()
	//can read variables from Resources()
	//can create a villages() and modify villageList
	//when destroyed, can modify wanderersList in Civ()
}

class Resources()
{
	//reads variables from other, unmentioned, classes
}
Does any of this make sense? Is any of this possible? Should I use Extended Classes rather than nested ones? (Oh, and I decided to put this here rather than the Game Programming section because this deals with code structure.)

Share this post


Link to post
Share on other sites
Nested classes are useful to hide private implementation details (see the PIMPL idiom), but for other uses they only serve to confuse.

Circular dependencies are also good to avoid, wherever possible. If Civilization contains a list of Villages and Wanderers, Village and Wanderer shouldn't need to have knowledge of Civilization. In particular, neither Village nor Wanderer should modify variables of Civilization - instead try to handle updates in a top-down fashion.

Share this post


Link to post
Share on other sites
Ok, so would you suggest I implement this? Here's how I envision the communication of the classes/entities:

Civ() functions as an overseer, mostly for holding a list of village() and wanderer() to be ran and updated during runtime, as well as be a centralized holding place for variables that will affect village() and wanderer().

I want each instance of wanderer() and village() to be able to remove itself from it's respective list in Civ() when the instance has been destroyed rather than have Civ() do a check to see if each instance is still there. I'd also like for village() and wanderer() to be able to create one another during runtime and update that list in Civ() rather than having them send a call to Civ() and have Civ() constantly waiting to receive a message.

And how would I get all of these to talk to unrelated classes, such as Resources()?

Share this post


Link to post
Share on other sites
I would probably re-organise the code so that each class maintains its own vector list:


class Village
{

private:

static std::vector<Village*> INSTANCES;

public:

Village()
{
INSTANCES.push_back(this);
}

~Village()
{
INSTANCES.remove(this);
}

static const std::vector<Village*>& GetVillages()
{
return INSTANCES;
}
};

class Civ
{
void DoSomething()
{
const std::vector<Village*>& villages = Village::GetVillages();

std::vector<Village*>::iterator itr;

for(itr = villages.begin; itr != villages.end(); ++itr)
{
(*itr)->
}
}
};

Share this post


Link to post
Share on other sites
Huh! That does solve one of my problems. But how would I have each new village() and wanderer() update a list exclusive to a certain Civ()?

Also, how would I call information from other classes that will be formed independently at the beginning of program? For example: Wanderer() reading a variable from Resources() or Terrain()?

Share this post


Link to post
Share on other sites

class Village
{

}

class Wanderer
{
void Explore( void )
{
m_Location += ChooseRandomDirection();
m_fRenderHeight = World::GetHeightAt(m_Location);

if (AtIdealVillageLocation())
{
World::CreateVillage(m_nCivIndex);
}
}

Location m_Location;
float m_fRenderHeight;

int m_nCivIndex;
}

class Terrain
{
GetHeightAt(Location location);


}

class Civ
{
bool CreateVillage(Location location);
{
if (m_nGold > VILLAGE_GOLD_COST && m_nIron > VILLAGE_IRON_COST)
{
//Some kind of location validation maybe
m_nGold -= VILLAGE_GOLD_COST;
m_nIron -= VILLAGE_IRON_COST;

Village *pVillage = new Village(location);
m_pVillages.push_back(pVillage);

return true;
}

return false;
}


std::vector<Village*> m_pVillages;

int m_nGold;
int m_nIron;
}

class World
{
static bool CreateVillage(int nCivIndex, Location location)
{
bool s_pCivs[nCivIndex]->CreateVillage(location);
}

static float GetHeightAt(Location location)
{
return s_Terrain.GetHeightAt(location);
}

static std::vector<Civ*> s_pCivs;
static Terrain s_Terrain;
}


There are a lot of ways to do it. For instance above World could have been a global and its members/functions wouldnt have to be static. It could use a singleton model or a couple other impementations.

The wandered could have an index or a pointer to the Civ. Or the Wanderer could pass itself to the World and the world could loop through all Civs asking which ones owns the passed in wanderer. Usually having an index to your "team" is pretty normal though.

I tried to include terrain a little bit just to throw out some more ideas, but again it is all up to you where/how you store things. In general if you have to jump through too many hoops or keep too many pointers/variables to everything your design could use another look. But generally model things in ways that make sense first. Then structure them for optimizations second, by time you are use to it all the optimization phase will be easier and it is best not to worry about it before then (depending on the scope of your project.)

Share this post


Link to post
Share on other sites
Quote:
Original post by Wavarian
I would probably re-organise the code so that each class maintains its own vector list:

Yeah, and that limits your villages from ever being used without registering themselves to that globally accessible list. Not a very elegant solution. Let the code that creates these Village instances be responsible for storing and using them, not the Village code itself.


@KnTenshi: the owning class (Civ) should be able to handle the destruction of it's villages and wanderers. Those objects shouldn't fiddle with their owner, they should at most give a signal that they need to be removed, possibly informing other objects (observer pattern) if that's necessary for your game. As for variables, see if you can pass those through functions instead, or if those objects even have to know about so many external variables.

Ultimately though, it depends on what you want to achieve. Yes, you've stated what you want to accomplish (A can read variables from B), but that's too low-level. Why should A be able to read from B? No, scrap that - what is A's reason to exist, it's responsibility, and what is B's goal? Once those things are clear, it'll be a little easier to design proper classes and the interactions between them.

Share this post


Link to post
Share on other sites
Well, thanks for all your help.

@Captain P.

Here's a more in depth look at what I have envisioned for the classes.

Civ() will hold threshold variables for each race or civilization. These include a variable for empire cohesion, preferred environment, breeding speed, and max village size. It will also, as I previously mentioned, hold a list of any and all villages and wanderers which will have each one run their code at a run time.

Village() should run itself based on whatever variables are in the Civ() it belongs to, such as breeding speed and max village size. Once it exceeds either its max village size or its local max size (can't support a larger size), it spawns a wanderer(). If a village().size ever reaches 0, it is destroyed and be removed from the owning Civ()'s villageList.

Wanderer() should also run itself based on variables from the village() that created it (current population in the wanderer(), for instance) and the Civ() of said village(). For it's existence, it will move around the map and check its current location and compare this information to the preferred environment within the Civ() that owns it. Once it finds a place that is suitable, creates a new village() instance, passes it some variables, and destroys itself and is removed from the owning Civ()'s wandererList. Though it might be hard, I'd like to include a way to create a new Civ() whenever a new village surpasses the empire cohesion threshold, with the wanderer class passing variables from the old Civ() to the new one.



I hope that is both what you were asking for and makes some bit of sense.

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