Representing a game world, alternative to dynamic casting? - c++

I'm trying to implement a game but first I need a way to represent the world that can hold players and items
I'm currently representing it as a 2D vector of <Entity> where Entity is a base class
Players and Items both derive from "Entity" class
Players and Items do not share common function except for maybe, a function that'll print their "information"
Dynamic casting will be needed, but I've read that it's a code smell as it is a school project, I wanna implement it in the "best way" possible
Any suggestions please ?

From the comments you've gotten so far, you can tell that at least some people think you should use separate arrays, and your argument for why it's one array doesn't really make sense, but sure...
The basic problem is that Items just flat out don't share a set of actions with Players, and the things you would do to each are different as well.
But if you insist on putting them into the same array, then you're going to need to detect what it is and end up with a typecast. Or do some polymorphism. For instance:
class Entity {
...
virtual void doSomeItemAction() {}
virtual void doSomePlayerAction() {}
}
class Item: public Entity {
...
void doSomeItemAction() override { ... }
}
et cetera.
Frankly, I wouldn't do it this way. I'd use separate vectors. But your two choices are detect type and typecast or do weird polymorphism that doesn't really fit your problem space, but you could make it work.

Related

Accessing subclass functions of member of collection of parent class objects

(Refer Update #1 for a concise version of the question.)
We have an (abstract) class named Games that has subclasses, say BasketBall and Hockey (and probably many more to come later).
Another class GameSchedule, must contain a collection GamesCollection of various Games objects. The issue is that we would, at times, like to iterate only through the BasketBall objects of GamesCollection and call functions that are specific to it (and not mentioned in the Games class).
That is, GameSchedule deals with a number of objects that broadly belong to Games class, in the sense that they do have common functions that are being accessed; at the same time, there is more granularity at which they are to be handled.
We would like to come up with a design that avoids unsafe downcasting, and is extensible in the sense that creating many subclasses under Games or any of its existing subclasses must not necessitate the addition of too much code to handle this requirement.
Examples:
A clumsy solution that I came up with, that doesn't do any downcasting at all, is to have dummy functions in the Game class for every subclass specific function that has to be called from GameSchedule. These dummy functions will have an overriding implementation in the appropriate subclasses which actually require its implementation.
We could explicitly maintain different containers for various subclasses of Games instead of a single container. But this would require a lot of extra code in GameSchedule, when the number of subclasses grow. Especially if we need to iterate through all the Games objects.
Is there a neat way of doing this?
Note: the code is written in C++
Update# 1: I realized that the question can be put in a much simpler way. Is it possible to have a container class for any object belonging to a hierarchy of classes? Moreover, this container class must have the ability to pick elements belonging to (or derive from) a particular class from the hierarchy and return an appropriate list.
In the context of the above problem, the container class must have functions like GetCricketGames, GetTestCricketGames, GetBaseballGame etc.,
This is exactly one of the problems that The "Tell, Don't Ask" principle was created for.
You're describing an object that holds onto references to other objects, and wants to ask them what type of object they are before telling them what they need to do. From the article linked above:
The problem is that, as the caller, you should not be making decisions based on the state of the called object that result in you then changing the state of the object. The logic you are implementing is probably the called object’s responsibility, not yours. For you to make decisions outside the object violates its encapsulation.
If you break the rules of encapsulation, you not only introduce the runtime risks incurred by rampant downcasts, but also make your system significantly less maintainable by making it easier for components to become tightly coupled.
Now that that's out there, let's look at how the "Tell, Don't Ask" could be applied to your design problem.
Let's go through your stated constraints (in no particular order):
GameSchedule needs to iterate over all games, performing general operations
GameSchedule needs to iterate over a subset of all games (e.g., Basketball), to perform type-specific operations
No downcasts
Must easily accommodate new Game subclasses
The first step to following the "Tell, Don't Ask" principle is identifying the actions that will take place in the system. This lets us take a step back and evaluate what the system should be doing, without getting bogged down into the details of how it should be doing it.
You made the following comment in #MarkB's answer:
If there's a TestCricket class inheriting from Cricket, and it has many specific attributes concerning the timings of the various innings of the match, and we would like to initialize the values of all TestCricket objects' timing attributes to some preset value, I need a loop that picks all TestCricket objects and calls some function like setInningTimings(int inning_index, Time_Object t)
In this case, the action is: "Initialize the inning timings of all TestCricket games to a preset value."
This is problematic, because the code that wants to perform this initialization is unable to differentiate between TestCricket games, and other games (e.g., Basketball). But maybe it doesn't need to...
Most games have some element of time: Basketball games have time-limited periods, while Baseball games have (basically) innings with basically unlimited time. Each type of game could have its own completely unique configuration. This is not something we want to offload onto a single class.
Instead of asking each game what type of Game it is, and then telling it how to initialize, consider how things would work if the GameSchedule simply told each Game object to initialize. This delegates the responsibility of the initialization to the subclass of Game - the class with literally the most knowledge of what type of game it is.
This can feel really weird at first, because the GameSchedule object is relinquishing control to another object. This is an example of the Hollywood Principle. It's a completely different way of solving problems than the approach most developers initially learn.
This approach deals with the constraints in the following ways:
GameSchedule can iterate over a list of Games without any problem
GameSchedule no longer needs to know the subtypes of its Games
No downcasting is necessary, because the subclasses themselves are handling the subclass-specific logic
When a new subclass is added, no logic needs to be changed anywhere - the subclass itself implements the necessary details (e.g., an InitializeTiming() method).
Edit: Here's an example, as a proof-of-concept.
struct Game
{
std::string m_name;
Game(std::string name)
: m_name(name)
{
}
virtual void Start() = 0;
virtual void InitializeTiming() = 0;
};
// A class to demonstrate a collaborating object
struct PeriodLengthProvider
{
int GetPeriodLength();
}
struct Basketball : Game
{
int m_period_length;
PeriodLengthProvider* m_period_length_provider;
Basketball(PeriodLengthProvider* period_length_provider)
: Game("Basketball")
, m_period_length_provider(period_length_provider)
{
}
void Start() override;
void InitializeTiming() override
{
m_period_length = m_time_provider->GetPeriodLength();
}
};
struct Baseball : Game
{
int m_number_of_innings;
Baseball() : Game("Baseball") { }
void Start() override;
void InitializeTiming() override
{
m_number_of_innings = 9;
}
}
struct GameSchedule
{
std::vector<Game*> m_games;
GameSchedule(std::vector<Game*> games)
: m_games(games)
{
}
void StartGames()
{
for(auto& game : m_games)
{
game->InitializeTiming();
game->Start();
}
}
};
You've already identified the first two options that came to my mind: Make the base class have the methods in question, or maintain separate containers for each game type.
The fact that you don't feel these are appropriate leads me to believe that the "abstract" interface you provide in the Game base class may be far too concrete. I suspect that what you need to do is step back and look at the base interface.
You haven't given any concrete example to help, so I'm going to make one up. Let's say your basketball class has a NextQuarter method and hockey has NextPeriod. Instead, add to the base class a NextGameSegment method, or something that abstracts away the game-specific details. All the game-specific implementation details should be hidden in the child class with only a game-general interface needed by the schedule class.
C# supports reflections and by using the "is" keyword or GetType() member function you could do these easily. If you are writing your code in unmanaged C++, I think the best way to do this is add a GetType() method in your base class (Games?). Which in its turn would return an enum, containing all the classes that derive from it (so you would have to create an enum too) for that. That way you can safely determine the type you are dealing with only through the base type. Below is an example:
enum class GameTypes { Game, Basketball, Football, Hockey };
class Game
{
public:
virtual GameTypes GetType() { return GameTypes::Game; }
}
class BasketBall : public Game
{
public:
GameTypes GetType() { return GameTypes::Basketball; }
}
and you do this for the remaining games (e.g. Football, Hockey). Then you keep a container of Game objects only. As you get the Game object, you call its GetType() method and effectively determine its type.
You're trying to have it all, and you can't do that. :) Either you need to do a downcast, or you'll need to utilize something like the visitor pattern that would then require you to do work every time you create a new implementation of Game. Or you can fundamentally redesign things to eliminate the need to pick the individual Basketballs out of a collection of Games.
And FWIW: downcasting may be ugly, but it's not unsafe as long as you use pointers and check for null:
for(Game* game : allGames)
{
Basketball* bball = dynamic_cast<Basketball*>(game);
if(bball != nullptr)
bball->SetupCourt();
}
I'd use the strategy pattern here.
Each game type has its own scheduling strategy which derives from the common strategy used by your game schedule class and decouples the dependency between the specific game and game schedule.

