Organization of code for a game using SDL - c++

I've been using SDL for some days now, and I decided after following some tutorials to start developing my own clone of Galaga. However, I had some difficulty trying to find a proper layout for my code.
For example, I have a Spaceship class defined as follows:
class Spaceship : public Sprite
{
public:
Spaceship(SDL_Surface *surface);
Spaceship(const char *filename);
void handleEvent(SDL_Event *event);
};
where Sprite is a base class that holds the position on the screen and so on.
My constructor would be something like:
Spaceship::Spaceship(SDL_Surface *surface) :
Sprite(surface)
{
m_y = Game::screenHeight() - m_surface->h; //positions the ship at the bottom
}
From what I've seen it's not possible to use Game::screenWidth() [static class] because I'd need to include "game.h", which is basically the main game class and includes "spaceship.h", creating basically an infinite loop (I've tried using #ifndef etc. with no success).
Is it possible to achieve this kind of result?
EDIT: I found a way to overcome the problem (I just added the "game.h" include in the cpp file and not in the header file).

If you only want to store pointers or references to those objects, then you can forward-declare one or both of the classes with class Game; or class Spaceship;. This is also fine if they take these objects as parameters or return them (with some exceptions, afaik).
If you actually want both to have a member of the other, then this is not possible, as each object would then have a copy of itself inside it.

You need to break a cycle in your dependency graph.
For example, one can add a field to your Spaceship class which saves a screen height.

Related

How to remove this circular dependency? [duplicate]

This question already has answers here:
Resolve build errors due to circular dependency amongst classes
(12 answers)
Closed 3 years ago.
What am I trying to do?
I am trying to make game. Instead of having global "managers"
, I decided that I could pass all managers down the hiearchy. My plan was to make "Application" class, that would hold all "manager" objects, like Window, Asset Manager, etc... Application would then pass it's reference to SceneManager, SceneManager would pass Application reference to Scene and Scene whould then pass it to GameObjects, so it would be possible to call any manager from any level of hiearchy.
The problem is, my Application holds SceneManager. And SceneManager needs to pass Application reference to Scene.
Diagram:
Code: (Simplified)
Application:
Application relies on SceneManager, because it needs to hold it and update it.
#include "SceneManager"
class Application {
public:
SceneManager& getSceneManager();
void update();
void quit();
enter code here
private:
SceneManager sceneManager;
// Input, Window, Asset loaders etc
};
SceneManager:
SceneManager relies on Application, because it needs to pass Application reference to the current Scene.
#include "Application"
class SceneManager {
public:
void updateCurrentScene(Application& application);
// Handling scene switching etc.
enter code here
private:
Scene currentScene;
};
In scene it would be then possible to:
void onUpdate(Application& application) {
application.getSceneManager().doSomething();
}
Is it possible to remove circular reference and still have this "passing the managers down"?
How would you do it?
You can “forward declare” the classes in the header files.
class Application;
Instead of the full #include.
You will need the #include in the cpp file (or really before you do anything with the forward declared class).

How would I separate this class?

I'm learning computer graphics and OpenGL, and I load models from my own binary format with a JSON manifest file to keep track of the assets.
The Model class I have right now keeps track of the OpenGL objects necessary to draw it with, as well as handling the processing of the 3D model files:
class Model
{
public:
Model(const std::string &filename);
// read the manifest
// load the appropriate binary files
// finally make the OpenGL objects this class keeps track of
// ... etc, like draw()
private:
// handles for various OpenGL objects
}
I would like to separate the file processing from the bookkeeping of OpenGL graphics stuff as I feel like that's too much responsibility for a single class. How would I go about doing that?
I thought about making a ModelLoader class, but I don't think there's any state that needs keeping track of in order to load this. So maybe I should make it a function inside a ModelLoader namespace. I played around with it but ended up with:
// ModelLoader.hpp
#include "Model.hpp"
namespace ModelLoader
{
Model load(const std::string &filename);
}
// ModelLoader.cpp
#include "ModelLoader.hpp"
Model ModelLoader::load()
{
return Model();
}
// Model.hpp
class Model;
namespace ModelLoader
{
Model load();
};
class Model
{
friend Model ModelLoader::load();
public:
// ... etc, like draw()
private:
Model(const std::string &filename); // accessible only through ModelLoader::load()
// handles for various OpenGL objects
}
There was a circular dependency between Model and ModelLoader, and what I have up there was the only way I could get it to compile. But as you can see, that kind of defeats the purpose of the declarations inside ModelLoader.hpp, plus it's duplicated code. I'm still not too good with C++ and object oriented design. Should I just go with what I had before? If I really wanted to separate file loading from bookkeeping, how should I do it? What's wrong with my attempts?
I'd recommend a slightly different approach. Make your class know how to serialize and deserialize itself from a stream.
That way you can use string streams, file streams, network streams, etc.

