I am trying to design a UIDraw method. I want to declare what UI elements to draw in the main Draw method But then Have a separate UIDraw Method later in the code. So I need a way to store instructions to execute in this new function. I hope it makes sense.
Something like this:
Draw();
DrawUI();
But say what UI to draw in the Draw() function.
Any ideas on how to tackle this problem?
There are many ways to tackle this problem depending on what exactly you need. One approach popular in the OO world is the so called Command Pattern (similar approaches exist in other programming paradigms, they just have either different names or are considered so obvious they don't even get a specific name at all).
The basic idea is this: You want to execute some command, but the time you want to execute the command and the time you decide what command to execute are different. So the way to solve this problem is to simply create an object that contains the information you need to execute the command, pass that object to the place that decides when the execution should happen, and then that code can run the command as it pleases.
Here’s a mockup of what that might look like in C++ (note: didn't actually compile this code, might contain minor errors – just meant to convey the idea).
#include <memory>
#include <vector>
/// this is an abstract class that gives us an interface to use
class DrawCommand {
public:
virtual void Draw() = 0;
};
/// one kind of thing you might want to draw
class DrawTree : public DrawCommand {
public:
void Draw() override {
// tree drawing code
}
};
/// another kind of thing you might want to draw
class DrawCat : public DrawCommand {
public:
void Draw() override {
// cat drawing code
}
};
/// we can even come up with ways to combine these in interesting ways
class DrawABunchOfThings : public DrawCommand {
std::vector<std::unique_ptr<DrawCommand>> things;
public:
DrawABunchOfThings(std::vector<std::unique_ptr<DrawCommand>> things)
: things{std::move(things)}
{}
void Draw() override {
for(auto &thing : things) {
thing->Draw();
}
}
};
/// this is where we decide what we will draw
std::unique_ptr<DrawCommand> PrepareDraw() {
if(someCondition) {
// just a cat
return std::make_unique<DrawCat>();
} else if(someOtherCondition) {
// just a tree
return std::make_unique<DrawTree>();
} else {
// forest with a cat hidden inside
return std::make_unique<DrawABunchOfThings>(
std::vector<std::unique_ptr<DrawCommand>>{
std::make_unique<DrawTree>(),
std::make_unique<DrawTree>(),
std::make_unique<DrawCat>()
std::make_unique<DrawTree>(),
}
);
}
}
/// this is where we will do the actual drawing
/// note that any arbitrary amount of code can go between
/// PrepareDraw and ExecuteDraw
void ExecuteDraw(DrawCommand &command) {
// this can of course have a bunch of elaborate
// code here as well -- also, DrawCommand::Draw might
// take extra parameters here, like 2D or 3D transforms,
// time since we last drew something, or whatever
command.Draw();
}
Note that if you only need a single method on this thing C++ already has this in the form of std::function, so you could just say using DrawCommand = std::function<void()>; and be done with it, which would also immediately allow you to use it with lambdas:
int nTimes = 10;
DrawCommand drawNTimesCommand = [nTimes]() {
for(int i = 0; i < nTimes; ++i) {
// draw something
}
};
// --- any code you like here ---
// actually execute the draw command
drawNTimesCommand();
Related
I am very new to C++, having only used Unrealscript previously, and I'm trying to write a relatively simple console game to teach myself the basics (using OneLoneCoder engine). I've set myself a goal of implementing pause/dialog screens which can call specific functions depending on player input (eg pressing Y or N when given an option, which could then lead to another dialog box, or something happening to the player). My first instinct was to create a base class like this:
wstring PauseText,PromptText;
PauseScreen CurrPauseScreen;
class PauseScreen
{
public:
virtual wstring GetPText()
{
return L"NO PAUSE TEXT";
}
virtual wstring GetPPText()
{
return L"NO PROMPT TEXT";
}
virtual void EFunc()
{
UnPause();
}
virtual void YFunc()
{
}
virtual void NFunc()
{
}
virtual void SetPrompts()
{
PauseText = GetPText();
PromptText = GetPPText();
}
PauseScreen()
{
SetPrompts();
}
~PauseScreen()
{
}
};
int main()
{
if (m_keys[L'E'].bPressed || m_keys[L'P'].bPressed)
{
CurrPauseScreen->EFunc();
}
else if (m_keys[L'Y'].bPressed)
{
CurrPauseScreen->YFunc();
}
else if (m_keys[L'N'].bPressed)
{
CurrPauseScreen->NFunc();
}
return 0;
}
and override functions as necessary. At the moment, I'm using a global CurrPauseScreen variable to store the currently used PauseScreen info, and simply take all necessary values and methods from that (remembering to delete it when game is unpaused or a new screen is created).
I initially attempted to use function pointers which pointed to class methods and didn't use the 'new' operator in order to avoid using heap memory because I know it's ill-advised, but I felt like I was chasing my own tail figuring out how to use them properly, as it doesn't seem easy to have a pointer point to a class method. Basically I want to know if there is a simpler way of setting/changing all necessary functions and variables through classes on a one-off basis, or if using classes and an Object-Oriented approach is advised at all in this situation, as from what I've seen through my google searching, it's often looked down upon in C++.
EDIT: The code I have at the moment works as I intended, but is just a little too 'messy' for my liking, having to place a class on the heap and ensure it's deleted appropriately at each step. Ideally I would like to simply instantiate a class on the stack and have the class handle all of the setting within itself, including changing the PauseText,PromptText and the various functions (EFunc(), YFunc() and NFunc()). Changing the text is easy enough, but changing function behaviour from within a class is where I am having the most trouble.
I'm trying to write a class (some sort of graphics engine) basically it's purpose is to render ANYTHING that I pass into it. In most tutorials I've seen, objects draw themselves. I'm not sure if that's how things are supposed to work. I've been searching the internet trying to come up with different ways to handle this problem, I've been reviewing function templates and class templates over and over again (which sounds like the solution I could be looking for) but when I try using templates, it just seems messy to me (possibly because I don't fully understand how to use them) and then I'll feel like taking the template class down, then I'll give it a second try but then I just take it down again, I'm not sure if that's the way to go but it might be. Originally it was tiled-based only (including a movable player on screen along with a camera system), but now I've trying to code up a tile map editor which has things such as tool bars, lists, text, possibly even primitives on screen in the future, etc. and I'm wondering how I will draw all those elements onto the screen with a certain procedure (the procedure isn't important right now, I'll find that out later). If any of you were going to write a graphics engine class, how would you have it distinguish different types of graphic objects from one another, such as a primitive not being drawn as a sprite or a sphere primitive not being drawn as a triangle primitive, etc.? Any help would be appreciated. :)
This is the header for it, it's not functional right now because I've been doing some editing on it, Just ignore the part where I'm using the "new" keyword, I'm still learning that, but I hope this gives an idea for what I'm trying to accomplish:
//graphicsEngine.h
#pragma once
#include<allegro5\allegro.h>
#include<allegro5\allegro_image.h>
#include<allegro5\allegro_primitives.h>
template <class graphicObjectData>
class graphicsEngine
{
public:
static graphicObjectData graphicObject[];
static int numObjects;
static void setup()
{
al_init_image_addon();
al_init_primitives_addon();
graphicObject = new graphicObjectData [1]; //ignore this line
}
template <class graphicObjectData> static void registerObject(graphicObjectData &newGraphicObject) //I'm trying to use a template function to take any type of graphic object
{
graphicObject[numObjects] = &newObject;
numObjects++;
}
static void process() //This is the main process where EVERYTHING is supposed be drawn
{
int i;
al_clear_to_color(al_map_rgb(0,0,0));
for (i=0;i<numObjects;i++) drawObject(graphicObject[i]);
al_flip_display();
}
};
I am a huge fan of templates, but you may find in this case that they are cumbersome (though not necessarily the wrong answer). Since it appears you may be wanting diverse object types in your drawing container, inheritance may actually be a stronger solution.
You will want a base type which provides an abstract interface for drawing. All this class needs is some function which provides a mechanism for the actual draw process. It does not actually care how drawing occurs, what's important is that the deriving class knows how to draw itself (if you want to separate your drawing and your objects, keep reading and I will try to explain a way to accomplish this):
class Drawable {
public:
// This is our interface for drawing. Simply, we just need
// something to instruct our base class to draw something.
// Note: this method is pure virtual so that is must be
// overriden by a deriving class.
virtual void draw() = 0;
// In addition, we need to also give this class a default virtual
// destructor in case the deriving class needs to clean itself up.
virtual ~Drawable() { /* The deriving class might want to fill this in */ }
};
From here, you would simply write new classes which inherit from the Drawable class and provide the necessary draw() override.
class Circle : public Drawable {
public:
void draw() {
// Do whatever you need to make this render a circle.
}
~Circle() { /* Do cleanup code */ }
};
class Tetrahedron : public Drawable {
public:
void draw() {
// Do whatever you need to make this render a tetrahedron.
}
~Tetrahedron() { /* Do cleanup code */ }
};
class DrawableText : public Drawable {
public:
std::string _text;
// Just to illustrate that the state of the deriving class
// could be variable and even dependent on other classes:
DrawableText(std::string text) : _text(text) {}
void draw() {
// Yet another override of the Drawable::draw function.
}
~DrawableText() {
// Cleanup here again - in this case, _text will clean itself
// up so nothing to do here. You could even omit this since
// Drawable provides a default destructor.
}
};
Now, to link all these objects together, you could simply place them in a container of your choosing which accepts references or pointers (or in C++11 and greater, unique_ptr, shared_ptr and friends). Setup whatever draw context you need and loop through all the contents of the container calling draw().
void do_drawing() {
// This works, but consider checking out unique_ptr and shared_ptr for safer
// memory management
std::vector<Drawable*> drawable_objects;
drawable_objects.push_back(new Circle);
drawable_objects.push_back(new Tetrahedron);
drawable_objects.push_back(new DrawableText("Hello, Drawing Program!"));
// Loop through and draw our circle, tetrahedron and text.
for (auto drawable_object : drawable_objects) {
drawable_object->draw();
}
// Remember to clean up the allocations in drawable_objects!
}
If you would like to provide state information to your drawing mechanism, you can require that as a parameter in the draw() routine of the Drawable base class:
class Drawable {
public:
// Now takes parameters which hold program state
virtual void draw(DrawContext& draw_context, WorldData& world_data) = 0;
virtual ~Drawable() { /* The deriving class might want to fill this in */ }
};
The deriving classes Circle, Tetrahedron and DrawableText would, of course, need their draw() signatures updated to take the new program state, but this will allow you to do all of your low-level drawing through an object which is designed for graphics drawing instead of burdening the main class with this functionality. What state you provide is solely up to you and your design. It's pretty flexible.
BIG UPDATE - Another Way to Do It Using Composition
I've been giving it careful thought, and decided to share what I've been up to. What I wrote above has worked for me in the past, but this time around I've decided to go a different route with my engine and forego a scene graph entirely. I'm not sure I can recommend this way of doing things as it can make things complicated, but it also opens the doors to a tremendous amount of flexibility. Effectively, I have written lower-level objects such as VertexBuffer, Effect, Texture etc. which allow me to compose objects in any way I want. I am using templates this time around more than inheritance (though intheritance is still necessary for providing implementations for the VertexBuffers, Textures, etc.).
The reason I bring this up is because you were talking about getting a larger degree of seperation. Using a system such as I described, I could build a world object like this:
class World {
public:
WorldGeometry geometry; // Would hold triangle data.
WorldOccluder occluder; // Runs occlusion tests against
// the geometry and flags what's visible and
// what is not.
WorldCollider collider; // Handles all routines for collision detections.
WorldDrawer drawer; // Draws the world geometry.
void process_and_draw();// Optionally calls everything in necessary
// order.
};
Here, i would have multiple objects which focus on a single aspect of my engine's processing. WorldGeometry would store all polygon details about this particular world object. WorldOccluder would do checks against the camera and geometry to see which patches of the world are actually visible. WorldCollider would process collission detection against any world objects (omitted for brevity). Finally, WorldDrawer would actually be responsible for the drawing of the world and maintain the VertexBuffer and other lower-level drawing objects as needed.
As you can see, this works a little more closely to what you originally asked as the geometry is actually not used only for rendering. It's more data on the polygons of the world but can be fed to WorldGeometry and WorldOccluder which don't do any drawing whatsoever. In fact, the World class only exists to group these similar classes together, but the WorldDrawer may not be dependent on a World object. Instead, it may need a WorldGeometry object or even a list of Triangles. Basically, your program structure becomes highly flexible and dependencies begin to disappear since objects do not inherit often or at all and only request what they absolutely require to function. Case in point:
class WorldOccluder {
public:
// I do not need anything more than a WorldGeometry reference here //
WorldOccluder(WorldGeometry& geometry) : _geometry(geometry)
// At this point, all I need to function is the position of the camera //
WorldOccluderResult check_occlusion(const Float3& camera) {
// Do all of the world occlusion checks based on the passed
// geometry and then return a WorldOccluderResult
// Which hypothetically could contain lists for visible and occluded
// geometry
}
private:
WorldGeometry& _geometry;
};
I chose the WorldOccluder as an example because I've spent the better part of the day working on something like this for my engine and have used a class hierarchy much like above. I've got boxes in 3D space changing colors based on if they should be seen or not. My classes are very succinct and easy to follow, and my entire project hierarchy is easy to follow (I think it is anyway). So this seems to work just fine! I love being on vacation!
Final note: I mentioned templates but didn't explain them. If I have an object that does processing around drawing, a template works really well for this. It avoids dependencies (such as through inheritence) while still giving a great degree of flexibility. Additionally, templates can be optimized by the compiler by inlining code and avoiding virtual-style calls (if the compiler can deduce such optimizations):
template <typename TEffect, TDrawable>
void draw(TEffect& effect, TDrawable& drawable, const Matrix& world, const Matrix& view, const Matrix& projection) {
// Setup effect matrices - our effect template
// must provide these function signatures
effect.world(world);
effect.view(view);
effect.projection(projection);
// Do some drawing!
// (NOTE: could use some RAII stuff here in case drawable throws).
effect.begin();
for (int pass = 0; pass < effect.pass_count(); pass++) {
effect.begin_pass(pass);
drawable.draw(); // Once again, TDrawable objects must provide this signature
effect.end_pass(pass);
}
effect.end();
}
My technique might really suck, but I do it like this.
class entity {
public:
virtual void render() {}
};
vector<entity> entities;
void render() {
for(auto c : entities) {
c->render();
}
}
Then I can do stuff like this:
class cubeEntity : public entity {
public:
virtual void render() override {
drawCube();
}
};
class triangleEntity : public entity {
public:
virtual void render() override {
drawTriangle();
}
};
And to use it:
entities.push_back(new cubeEntity());
entities.push_back(new triangleEntity());
People say that it's bad to use dynamic inheritance. They're a lot smarter than me, but this approach has been working fine for a while. Make sure to make all your destructors virtual!
The way the SFML graphics library draws objects (and the way I think is most manageable) is to have all drawable objects inherit from a 'Drawable' class (like the one in David Peterson's answer), which can then be passed to the graphics engine in order to be drawn.
To draw objects, I'd have:
A Base class:
class Drawable
{
int XPosition;
int YPosition;
int PixelData[100][100]; //Or whatever storage system you're using
}
This can be used to contain information common to all drawable classes (like position, and some form of data storage).
Derived Subclasses:
class Triangle : public Drawable
{
Triangle() {} //overloaded constructors, additional variables etc
int indigenous_to_triangle;
}
Because each subclass is largely unique, you can use this method to create anything from sprites to graphical-primitives.
Each of these derived classes can then be passed to the engine by reference with
A 'Draw' function referencing the Base class:
void GraphicsEngine::draw(const Drawable& _object);
Using this method, a template is no longer necessary. Unfortunately your current graphicObjectData array wouldn't work, because derived classes would be 'sliced' in order to fit in it. However, creating a list or vector of 'const Drawable*' pointers (or preferably, smart pointers) would work just as well for keeping tabs on all your objects, though the actual objects would have to be stored elsewhere.
You could use something like this to draw everything using a vector of pointers (I tried to preserve your function and variable names):
std::vector<const Drawable*> graphicObject; //Smart pointers would be better here
static void process()
{
for (int i = 0; i < graphicObject.size(); ++i)
draw(graphicObject[i]);
}
You'd just have to make sure you added each object to the list as it was created.
If you were clever about it, you could even do this in the construction and destruction:
class Drawable; //So the compiler doesn't throw an error
std::vector<const Drawable*> graphicObject;
class Drawable
{
Triangle() {} //overloaded constructors, additional variables etc
int indigenous_to_triangle;
std::vector<const Drawable*>::iterator itPos;
Drawable() {
graphicObject.push_back(this);
itPos = graphicObject.end() - 1;
}
~Drawable() {
graphicObject.erase(itPos);
}
}
Now you can just create objects and they'll be drawn automatically when process() is called! And they'll even be removed from the list once they're destroyed!
All the above ideas have served me well in the past, so I hope I've helped you out, or at least given you something to think about.
We have a rendering pipeline and our current code creates an instance for every stage of the pipeline. This means that as we update our code, we will be constantly updating the pipeline (or multiple sets of pipelines) code. This feels like a point where we should have additional abstraction, but we're not sure how to proceed.
Edit: It seems my pseudo code is not well understood. Perhaps a diagram will more easily explain the pattern.
Link to a block diagram: http://yuml.me/0650d1bf.svg
// yuml.me
[GenericRenderStage|render|Parent Class]<---[Shadow1RenderStage|render|Derived Class]
[Shadow1RenderStage|render|Derived Class]<---[_shadowRenderStage1|Singleton Object]
[GenericRenderStage|render|Parent Class]<---[Shadow2RenderStage|render|Derived Class]
[Shadow2RenderStage|render|Derived Class]<---[_shadowRenderStage2|Singleton Object]
[GenericRenderStage|render|Parent Class]<---[ShadowNRenderStage|render|Derived Class]
[ShadowNRenderStage|render|Derived Class]<---[_shadowRenderStageN|Singleton Object]
Psuedo-c++ code of parent class:
class GenericRenderStage(...) {
/// Render method
virtual void render(void) {
/// handles drawing code
}
class Shadow1RenderStage : GenericRenderStage(...) {
/// Render method
void render(void) {
/// handles custom drawing for shadow1 stage
}
class Shadow2RenderStage : GenericRenderStage(...) {
/// Render method
void render(void) {
/// handles custom drawing for shadow2 stage
}
...
class ShadowNRenderStage : GenericRenderStage(...) {
/// Render method
void render(void) {
/// handles custom drawing for shadowN stage
}
We then have a set of the same type of pattern for our pipelines...
class GenericRenderPipeLine(...) {
/// Render method
virtual void render(void) {
/// handles drawing code
}
class ShadowRenderPipeline : GenericRenderPipeLine() {
/// instantiate stages for this pipeline
ShadowRenderPipeline() {
shadow1Stage = new Shadow1RenderStage();
shadow2Stage = new Shadow2RenderStage();
...
shadowNStage = new ShadowNRenderStage();
}
/// Render method
void render(void) {
/// setup fbo
/// for each render stage, render
shadow1Stage.render()
shadow2Stage.render()
...
shadowNStage.render()
/// handle fbo
}
Something here seems really wrong with the pattern. We've got a parent class that is basically a set of virtual methods to be inherited by a customized class that only ever has one instance.
From what I understand (please correct me if I'm wrong), each render stage is unique and doesn't really follow any specific pattern. So, I think it's best to keep those the way they are; have each render stage in a self-contained file/class.
However, I think you could reduce a lot of work by eliminating your render pipeline inheritance structure. All of these appear to be the same (i.e. they have some number of stages and call render() on each of them). What if you instead had a dynamic, generic pipeline?
#include <vector>
#include <memory>
class DynamicRenderPipeline {
private:
std::vector<std::unique_ptr<GenericRenderStage>> renderStages;
public:
void add(std::unique_ptr<GenericRenderStage> renderStage) {
renderStages.push_back(std::move(renderStage));
}
void render() {
for (auto& stage : renderStages) {
stage->render();
}
}
};
int main() {
DynamicRenderPipeline pipeline;
pipeline.add(std::unique_ptr<GenericRenderStage>(new RenderStage1()));
pipeline.add(std::unique_ptr<GenericRenderStage>(new RenderStage2()));
pipeline.add(std::unique_ptr<GenericRenderStage>(new RenderStage3()));
pipeline.add(std::unique_ptr<GenericRenderStage>(new RenderStage4()));
pipeline.add(std::unique_ptr<GenericRenderStage>(new RenderStage5()));
pipeline.render();
}
You can now just create instances of DynamicRenderPipeline and add any stages you wish. When you call render() on it, it will loop through all of the added render stages in the proper order. Now your pipeline only depends on the GenericRenderStage interface. If you're not using C++11 you could do the same with raw pointers (instead of unique_ptr), but you'd have to make sure to clean up your vector in the pipeline's destructor.
The fact that you only ever instantiate one object of each one of the many classes you created is a manifestation of a common problem in class-based OOP à la Java/C++. It is somewhat easier to circumvent in C++ than in Java.
The problem is simply that all code has to reside in class definitions if you want to go the pure class-based OO way. For instance, in Java, if you wanted to create many vastly different comparators (boolean predicates of two values of the same type), you ideally would have to create just as many subclasses of the standard Java generic interface Comparator. Actually, I lied, because in many cases you could just use the
new Comparator<Type>() {
public bool compare(Type a, Type b) { /* */ }
}
syntax, which is the closest Java ever got to having first-class citizen functions prior to Java 8. However, even that syntax doesn't work when you want to allow the creation of customized comparators, and you then have to write an entire class like so in order to void repeating yourself:
class CompareIntsPlusX implements Comparator<int>
{
private int number;
public CompareIntsPlusX(int number) {
this.number = number;
}
public bool compare(int x, int y) {
return x < y + number;
}
}
Comparator<int> myComparator = new CompareIntsPlusX(3);
and we end up with very cumbersome syntax for even the simplest of objects. Notice that in any (somewhat) functional programming language like Javascript, this problem would be more easily solved.
The same phenomenon is happening here. You have been going the class-based OO way in your pipeline stage definitions, and now you realise it's not scalable because you only need one object carrying with it the code defined in its class, and you need many such objects.
Those objects are what you referred to as "singletons" even though they do not in any way follow the Singleton design pattern. They are de facto singletons, and the reason for this is that they are actually just functions in disguise. Their only goal is to "carry" with them a void render() method.
From here you have several solutions:
If the render functions are vastly different, and you cannot generate them from one class that accepts parameters like we did with the CompareIntsPlusX Java class above, that is to say if you cannot factor your code, then
If you are using a functional style of C++03 (I wouldn't recommend that) or of C++11 (I have never used what I'm about to suggest) then you can simply use one RenderStage class defined like so:
class RenderStage
{
private:
std::function<void()> renderFunction;
public:
RenderStage(std::function<void()> renderFunction)
: renderFunction(renderFunction)
{ }
void render() {
renderFunction();
}
}
/* Somewhere else in the code, create your render stages */
RenderStage r1([]() {
// blah blah
});
// You can also capture stuff!
Texture tex;
RenderStage r2([&tex]() {
// blah blah
});
In C++03, we would use function pointers (whose functions are defined in a namespace because we don't want to be polluting the global namespace). Note that in the C++11 case, we only need to use std::function if captures are needed in the lambdas. If not, then just use function pointers.
Else, if you want to keep using an OO style, then create as many classes as you need and don't feel bad about it. In fact, creating anonymous classes is what the compiler does behind your back when you create lambdas (in fact it creates classes if your lambdas have captures and simple functions if not) and the Java compiler does it too when you "instantiate an interface".
Else, if the render methods can be factored, i.e. if instead of N classes you can have one with a constructor that allows for customization, then do that instead.
It's probable that a mix of the first and second solutions is what you need. You should try the second solution of having customizable render stage objects before you go for the more complex solution.
I'm in a bit of a pickle: say I'm making a simple, 2D, Zelda-like game.
When two Objects collide, each should have a resulting action. However, when the main character collides with something, his reaction depends solely on the type of the object with which he collided. If it's a monster, he should bounce back, if it's a wall, nothing should happen, if it's a magical blue box with ribbons, he should heal, etc. (these are just examples).
I should also note that BOTH things are part of the collision, that is, collision events should happen for both the character AND the monster, not just one or the other.
How would you write code like this? I can think of a number of incredibly inelegant ways, for instance, having virtual functions in the global WorldObject class, to identify attributes - for instance, a GetObjectType() function (returns ints, char*s, anything that identifies the object as Monster, Box, or Wall), then in classes with more attributes, say Monster, there could be more virtual functions, say GetSpecies().
However, this becomes annoying to maintain, and leads to a large cascading switch (or If) statement in the collision handler
MainCharacter::Handler(Object& obj)
{
switch(obj.GetType())
{
case MONSTER:
switch((*(Monster*)&obj)->GetSpecies())
{
case EVILSCARYDOG:
...
...
}
...
}
}
There's also the option of using files, and the files would have things like:
Object=Monster
Species=EvilScaryDog
Subspecies=Boss
And then the code can retrieve the attributes without the need for virtual functions cluttering everything up. This doesn't solve the cascading If problem, however.
And THEN there's the option of having a function for each case, say CollideWall(), CollideMonster(), CollideHealingThingy(). This is personally my least favourite (although they're all far from likeable), because it seems the most cumbersome to maintain.
Could somebody please give some insight into more elegant solutions to this problem?
Thanks for any and all help!
I would do it vice versa - because if the character collides with an object, an object collides with the character as well. Thus you can have a base class Object, like this:
class Object {
virtual void collideWithCharacter(MainCharacter&) = 0;
};
class Monster : public Object {
virtual void collideWithCharacter(MainCharacter&) { /* Monster collision handler */ }
};
// etc. for each object
Generally in OOP design virtual functions are the only "correct" solution for cases like this:
switch (obj.getType()) {
case A: /* ... */ break;
case B: /* ... */ break;
}
EDIT:
After your clarification, you will need to adjust the above a bit. The MainCharacter should have overloaded methods for each of the objects it can collide with:
class MainCharacter {
void collideWith(Monster&) { /* ... */ }
void collideWith(EvilScaryDog&) { /* ... */ }
void collideWith(Boss&) { /* ... */ }
/* etc. for each object */
};
class Object {
virtual void collideWithCharacter(MainCharacter&) = 0;
};
class Monster : public Object {
virtual void collideWithCharacter(MainCharacter& c)
{
c.collideWith(*this); // Tell the main character it collided with us
/* ... */
}
};
/* So on for each object */
This way you notify the main character about the collision and it can take appropriate actions. Also if you need an object that should not notify the main character about the collision, you can just remove the notification call in that particular class.
This approach is called a double dispatch.
I would also consider making the MainCharacter itself an Object, move the overloads to Object and use collideWith instead of collideWithCharacter.
How about deriving all collidable objects from one common abstract class (let's call it Collidable). That class could contain all properties that can be changed by a collission and one HandleCollision function. When two objects collide, you just call HandleCollision on each object with the other object as the argument. Each object manipulates the other to handle the collision. Neither object needs to know what other object type it just bounced into and you have no big switch statements.
Make all colidable entities implement an interface (lets say "Collidable") with a collideWith(Collidable) method.
Then, on you collision detection algorithm, if you detect that A collides with B, you would call:
A->collideWith((Collidable)B);
B->collideWith((Collidable)A);
Assume that A is the MainCharacter and B a monster and both implement the Collidable interface.
A->collideWith(B);
Would call the following:
MainCharacter::collideWith(Collidable& obj)
{
//switch(obj.GetType()){
// case MONSTER:
// ...
//instead of this switch you were doing, dispatch it to another function
obj->collideWith(this); //Note that "this", in this context is evaluated to the
//something of type MainCharacter.
}
This would in turn call the Monster::collideWith(MainCharacter) method and you can implement all monster-character behaviour there:
Monster::CollideWith(MainCharacter mc){
//take the life of character and make it bounce back
mc->takeDamage(this.attackPower);
mc->bounceBack(20/*e.g.*/);
}
More info: Single Dispatch
Hope it helps.
What you call "an annoying switch statement" i would call "a great game" so you are on the right track.
Having a function for every interaction/game rule is exactly what I would suggest. It makes it easy to find, debug, change and add new functionality:
void PlayerCollidesWithWall(player, wall) {
player.velocity = 0;
}
void PlayerCollidesWithHPPotion(player, hpPoition) {
player.hp = player.maxHp;
Destroy(hpPoition);
}
...
So the question is really how to detect each of these cases. Assuming you have some sort of collision detection that results in X and Y collide (as simple as N^2 overlap tests (hey, it works for plants vs zombies, and that's got a lot going on!) or as complicated as sweep and prune + gjk)
void DoCollision(x, y) {
if (x.IsPlayer() && y.IsWall()) { // need reverse too, y.IsPlayer, x.IsWall
PlayerCollidesWithWall(x, y); // unless you have somehow sorted them...
return;
}
if (x.IsPlayer() && y.IsPotion() { ... }
...
This style, while verbose is
easy to debug
easy to add cases
shows you when you have
logical/design inconsistencies or
omissions "oh what if a X is both a
player and a wall due to the
"PosessWall" ability, what then!?!"
(and then lets you simply add cases
to handle those)
Spore's cell stage uses exactly this style and has approximately 100 checks resulting in about 70 different outcomes (not counting the param reversals). It's only a ten minute game, that's 1 new interaction every 6 seconds for the whole stage - now that's gameplay value!
If I am getting your problem correctly, I would sth like
Class EventManager {
// some members/methods
handleCollisionEvent(ObjectType1 o1, ObjectType2 o2);
// and do overloading for every type of unique behavior with different type of objects.
// can have default behavior as well for unhandled object types
}
Let's say we already have a hierarchy of classes, e.g.
class Shape { virtual void get_area() = 0; };
class Square : Shape { ... };
class Circle : Shape { ... };
etc.
Now let's say that I want to (effectively) add a virtual draw() = 0 method to Shape with appropriate definitions in each sub-class. However, let's say I want to do this without modifying those classes (as they are part of a library that I don't want to change).
What would be the best way to go about this?
Whether or not I actually "add" a virtual method or not is not important, I just want polymorphic behaviour given an array of pointers.
My first thought would be to do this:
class IDrawable { virtual void draw() = 0; };
class DrawableSquare : Square, IDrawable { void draw() { ... } };
class DrawableCircle : Circle, IDrawable { void draw() { ... } };
and then just replace all creations of Squares and Circles with DrawableSquares and DrawableCircles, respectively.
Is that the best way to accomplish this, or is there something better (preferably something that leaves the creation of Squares and Circles intact).
Thanks in advance.
(I do propose a solution down further... bear with me...)
One way to (almost) solve your problem is to use a Visitor design pattern. Something like this:
class DrawVisitor
{
public:
void draw(const Shape &shape); // dispatches to correct private method
private:
void visitSquare(const Square &square);
void visitCircle(const Circle &circle);
};
Then instead of this:
Shape &shape = getShape(); // returns some Shape subclass
shape.draw(); // virtual method
You would do:
DrawVisitor dv;
Shape &shape = getShape();
dv.draw(shape);
Normally in a Visitor pattern you would implement the draw method like this:
DrawVisitor::draw(const Shape &shape)
{
shape.accept(*this);
}
But that only works if the Shape hierarchy was designed to be visited: each subclass implements the virtual method accept by calling the appropriate visitXxxx method on the Visitor. Most likely it was not designed for that.
Without being able to modify the class hierarchy to add a virtual accept method to Shape (and all subclasses), you need some other way to dispatch to the correct draw method. One naieve approach is this:
DrawVisitor::draw(const Shape &shape)
{
if (const Square *pSquare = dynamic_cast<const Square *>(&shape))
{
visitSquare(*pSquare);
}
else if (const Circle *pCircle = dynamic_cast<const Circle *>(&shape))
{
visitCircle(*pCircle);
}
// etc.
}
That will work, but there is a performance hit to using dynamic_cast that way. If you can afford that hit, it is a straightforward approach that is easy to understand, debug, maintain, etc.
Suppose there was an enumeration of all shape types:
enum ShapeId { SQUARE, CIRCLE, ... };
and there was a virtual method ShapeId Shape::getId() const = 0; that each subclass would override to return its ShapeId. Then you could do your dispatch using a massive switch statement instead of the if-elsif-elsif of dynamic_casts. Or perhaps instead of a switch use a hashtable. The best case scenario is to put this mapping function in one place, so that you can define multiple visitors without having to repeat the mapping logic each time.
So you probably don't have a getid() method either. Too bad. What's another way to get an ID that is unique for each type of object? RTTI. This is not necessarily elegant or foolproof, but you can create a hashtable of type_info pointers. You can build this hashtable in some initialization code or build it dynamically (or both).
DrawVisitor::init() // static method or ctor
{
typeMap_[&typeid(Square)] = &visitSquare;
typeMap_[&typeid(Circle)] = &visitCircle;
// etc.
}
DrawVisitor::draw(const Shape &shape)
{
type_info *ti = typeid(shape);
typedef void (DrawVisitor::*VisitFun)(const Shape &shape);
VisitFun visit = 0; // or default draw method?
TypeMap::iterator iter = typeMap_.find(ti);
if (iter != typeMap_.end())
{
visit = iter->second;
}
else if (const Square *pSquare = dynamic_cast<const Square *>(&shape))
{
visit = typeMap_[ti] = &visitSquare;
}
else if (const Circle *pCircle = dynamic_cast<const Circle *>(&shape))
{
visit = typeMap_[ti] = &visitCircle;
}
// etc.
if (visit)
{
// will have to do static_cast<> inside the function
((*this).*(visit))(shape);
}
}
Might be some bugs/syntax errors in there, I haven't tried compiling this example. I have done something like this before -- the technique works. I'm not sure if you might run into problems with shared libraries though.
One last thing I'll add: regardless of how you decide to do the dispatch, it probably makes sense to make a visitor base class:
class ShapeVisitor
{
public:
void visit(const Shape &shape); // not virtual
private:
virtual void visitSquare(const Square &square) = 0;
virtual void visitCircle(const Circle &circle) = 0;
};
What you're describing is somewhat like the decorator pattern. Which is very suitable to change runtime behaviour of existing classes.
But I don't really see how to implement your practical example, if shapes have no way to be drawn, then there's no way to change drawing behaviour at runtime either...
But I suppose this is just a very simplified example for stackoverflow? If all the basic building blocks for the desired functionality are available, then implementing the exact runtime behaviour with such a pattern is certainly a decent option.
One 'off the wall' solution you might like to consider, depending on the circumstance, is to use templates to give you compile time polymorphic behaviour. Before you say anything, I know that this will not give you traditional runtime polymorphism so it may well not be useful but depending on the limitations of the environment in which you're working, it can prove useful:
#include <iostream>
using namespace std;
// This bit's a bit like your library.
struct Square{};
struct Circle{};
struct AShape{};
// and this is your extra stuff.
template < class T >
class Drawable { public: void draw() const { cout << "General Shape" << endl; } };
template <> void Drawable< Square >::draw() const { cout << "Square!" << endl; };
template <> void Drawable< Circle >::draw() const { cout << "Circle!" << endl; };
template < class T >
void drawIt( const T& obj )
{
obj.draw();
}
int main( int argc, char* argv[] )
{
Drawable<Square> a;
Drawable<Circle> b;
Drawable<AShape> c;
a.draw(); // prints "Square!"
b.draw(); // prints "Circle!"
c.draw(); // prints "General Shape" as there's no specific specialisation for an Drawable< AShape >
drawIt(a); // prints "Square!"
drawIt(b); // prints "Circle!"
drawIt(c); // prints "General Shape" as there's no specific specialisation for an Drawable< AShape >
}
The drawIt() method is probably the key thing here as it represents generic behaviour for any class meeting the requirement of having a draw() method. Do watch out for code bloat here though as the compiler will instantiate a separate method for each type passed.
This can be useful in situations where you need to write one function to work on many types which have no common base class. I'm aware that this is not the question you asked, but I thought I'd throw it just as an alternative.