How do I use derived classes if I only have a base class pointer?

So here's what I got in a nutshell.
I have a base item class from which, potions, equipment, spells, etc.. are derived and several classes are derived from those and so on. Note: some derived classes have non-virtual class-specific member functions / data types.
I have also created a "random" armor/weapon generator.
What I want to have is an inventory kind of like this:
struct Hero_Inventory
{
std::vector<Spell*> Spell_Inventory;
std::vector<Potion*> Potion_Inventory;
std::vector<Equipment*> Equipment_Inventory;
Hero_Inventory() {}
};
Creating a container (inventory) for my spells and potions has been pretty straight forward. As they will be predefined. Using polymorphism and pointers wont be a problem
My main problem is figuring out to store and use (ex. access the weapon-class's specific member functions) my randomly generated weapons / armor (which are both derived from Equipment).
I would like for all of my "Equipment" to be in one container.
I'm generating all of my Equipment in a few functions so when I finish the generation process and end up with something like this:
Equipment * TestArmor = new Armor(/* Bunch of parameters go here */);
I don't know what to do with it, because as soon as that function goes out of scope I loose that pointer. And without pointers / referencing I can't use polymorphism, which is allowing me to keep my Equipment all in one container.
I'm really lost at this point and I'm looking for any suggestions or alternatives people can suggest. If you need more code I'll post it, just tell me what part(s) your interested in.
Sorry if I've been vague, this is my fist post. I'm usually pretty good at figuring things out on my own but this thing has me beat. If anyone needs more information ask and I'll try to provide it.
Thanks in advance,
-Ryan
Create a uniform interface for manipulating the Equipment objects:
class Equipment {
public:
virtual void render(Renderer& renderer) = 0;
virtual void createController(ControllerManager& controllerManager) = 0;
virtual void load(std::istream& input) = 0;
virtual void save(std::ostream& output) = 0;
};
The function createController is interesting as the equipment will be able to tell the ControllerManager how to create something that will manipulate its exact values.
If you want a function which allows interaction with other Equipment objects, you probably need the Visitor Pattern. This is a way of introducing polymorphism based on multiple types rather than a single type.

Selecting the right strategy based on two object types

I'm not sure how to name this problem, so I'm going to try to explain as good as I can.
I want to be able to switch strategies depending on the types of two different objects. To make this work, I am thinking of flagging the objects with an enum type, and having a 'registry' (arrayish) of these strategies. Ideally, the correct strategy would be accessed with some simple operation like a bitwise operator between the two types.
This pseudocode may make what I'm trying to explain easier to understand:
enum Type { A, B, C }
struct Object {
Type type;
}
class ActionRunner {
vector<Strategy> strategies;
void registerStrategy(type1, type2, strategy) {
strategies[type1 operator type2] = strategy;
}
void runStrategyFor(type1, type2) {
strategies[type1 operator type2].execute();
}
}
This would be easy to solve using a map, but I'd like to use an array or vector because a map seems like an overkill for a problem like this and using an array is probably much faster.
So the problem is I don't know what operator I might be able to use to select the 'position' of the right strategy. I've been thinking of a few combinations but it seems all of them end up causing collisions with the different combinations at some point.
Does anyone have any clues/advice on what I may be able to use for this?
PS: I know premature optimization is bad, but I'm just trying to figure out if this problem can be solved in a simple way.
------- EDIT ------------------------------------------------
In light of the answers, I've been giving the problem some extra thought and I've come to the conclusion what I intended with this question isn't possible the way I'd like it. I'm going to try to re-state the problem I'm trying to solve now using this question.
I'd like to have a class structure in which there's objects of certain type 'BaseClass' and a 'processor' object that takes two objects derived from 'BaseClass' and runs the right strategy for those. Something like this:
class Processor {
void run (DerivedA a, DerivedB b);
}
class BaseClass {}
class DerivedA: public BaseClass {}
class DerivedB: public BaseClass {}
BaseClass a = new DerivedA;
BaseClass b = new DerivedB;
processor.run(a, b)
According to what I understand, this would not work as I'd expect if what is passed as parameters to 'run' are references, which is what I'd rather do. Is there any way to do this without way-too-complicated code? (tripple dispatch!?)
I have in mind something like the double dispatch combined with an slave (processor) object that I think would work, but that seems awfully complex and probably a pain to maintain and extend.
Thanks!
The second sentence of your question rang a bell for me:
I want to be able to switch strategies depending on the types of two different objects.
This sounds like you want to perform a double dispatch. See the question (in particular, the answers to the question ;-)) at Double dispatch/multimethods in C++ for how to implement this in C++.
That's a classic example for using map instead of array. Array is actually a private case of map with key defined as an integer. In your case the key is a tuple so a simple array won't do and you'll end up with collisions (even if you're lucky for your specific input, your code will be extremely non-robust).
You can have an intermediate solution, between simple array and map: 2D array, with your 2 types serving as indices to rows and columns..