Void pointer to object pointer

I'm developing a GUI for a mbed microcontroller in C++ and I have a few problems.
The situation is:
Different widget classes (button, slider...) with a widget virtual parent function. Then a virtual function layout with also classes like (gridLayout, ...). The layout has functions like layout.add(*widget) to add the widget pointers to a vector.
Then I have a controller function that handle the touch events and uses the current active layout to check what the correct widget is in the layout at the x,y coordinates of the touch.
Now I want to add a pointer pointed to a layout in the widget class so the controller class can possible change the activeLayout if this is required. There is also a function pointer so the controller can run a certain function when a widget is used.
Now the problem: I would like to do something like this:
Button::Button(char* text_, int color_, void *function_, Layout *layout_): text(text_), color(color_), function(function_), layout(layout_){}
But then I need to include the layout class, and the layout class already includes the widget class --> error! What is the easiest way to do this? I already tried void* pointers and then a static cast to Layout but that didn't work.
I also need to include a TFT class in every widget and layout, what would be the easiest way to do that? Now I just have a Display.h with in it:
#ifndef DISPLAY_H
#define DISPLAY_H
static SPI_TFT Screen(LCD_SDI, LCD_SDO, LCD_SCK, LCD_CS,"Screen");
#endif
But I don't really think this is the correct way to do something like this.
Thank you very much for your help!
The solution was: using forward declaration in each class. class Layout;
Then for the TFT class i had to use extern SPI_TFT Screen; and in my main.cpp I did the SPI_TFT Screen(LCD_SDI, LCD_SDO, LCD_SCK, LCD_CS,"Screen");
(thank you very much t.niese, Lightness Races in Orbit and Jan Hudec)

How to layout a program?