How to design OO graph node classes with improved usability & readability?

This is a basic OO design question. I'm writing classes in C++ to represent items in a flow chart according to an input C file that have been parsed.
Simply we have 2 types of items (classes) : FlowChartActionItem and FlowChartConditionItem.
These represent Actions and Decision/Condition elements of a flowchart respectively. And they also represent Statements and If-conditions respectively, that existed in the input C file. Both classes inherit FlowChartItem.
Each sub-classes has a number of pointers to the items that comes after them; yes, we have a graph, with nodes(items) and links(pointers). But the FlowChartActionItem has only one outward pointer while the FlowChartConditionItem has 3 outward pointers (for the then-statements branch, the else-statements branch and a pointer to whatever comes after the both branches of the if-condition.
My problem is writing a neat setter for the outward pointers (nextItems). Take a look at the classes :
class FlowChartItem
{
public:
//I **need** this setter to stay in the parent class FlowChartItem
virtual void SetNextItem(FlowChartItem* nextItem, char index) = NULL;
};
-
class FlowChartActionItem:public FlowChartItem
{
public:
FlowChartItem* nextItem; //Only 1 next item
public:
void SetNextItem(FlowChartItem* nextItem, char index);
};
-
class FlowChartConditionItem: public FlowChartItem
{
public:
FlowChartItem* nextItem;
FlowChartItem* trueBranchItem;
FlowChartItem* falseBranchItem; //we have 3 next items here
public:
void SetNextItem(FlowChartItem* nextItem, char index);
};
I needed a generic setter that doesn't depend on the number of pointers the sub-class is having.
As you see I've used char index to tell the setter which pointer is to be set. But I don't like this and I need to make things neater. Because code won't be readable e.g :
item1.setNextItem(item2,1);
we don't remember what the 1 means? the then-branch ? the else ? ??
The obvious answer is to define an enum in FlowCharItem, but then we'll have one of two problems :
1- Enum values will be defined Now and will thus be tailored for the current sub-classes FlowChartActioItem and FlowChartConditionItem, so calls to SetNextItem on future sub-classes will have very bad readability. And even worse, they cannot have more than 3 outward pointers!
2- Solve the 1st problem by making developers of the future sub-classes edit the header file of FlowChartItem and add whatever values in the enum ! of course not acceptable!
What solution do I have in order to keep
-good readability
-neat extensibility of my classes ??
This is a form of a common architecture dilemma. Different child classes have a shared behavior that differs slightly and you need to somehow extract the common essence to the base class in a way that makes sense. A trap that you will typically regret is to let the child class functionality bleed into the parent class. For instance I would not recommend a set of potential enum names for types of output connections defined in FlowChartItem. Those names would only make sense in the individual child nodes that use them. It would be similarly bad to complicate each of your sub classes to accommodate the design of their siblings. Above all things, KIS! Keep. It. Simple.
In this case, it feels like you're overthinking it. Design your parent class around the abstract concept of what it represents and how it will be used by other code, not how it's inheritors will specialize it.
The name SetNextItem could just be changed to make it more clear what both of the parameters do. It's only the "next" item in the sense of your entire chart, not in the context of a single FlowChartItem. A flow chart is a directed graph and each node would typically only know about itself and it's connections. (Also, you're not writing visual basic, so containers index starting from 0! :-) )
virtual void SetOutConnectionByIndex(FlowChartItem* nextItem, char index);
Or if you prefer shorter names, then you could set the "N'th" output item: SetNthOutItem.
Since it not valid to set a child using an out-of-range index, then you probably want to have another pure virtual function in FlowChartItem that returns the maximum number of supported children and make SetChildByIndex return a success/failure code (or if you're one of those people, throw an exception) if the index is out of range.
virtual bool SetChildByIndex(FlowChartItem* item, char index);
Now... having written all that, I start to wonder about the code you have that will call this function. Does it really only know about each node as a FlowChartItem, but still needs to set it's children in a particular order which it doesn't know the significance of? This might be valid if you have other code which is aware of the real item types and the meaning of their child orderings and that code is providing the item pointers and their index numbers to the code that does the setting. Maybe de-serialization code, but this is not the right way to handle serialization. Is FlowChartItem exposed through a strict API and the chart is built up by code that knows of the different types of flow chart items but does not have access to the actual classes? Maybe valid in that case, but I'm speculating now well beyond the details you've provided.
But if this function is only going to be called by code that knows the real item type, has access to the actual class, and knows what the index means, then this probably shouldn't be in the base class at all.
I can, however, imagine lots of types of code that would need to fetch a FlowChartItem's children in order, without knowing the significance of that order. Code to draw your flow chart, code to execute your flow-chart, whatever. If you cut your question down for brevity and are also thinking about similar getter method, then the above advice would apply (though you could also consider an iterator pattern).
I'm sidestepping your dubious need for a "generic" SetNextItem in the base class, and will propose a way you can implement your idea.
You could store FlowChartItem* items in a std::map<std::string, FlowChartItems*> (what I call an adjacency map), and set the items by name. This way, subclasses can have as many adjacencies as they want and there's no need to maintain a central enum of adjacency types.
class FlowChartItem
{
public:
virtual void SetAdjacency(FlowChartItem* item, const std::string &type)
{
// Enforce the use of a valid adjacency name
assert(NameSet().count(type) != 0);
adjacencyMap_[name] = nextItem
}
protected:
// Subclasses must override this and return a set of valid adjacency names
const std::set<std::string>& NameSet() = 0;
std::map<std::string, FlowChartItem*> adjacencyMap_;
};
class FlowChartActionItem : public FlowChartItem
{
public:
// Convenience member function for when we're dealing directly
// with a FlowChartActionItem.
void SetNextItem(FlowChartItem* item) {SetAdjacency(item, "next");}
protected:
const std::set<std::string>& NameSet()
{
// Initialize static nameSet_ if emtpy
return nameSet_;
}
private:
// One set for the whole class (static).
const static std::set<std::string> nameSet_;
static std::set<std::string> MakeNameSet()
{
std::set<std::string> names;
names.insert("next");
return names;
}
}
// Initialize static member
const std::set<std::string> FlowChartActionItem::nameSet_ =
FlowChartActionItem::MakeNameSet();
Usage:
item1.SetAdjacency(&item2, "next");
I needed a generic setter that doesn't depend on the number of
pointers the sub-class is having.
The only way to have a mutable structure like this is to allow the client to access a data structure, say, std::vector<FlowChartItem*> or std::unordered_map<unsigned int, FlowChartItem*> or whatever. They can read it and set the values.
Fundamentally, as long as you're trying to dynamically set static items, you're going to have a mess. You're trying to implement your own, highly primitive, reflection system.
You need to have dynamic items if you want them to be dynamically set without a language-built-in reflection system or endlessly wasting your life jerking around trying to make it work.
As a bonus, if you have something like that, the use case for your derived classes just got a lot lower, and you could maybe even get rid of them. WinRAR™.

Possible to declare elements of a function array individually?

So, a quick summary of why I'm trying to do this:
I'm making a space flight program, wherein (once I code in more than one ship) I will be able to store different ships, e.g. craft[HAB], craft[AYSE], craft[ISS], and so forth. At the moment, I have only coded in one ship, and I declare it like so:
enum craft {HAB, CRAFTMAX};
...
[declaring ship class here]
...
ship craft[CRAFTMAX];
However, not all ships will be the same structure. For example, HAB (short for Habitat) will be a circle with three engine pods on the bottom, AYSE will be a space station with a tube going to the centre, and docking lights, and so forth. I am making these functions draw a vector to the screen.
At the moment, I have declared ship::draw, and I just use this to draw the Hab. However, I want to be able to modify each draw function to draw that ship, i.e. craft[AYSE].draw() will have a different declaration than craft[HAB].draw().
I've thought, and looked up different ways to do this, but I haven't gotten much success. I'd still like to be able to iterate through all the crafts for ease of calculating gravity and collisions. But I'm guessing if it's impossible to individually declare functions when they are elements of an array, it won't be too much trouble to declare each ship individually, as there will only be 10, max.
Here is my git repository that is storing this, if you want to take a look at any other code. It is definitely a bit unorganized, as it is a monopoly project, and I only ever see myself using it.
Any of you tried to do this? I'm sure there must be a few people out there!
And thanks in advance.
I think you will be much better by using a base class for a Ship object, then deriving from this base class for the different types of ships. Then use some container that allows you to iterate through all ship objects and call the respective functions. Like:
class Ship {
public:
virtual void draw() const = 0;
};
class HAB : public Ship {
virtual void draw() const;
};
class AYSE : public Ship {
virtual void draw() const;
};
Then using a container like:
vector<Ship> ships;
ship.insert(HAB());
ship.insert(AYSE());
// to draw
for_each(ships.begin(), ships.end(), mem_fn(&Ship::draw));
I came up with this fairly quick so you will have to work out the details. The way you are thinking of doing it is not very OO and will have problems in terms of maintenance (think Single Point of Maintenance).
I don't like the look of your code - using the word craft as both a type identifier and a variable identifier...
But from your question it looks like you want to use inheritance. So you declare a
class ship {
// put here all methods that all ships have and that are the same
// and all data that all ships.
virtual void Draw( ) = 0; // subclasses of ship are forced to implement their own Draw
// etc.
};
Now when you want an array of ships, make it an array of pointers to ship. You can then put in pointers to the subclasses, and use dynamic_cast to get pointers back to the subclasses when you need them. But by calling A[4]->Draw() you will get whatever Draw routine is appropriate for the object in location 4 of the array.
The OO way would be to create a hierarchy of types, with each type representing one of the types of aircrafts. Use virtual functions to provide different implementations for the common interface (declared in the base class).
Once you have this, you will need to store the objects in the container polymorphically (i.e. not the object, but rather a smart pointer to the objects). The (smart) pointers would be of the base type and the objects of the actual types. I would recommend that you use a higher level container rather than arrays (i.e. std::vector<std::unique_ptr<ship>>)
You'll probably want to declare a base class and implement each type of ship as child classes.
class HAB: public ship{
//code here
};
For more information on inheritance: see this tutorial.
The colon shows that HAB inherits member data and function from the class ship. This way you can define some functions uniquely in each of the child classes while still having them share important functions with the base class. For example each ship type is likely to have similar member functions like get_position() whereas a draw function depends specifically on each ship type.
The beauty of polymorphism is that you can refer to the child classes as their parent class. So you can make an array of ship * (ship pointers) to refer to an array of child classes.
ship * array[CRAFTMAX];
array[0]=new HAB;
However before using this sort of thing you should be really up on your pointers because mismanagement can result in memory leaks. That is, you allocate memory and never free it up.
This website has some nice instruction in polymorphism.