I'm making an Arkanoid clone. This is the program layout I came up with:
source.cpp // few lines
App class // has constants APP_WIDTH and APP_HEIGHT
Ball class // has constant RADIUS
Brick class
Paddle class
Now I want to place the ball at the center of the window at the beginning of the game. Normally I would accomplish it like this:
Ball::Ball (App &app)
{
circle.setPos(app->WINDOW_WIDTH/2-RADIUS/2,app->WINDOW_HEIGHT/2-RADIUS/2)
}
But the ball class doesn't know anything about the App!
Do I need to make APP_WIDTH and APP_HEIGHT global variables?
Or do I need to turn the current app layout upside down, so that Ball class has #include "app.hpp" statement?
EDIT: Or do I need to declare ball, brick and paddle classes inside the app class? But then where I define them? Inside the same app class? Then the header gets too big!
And maybe there are some good tutorials on program layout topic on the internet? I haven't found any...
QUESTION 2:
Why do classes need protected variables if "there is no reason that ball would know anything about app class"
Since the issue seems to be that "Ball doesn't have any access to the private members of app class.", than maybe you want to make a getter.
A getter is a public method that returns the value of a private field.
If you do that, you can access the values of those members like so
circle.setPos(app->GetWidth()....
Your getter might look similar to the following
public int GetWidth()
{
return this.APP_WIDTH;
}
There is no reason for the game objects to know anything about the App they are part of. When it needs any information from App, it should receive them from App directly. This can happen either through setter-methods (recommended when properties can be changed by the App later, like the position of the ball) or in the constructor (recommended for things which don't change, like the positions of blocks).
Ball should have a SetPosition(x,y) which app invokes with the above calculation. Internally, this SetPosition would set the circle like above, so ball knows nothing about app.

C++/Qt - multiple inheritance with QGraphicsItem doesn't work as expected

I recently met a strange problem of my little program and it would be great if you help me to get the reason of this behavior.
My task is quiet simple - I want to use Qt Graphics Framework to show some objects and I want Box2D to calculate bodies position. So my class hierarchy looks like the following:
I have 1 base abstract class B2DObject. It contains some Box2D staff + some common parameters for its successors (names, some flags, etc.). It also has couple of pure virtual functions that will be reimplemented in successor classes.
Then I implement some classes that represent basic shapes: circles, rectangles, polygons, etc. I am doing it in the following way:
class ExtendedPolygon : public B2DObject, public QGraphicsPolygonItem { ... };
class ExtendedCircle : public B2DObject, public QGraphicsEllipseItem { ... };
etc.
(for those who are not familiar with Qt, QGraphics***Item is inherited from QGraphicsItem).
Also I inherited QGraphicsScene and reimplemented its mousePressEvent. In this function I request an object placed at some point on the screen using QGraphicsScene::itemAt function (which returns QGraphicsItem*), convert it to B2DObject* and try to get some internal field from this object:
void TestScene::mousePressEvent (QGraphicsSceneMouseEvent *event)
{
QGraphicsItem* item = itemAt (event->scenePos ());
if (item)
{
B2DObject* obj = reinterpret_cast < B2DObject* > (item);
QString objName = obj->Name(); // just for example,
// getting other internal fields has
// the same effect (described below)
// use retrieved field somehow (e.g. print in the screen)
}
// give the event to the ancestor
}
Unfortunately, dynamic_cast will not work here because these classes are completely unrelated.
Then I create necessary objects and add it to my scene:
ExtendedPolygon* polygon = new ExtendedPolygon (parameters);
polygon->setName (QString ("Object 1"));
...
TestScene scene;
scene.addItem (polygon);
(for those who are not familiar with Qt, here is the prototype of the last function:
void QGraphicsScene::addItem(QGraphicsItem *item);
I guess it just stores all items in internal index storage and calls QGraphicsItem::paint (...) when item needs to be repainted. I suppose QGraphicsScene doesn't make any significant changes to this item).
So my problems start when I run the program and click on an item on the screen. TestScene::mousePressEvent is called (see a piece of code above).
Mouse click position is retrieved, item is found. Casting works fine: in the debugger window (I'm using Qt Creator) I see that obj points to ExtendedPolygon (address is the same as when I add the item to the scene and in the debugger window I can see all the fields). But when I get some field, I receive garbage in any case (and it does not matter, what I'm trying to get - a QString or a pointer to some other structure).
So first of all, I would like to get any advice about my multiple inheritance. In 95% of cases I try to avoid it, but here it is very effective in the programming point of view. So I would appreciate it if you provide me with your point of view about the architecture of the classes hierarchy - does it even suppose to work as I expect it?
If on this level everything is quite fine, then it would be great if someone gets any idea why doesn't it work.
I have some ideas about workaround, but I really would like to solve this problem (just in order not to repeat the same error anymore).
Looks like I've found the root cause of my problem. It was just lack of knowledge regarding how multiple inheritance really works on data layer.
Let's assume that we have 2 basic classes, A and B. Each of them provides some internal data fields and some interfaces.
Then we create a derived class AABB, inheriting both A and B:
class AABB : public A, public B {...}
AABB could add some additional data fields and reimplement some of the interfaces, but it is not necessary.
Let's create and object of class AABB:
AABB* obj = new AABB ();
For example, obj points at address 0x8416e0. At this address starts data from ancestor class A. Data from ancestor class B starts with some offset (it should bw equal to sizeof (A)), for example, at 0x841700.
If we have some function f (B* b), and if we pass a pointer at AABB object to that function (like this: f (obj), obj is created above), actually not obj start address is passed, but rather a pointer at a start of B data section of AABB object.
Thus this misunderstanding of multiple inheritance inner works has led me to the problem I've got.
I guess Qobjects and multiple inheritance has been already treated. As an example: QObject Multiple Inheritance