I am making a game in C++ using SFML (although that doesn't matter) and am struggling to come up with a good design. Right now I have a game class that holds level objects. When you click a button in the level, it needs to change the current game level. The only way I can figure is to pass a pointer of the game and store it in each level so I can call functions from within the level, but this seems like extremely bad structure and organization. Is this bad or not and what might be a better structure to use instead?
Here is the game class:
#include "SFML/Graphics.hpp"
#include "mainMenu.h"
#include "levelMenu.h"
class Level;
class Game {
public:
Game() { mainMenu = MainMenu(this); }
void input();
void setLevel(Level* level);
LevelMenu& getLevelMenu() { return levelMenu; }
private:
Level* currLevel;
MainMenu mainMenu;
LevelMenu levelMenu;
};
And in my mainMenu class I want to make the game class's current class change to levelMenu:
#include "game.h"
class MainMenu {
public:
MainMenu(Game* game) { this->game = game; }
void input(sf::Event event) {
if (event.type == sf::Event::MouseButtonReleased) {
game->setLevel(game->getLevelMenu());
}
}
private:
Game* game;
};
I think that looks decent, just some general suggestions:
An abstract base class Menu that handles the Game-variable for you.
Learn to use references and shared pointers of various types.
Keep interface, game mechanics and objects fairly seperate, look up the basics of MVC, model view controller.
I'd suggest that you don't worry too much about design like this, it's highly likely that you will realize that your design doesn't work or is suboptimal down the line after building the rest of the game, and then you can rewrite it at that point having learnt a lot more when building the other subsystems.
Related
I've got a serious problem with my SFML game.
I've been trying whole day to find a solution, tried diffrent things but nothing worked for me so far.
These are my .h files:
Bullet.h
#pragma once
#include <SFML\Graphics.hpp>
#include <iostream>
#include <vector>
class Bullet
{
friend class Player;
friend class Game;
float width;
float height;
float x;
float y;
std::vector<Bullet*> projectiles;
sf::RectangleShape bullet;
void draw_projectiles(sf::RenderWindow &window);
void make_projectiles();
public:
void check();
Bullet();
~Bullet();
};
Game.h
#pragma once
#include <SFML\Graphics.hpp>
#include "Player.h"
#include "Bullet.h"
#include <vector>
//#include "Enemy.h"
class Game
{
friend class Player;
sf::RenderWindow* window;
sf::Event* evnt;
Player* player;
Bullet* bullet;
public:
void Loop();
void game_func();
Game();
~Game();
};
Player.h
#pragma once
#include <SFML\Graphics.hpp>
#include <iostream>
#include "Game.h"
#include "Bullet.h"
class Player
{
sf::RectangleShape player;
Bullet* bullet;
int ammo;
float width;
float height;
int x;
int y;
float vel;
public:
void draw(sf::RenderWindow &window);
void move(sf::Event &evnt, sf::RenderWindow &window);
Player();
~Player();
};
Here come cpp files
Bullet.cpp
#include "Bullet.h"
void Bullet::check()
{
x = bullet.getPosition().x;
y = bullet.getPosition().y;
}
void Bullet::draw_projectiles(sf::RenderWindow &window)
{
for (int i = 0; i < 10; i++)
{
window.draw(projectiles[i]->bullet);
}
}
void Bullet::make_projectiles()
{
projectiles.push_back(new Bullet());
}
Bullet::Bullet()
{
std::cout << "zostal utworzony nowy obiekt" << std::endl;
width = 50;
height = 50;
bullet = sf::RectangleShape(sf::Vector2f(width, height));
bullet.setFillColor(sf::Color::Yellow);
bullet.setPosition(0, 0);
x = bullet.getPosition().x;
y = bullet.getPosition().y;
}
Bullet::~Bullet(){}
Game.cpp
#include "Game.h"
Game::Game()
{
window= new sf::RenderWindow(sf::VideoMode(1280, 720), "SFML Game",
sf::Style::Close);
player = new Player();
}
Game::~Game(){}
void Game::Loop()
{
while (window->isOpen())
{
sf::Event evnt;
while (window->pollEvent(evnt))
{
//events
if (evnt.type==sf::Event::Closed)
window->close();
player->move(evnt, *window);
window->clear();
player->draw(*window);
window->display();
bullet->draw_projectiles(*window);
}
}
}
void Game::game_func()
{
Game::Loop();
}
Player.cpp
#include "Player.h"
void Player::draw(sf::RenderWindow &window)
{
window.draw(player);
}
void Player::move(sf::Event &evnt, sf::RenderWindow &window)
{
x = player.getPosition().x;
y = player.getPosition().y;
float width = window.getSize().x;
float height = window.getSize().y;
Bullet obj;
if (evnt.type == sf::Event::KeyPressed)
{
//movement
if (evnt.key.code == sf::Keyboard::Key::W)
{
if (y <= 0)
{
return;
}
player.move(0, -1 * vel);
}
if (evnt.key.code == sf::Keyboard::Key::S)
{
if (y >= height - Player::height)
{
return;
}
player.move(0, 1 * vel);
}
if (evnt.key.code == sf::Keyboard::Key::A)
{
if (x <= 0)
{
return;
}
player.move(-1 * vel, 0);
}
if (evnt.key.code == sf::Keyboard::D)
{
if(x>width-Player::width)
{
return;
}
player.move(1 * vel, 0);
}
if (evnt.key.code == sf::Keyboard::Space)
{
obj.make_projectiles();
}
}
}
Player::Player()
{
width = 100;
height = 100;
vel = 10;
player = sf::RectangleShape(sf::Vector2f(width, height));
player.setFillColor(sf::Color::Red);
player.setPosition(sf::Vector2f(15, 20));
}
Player::~Player(){}
And main.cpp
#include <SFML/Graphics.hpp>
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>
#include "Game.h"
int main()
{
Game gme;
gme.game_func();
return 0;
}
I tried many diffrent things and can't figure it out why it's not working. Im running in on Visual Studio 15.
So here is error that I'm getting:
Exception thrown: read access violation.
std::_Vector_alloc<std::_Vec_base_types<Bullet *,std::allocator<Bullet *> >
>::_Mylast(...) returned 0x18.
I'm aware that code is not perfect and little messy but I'm just a begginer and trying to learn new stuff.
I will appreciate any help!
I answered your question in my last paragraphs, you can skip to that paragraph but I sugest you take a look at all of this. First of all you should understand how should a basic game look like in code.
The Game Logic
You can separate the game logic in 2 main functions. The initialization and the loop.
Initialization
In the initialization function, you basically load everything needed for your game to run (that is only available for small games, since loading tens of gigs of sprites in memory may not be the best solution for bigger ones. With time you'll figure out the right time to load and release resources).
The loop
This is called the main loop or the game loop. This loop should execute 3 main functions. Handle user input, update world, and render the world. This loop should execute while the game is running (i.e. while the window is open)
So your main in pseudo-c++ should look something like this:
Init();
while (window.isOpen())
{
HandleEvents(window); //user input
Update(elapsedTime);
Render(window);
}
I'll explain what the functions do, what the arguments mean and how this functions are mapped to your code. Keep in mind that every function has one specific task and only that. I won't check if the user is pressing a button while I'm drawing the sprites on the screen.
User input
Everything from button pressing and mouse clicking to pressing the exit button and resizing the window is called user input. User's actions generate the so called events, which we handle at the beginning of each loop. Now this events are window specific(you can't control the player if the window is minimized or unfocused). That means that the window generates the events (if I'm wrong with this one technically, please correct me). This is the reason that when you are handling events you need to pass the window.
Events
Before handling the events, you need to understand how sf::Event is made (see more on the sfml page). Long story short the sf::Event is an union (only one field is valid at a time). That is, if you try to access event.key when the window.pollEvent() returned an sf::Event::JoystickEvent you will get an undefined behavior (I lived a long happy life without knowing what unions are, never used them and probably never will, but they are quite an interesting concept that is worth at least reading about). Ok so an event object is created by calling window.pollEvent() and passing to it an sf::Event instance. This function will give you events from the queue until there are no more events to be given, that's when it returns false. With that in mind, your Event handling code would look something like:
sf::Event ev;
while (window.pollEvent(ev))
{
switch (ev.type)
{
//code for each type needed by your application
}
}
Keep in mind that key events do not handle real time input (sf::Keyboard::isKeyPressed does that). This means that if you want your character to move when you hold a button, handling it by events will result in a delay that can be the best explained by the way typing works(when you hold down 'a' for example the first character is written immediately, the rest of the input is delayed by a second before registering). This is a way of explaining it, but maybe not the most technical one(I'm asking for a little help here :) ). Anyway, this problem can be solved either by using the static methods of sf::Keyboard or by keeping a bool in your Player class that answers to the events KeyPressed and KeyReleased(the update will be handled based on that bool).
World Update
Here is your logic code(although player movement may also be handled in the events section, since it's based on them). Here you update your entities(move the enemy one more block based on his AI), move the sun around the map etc. Keep in mind that this has nothing to do with the drawing part, in this section you only change the state of your objects. In your game it means, after you launched a projective through an event triggered by the user, each frame you move the projectile. This code usually requires some sort of frame counting method.
Frames
A frame is an iteration of the loop, you can say that the game updates and draws itself each frame. Frames are a very important concept because they arise some issues. If the game updates itself each frame, that means that each frame the projectile is moving, so that means that his movement is dependent to the FPS your pc can run. This is a problem, because while your game may run as you want on your pc, at a stable 60 FPS rate, on mine it might run at 53, or some other random value. That means that the projectiles on my pc will move slower, and we don't want that.
Frame independent movement
This can be achieved by counting the frames. One way you can do that is by counting the seconds it passed since the last frame, with that in mind you can get the amount of space your entity needs to move in that specific frame. For example, you want to move your projectile with 100px/sec. If you have 2FPS that means that in 2 frames it needs to move 100px, so each frame moves 100 / 2 px. So the formula is finalDistance / framerate. There are more ways of doing this, but in my opinion this is the simplest to understand at the beginning. So how is this implemented in SFML? You basically keep a clock that you restart at the end of each update. getElapsedTime and restart does that, but restart returns the elapsedTime so it is better to call it once, since calling them one by one may result in different times and desyncs.
sf::Clock clock;
while (window.isOpen())
{
HandleEvents(window);
Update(clock.restart());
Render(window);
}
And you simply move your entities with move(vector * clock.getElapsedTime().asSeconds()) since sf::Vector has operator* overloaded for floats(the return type of asSeconds()).
Rendering
The rendering part may be very complicated, but sfml makes it "simple and fast". Basically it works like that: You clear the screen, you draw your entities, you display the screen. The more technical answer is the following: the window consists of 2 buffers, one visible and one hidden. The visible one is the one you see on the screen. When you call clear() you basically clear the hidden one, draw() draws also on the hidden window, and finally display() swaps the buffers.
That means that you won't see any results unless you call window.display(), and you'll get a window xp experience if you don't call clear() before drawing. So the Render function might look like this:
window.clear();
window.draw(player); //or player.draw(window) based on your implementation
//other draws
window.display();
Your question
What happens in your code is that you try to access things that don't exist. You add one projectile at a time, but each frame you draw 10 of them.
The solution
Keep a counter of your objects. Since you are using a vector that is already provided, you have std::vector::size that returns exactly what you expect, so your code will turn into something like:
for (int i = 0; i < yourProjectiles.size(); i++)
{
window.draw(yourProjectiles[i]->bullet);
}
Alternatively you can use iterators(look them up):
for (auto it = yourProjectiles.begin(); it != yourProjectiles.end(); ++it)
{
window.draw(it->bullet);
}
Memory management
You don't deallocate memory. You have to look into dynamic memory allocation. The base principle is that for every new there should be a delete. The deallocation part should be handled most of the time in the destructor of the class. I think someone may suggested to use smart pointers(std::shared_ptr) so manage your memory, but I can't recommend you that since you are at the beginning. Smart pointers are a concept you should keep in mind, but as you started out it is better to face the struggles of manual memory management(until you get used to it).
Code organizing
A class should be made for only one purpose. When you create a class called Bullet, it is expected that this Bullet will represent one projectile in your game, but when your Bullet makes "projectiles" and stores projectiles, it becomes a paranormal entity. Your bullet atm holds pointers to instances of other bullets that hold pointers to instances of other bullets. This is a total mess. Unless you want to create a graph or a tree of some sort you don't have any reason to store pointers of instances of the same class.
Too many friends
If every class is friend with every class, what is your reason of creating private fields? Friend is a very powerful concept and should be used with care, only in cases you DON'T have other options. The only reason I would avoid this keyword is the messiness it creates. It creates the same effect as public attributes. When everything is accessible from everywhere, everything can be destroyed from everywhere. When you create a small set of methods that manipulate your attributes, you know where the problem is.
Conclusion
I might suggest looking a little more into c++ and after that debug your game, or recreate it from scratch. While I know how it feels to try something new, you should always be careful to not shoot yourself in the leg, and don't be afraid to go back to the basics when you stumble into such errors. You have problems managing memory? Read more about dynamic memory allocation, do some example apps using it. Besides that I noticed you are still at the beginning with using classes. I'd say practice makes perfect. Look at other people code, even these 3rd party libraries like sfml may give you some hints on good class practices. The good thing is that it is not needed to look at the source code of those libraries, you just use their interface. If you like it, it means it is good written and you may borrow a part of that style and implement in your classes. I'll conclude this by saying that I am very happy and eager to help you via email if you have any other question regarding anything.
I believe you are attempting to access ten projectiles:
for (int i = 0; i < 10; i++)
{
window.draw(projectiles[i]->bullet);
}
But you only add one at a time:
projectiles.push_back(new Bullet());
Reading books and topics on Cocos2dx everyone seems to be teaching it like so:
Create a class that inherits from CCLayer
Within that CCLayer class, instantiate a Static SCENE
Add layout to scene
Metaphorically, it is like the Egg creates its Parent. This seems backwards, non-intuitive. Why not just do this:
Create a class that inherits from CCScene (call it GameScene)
Create another class that inherits from CCLayer (call it GameLayer)
The GameScene class is a singleton (has a singleton member: static GameScene* scene)
Instantiate the GameLayer class within the GameScene class
The GameLayer class will have the usual suspects: UPDATE, INIT, etc. and the GameScene class with have INIT and it's static self-referencing member.
While this may seem like more work, it really isn't and logically makes more sense, furthermore, it affords the developer a place, to place SCENE specific logic, and LAYER specific logic.
Are there any issues doing it this way? Why are so many teaching it backwards?
EXAMPLE:
# GameScene
#ifndef __GameScene__
#define __GameScene__
#include "cocos2d.h"
using namespace cocos2d;
class GameScene : public cocos2d::CCScene
{
public:
~GameScene();
virtual bool init();
static GameScene* scene();
CREATE_FUNC(GameScene);
};
#endif /* defined(__GameScene__) */
#include "GameScene.h"
#include "GameLayer.h"
GameScene::~GameScene() {}
GameScene* GameScene::scene()
{
GameScene *scene = GameScene::create();
GameLayer *layer = GameLayer::create();
scene->addChild(layer);
return scene;
}
bool GameScene::init()
{
if (!CCScene::init()) return false;
return true;
}
# GameLayer
#ifndef __GAMELAYER_H__
#define __GAMELAYER_H__
#include "cocos2d.h"
using namespace cocos2d;
class GameLayer : public cocos2d::CCLayer
{
public:
~GameLayer();
virtual bool init();
virtual void draw();
void update(float dt);
CREATE_FUNC(GameLayer);
};
#endif // __GAMELAYER_H__
#include "GameLayer.h"
GameLayer::~GameLayer() {}
bool GameLayer::init()
{
if (!CCLayer::init())
return false;
this->schedule(schedule_selector(GameLayer::update));
return true;
}
void GameLayer::draw() {}
void GameLayer::update(float dt) {}
And finally within the AppDelegate CPP
bool AppDelegate::applicationDidFinishLaunching()
{
// initialize director
...
...
// Create a scene
GameScene *pScene = GameScene::scene();
// Run
pDirector->runWithScene(pScene);
return true;
}
I also have a thread on this topic on cocos2dx:
http://discuss.cocos2d-x.org/t/layer-instantiates-scene/18149/4
There is a confusion between base class names and the subclass names.
For instance in the cocos2d-x wiki they subclass from Layer (CCLayer) but they name this Layer subclass GameScene even though it isn't an actual scene, it's a layer. Further down they create the actual Scene (CCScene) instance with the call to createScene, which I assume returns a generic Scene instance with the GameScene instance added to the scene:
auto scene = GameScene::createScene();
Director::getInstance()->replaceScene(scene);
So you do end up with the following hierarchy:
Scene
Layer (custom class: GameScene)
Nodes...
Now the origin of this weird naming philosophy is simply that it has been going around in the cocos2d community for ages. In very early cocos2d-iphone project templates you had a HelloWorldScene class that inherited from CCLayer. It contained a class method scene that created an instance of CCScene, created a HelloWorldScene instance and added it to the generic scene instance before returning it.
So basically this is simply a confusion due to badly named subclasses in project templates, tutorials and books. Against all rational thought the "tradition" prevailed in cocos2d-x. In cocos2d-iphone this was eventually fixed (in v2.x I believe) by renaming the template class to HelloWorldLayer.
Rodger Engelbert author of Cocos2d-x by Example, Beginners Guide responded to this question via email.
Hi Jason,
There is no need to follow the strategy used in the template. In fact
I don't know anyone who does it outside the Cocos2d-x group and I only
ever used it in the examples for the book for consistency.
A Scene is unique, and it's what the director requires to run. It's
possible to have two scenes running during transitions, but otherwise
a scene is structurally treated as One block in your architecture. You
may or may not organize your project into multiple blocks, but you
will need at least one.
But you're free to do it in any way you wish. You might use scenes
more prominently, as some developers do or use one only, for the sake
of the Director, and focus on master Layer objects. Also, keep in mind
that the generated code in the template is only trying to give you a
canvas as quickly as possible. It's not necessary the best starting
point for your project. It's up to you to make that decision.
Roger
I recently began learning OOP concepts in C++ and tried making a simple Tic-Tac-Toe game with classes. My Game class's game loop gets input from the user, which is where I am having this problem. I created an InputHandler class that the Game class has an instance of, and in the game loop I call inputHandler.input(). If the player types "restart", I want the game to restart by calling game.restart(), however my InputHandler object does not have an instance of the game. So my current solution is to pass the game by reference to the InputHandler object so I can call game.restart() from there, however this seems like bad practice from everything I have learned about OOP. Also, for every function that does something similar to this, I would need to pass the game object by reference there also. I feel like I am missing something fundamental about OOP design. Is it bad to pass the game object by reference, or is there a better way solve this problem?
//game.cpp
void Game::run() {
while(!gameOver) {
inputHandler.input(this);
}
}
//inputHandler.cpp
void InputHandler::input(Game& game) {
std::string input;
std::cin >> input;
if (input == "restart") {
game.restart();
}
}
One way to deal with special action is to pass a handler function (aka callback). The C++ way would be a std::function<void()> which can be triggered upon specific events being detected:
class SomeClass {
...
std::function<void()> d_restartHandler;
public:
void setRestartHandler(std::function<void()> handler) { d_restartHandler = handler; }
void doSomething() {
...
if (timeToRestart && this->d_restartHandler) {
this->d_restartHandler();
}
...
}
};
The function template std::function<Signature> can actually be parameterized by suitable parameters, too, by instantiating it with a suitable signature. If you feel that this approach isn't object oriented: it actually is! Internally, std::function<Signature> holds a hierarchy with a base class can a concrete class holding the actual function object to dispatch to. You can even implement something similar yourself but I'd think that would be a pointless waste of time.
Assuming you have your SomeClass instance sc and your Game instance g, you could register for a restart using something like
sc.setRestartHandler([&](){ g.restart(); });
So I am semi-new to C++, and completely new to SDL. Most of my conceptual knowledge of OOP comes from Java and PHP. So bear with me.
I am trying to work out some simple design logic with my program / soon to be side-scroller. My problem lies with trying to make my 'screen' layer (screen = SDL_SetVideoMode(...)) accessible to all my other classes; Hero class, background layer, enemies, etc. I have been loosely following some more procedural tutorials, and have been trying to adapt them to a more object oriented approach. Here is a little bit of what I have so far:
main.cpp
#include "Game.h"
#include "Hero.h"
int main(int argc, char* argv[])
{
//Init Game
Game Game;
//Load hero
Hero Hero(Game.screen);
//While game is running
while(Game.runningState())
{
//Handle Window and Hero inputs
Game.Input();
Hero.userInput();
//Draw
Game.DrawBackground();
Hero.drawHero();
//Update
Game.Update();
}
//Clean up
Game.Clean();
return 0;
}
As you can see, I have a Game class, and a Hero class. The Game class is responsible for setting up the initial window, and placing a background. It also updates the screen as you can see.
Now, since my Game class holds the 'screen' property, which is a handle for SDL_SetVideoMode, I am stuck passing this into any other class (ex: Hero Hero(Game.screen);) that needs to update to this screen... say via SDL_BlitSurface.
Now, this works, however I am getting the idea there has GOT to be a more elegant approach. Like possibly keeping that screen handler on the global scope (if possible)?
TLDR / Simple version: What is the best way to go about making my window / screen handler accessible to all my subsequent classes?
I like the way you are doing it.
Though rather than passing the screen reference I would pass a reference to a game itself. Thus each hero object knows which game it belongs too, it can then ask the game object for the screen as required.
The reason I would do this is so that in a few years when your game is a wide and successful product and you convert it for online-play you really need to do no work. The game server will be able to easily support multiple game objects, each game object hosting multiple hero objects. As each hero object wants to draw it asks the game for the screen abd updates the screen (the screen can now very from game object to game object and still work perfectly (as long as they have the same interface).
class Game
{
public:
Game(Screen& screen)
: screen(screen)
{}
virtual ~Game() {}
virtual Screen& screen() { return theGameScreen;}
void update() { /* Draw Screen. Then draw all the heros */ }
private:
friend Hero::Hero(Game&);
friend Hero::~Hero();
void addHero(Hero& newHero) {herosInGame.push_back(&newHero);}
void delHero(Hero& newHeor) {/* Delete Hero from herosInGame */}
// Implementation detail about how a game stores a screen
// I do not have enough context only that a Game should have one
// So theoretically:
Screen& theGameScreen;
std::vector<Hero*> herosInGame;
};
class Hero
{
public:
Hero(Game& game)
: game(game)
{game.addHero(*this);}
virtual ~Hero()
{game.delHero(*this);}
virtual void Draw(Screen& screen) {/* Draw a hero on the screen */}
private:
Game& game;
};
Main.
#include "Game.h"
#include "Hero.h"
int main(int argc, char* argv[])
{
//Init Game
Screen aScreenObject
Game game(aScreenObject);
//Load hero
Hero hero(game); // or create one hero object for each player
//While game is running
while(game.runningState())
{
//Handle Window and Hero inputs
Game.Input();
Hero.userInput();
//Update
Game.update();
}
//Clean up
// Game.Clean(); Don't do this
// This is what the destructor is for.
}
I don't know if it's elegant, but what I do for the side-scrolling game I'm making is to make a show() function in each class than draws to the screen, and passing the screen handle as a parameter. Then whenever I want to draw something to the screen I just do foo.show(screen). The screen handle is in main().
The first, and honestly, easiest solution, is to use a global variable. Yes, yes, yes, everyone says global variables are horrible, but in this situation, it's perfectly fine.
The other solution, which is a bit more work, but can result in somewhat more portable code, is to encapsulate your drawing functions into a single, static class. This way, you can draw to the screen directly without having to pass around a variable, or have to lie awake at night thinking the code review police will get you because you used a global variable. Plus, this can potentially make it easier if you ever decide to port your game to a new library. Some quick and dirty pseudocode:
class Drawing
public:
static void Draw(x, y, sdl_surface graphic, sdl_rect & clip=null);
static void init(sdl_surface & screen);
private:
sdl_surface screen;
void Drawing::Draw(x, y, sdl_surface graphic, sdl_rect & clip=null)
{
sdl_blit(x, y, graphic, clip);
}
void Drawing::init(sdl_surface & screen)
{
this.screen=screen;
}
It sounds like you're looking for a way to implement the Singleton design pattern, where you would have a single Screen object. If you know you're only ever going to have a single Screen object it should work fine.
In this case you would implement a static method on the Game class:
class Game
{
public:
static Game *GetTheSceenObject();
private:
static Screen *theScreen; // details of initialisation ommitted
}
that would return a pointer to the single Screen object.
If there is a possibility that you'll end up using multiple SDL screens, though, it may be worth creating a Draw() method in your Hero class that is responsible for drawing the hero on each of the Screens managed by the Game class by iterating through a list provided by the Game class.
That functionality could be contained in the methods of a common DrawableThingy class that Hero and Enemy are derived from.
Passing Game.screen around is more OO (though it might be better to have a getter function) than having one instance of it that can be accessed from any class, because if you have one global version, you can't have more than one Game.screen at any one time.
However if you know you'll only ever need one in the entire lifetime of the program, you might consider making Game::Screen() a public static function in the Game class that returns a private static member screen. That way, anyone can call Game::Screen() and get the screen.
Example (assuming ScreenType is the type of screen and that you store a pointer to it):
class Game {
public:
static ScreenType* Screen() {
if (!screen)
screen = GetScreenType(args);
return screen;
}
}
private:
// if you don't already know:
// static means only one of this variable exists, *not* one per instance
// so there is only one no matter how many instances you make
// the same applies to static functions, which you don't need an instance to call
static ScreenType* screen;
};
// and somewhere in a .cpp file
ScreenType* Game::screen = NULL;
// and you use it like this
ScreenType* scr = Game::Screen();
// use scr
In most or all object oriented games, each class relies on not just its own but parent classes. How is this class connection implemented in C++? Do you just add a pointer for the parent class you need or is there a better way?
For example a football game, when the person class clicks it ask the scene class if he is kicking any balls, and if he is then move it. I hope this is understandable and not too abstract.
I don't think passing along the parent in a constructor is a good idea. Instead, you should be using a class that maintains a list of all game elements and facilities interactions between them; for instance, the Game class illustrated below would check for collisions between any two players and if it's detected tell each of them that they were hit and by who.
I'm not sure if this will benefit you at all, but I typed it up for my initial response so I might as well submit. Note that all of this is still relevant if you're talking about a text-only game, just ignore the allusions to graphics in that case. Game design is based around a continuous game loop, and can be thought of very simply as:
while(true)
for each tick:
react to user input
update player, enemies, objects, etc.
end while
Where "tick" is every iteration of the game clock, however you choose to implement it--based on the fps, each second, whatever. In your example, the user clicks the football, the game sees the click and tells the football to move. To do this very simply, maintain a list all of all of the game elements within a class that maintains the state. To illustrate, here are is a very basic way you could implement this:
class Game {
vector<GameElement> elements;
Football football;
Player currentPlayer;
Game() {
this.football = new Football();
}
void update() {
for e in elements:
e.update();
// Once every element has been updated for the current tick, redraw them on the screen
screen.redraw();
}
void addElement(GameElement e) {
elements.add(e);
}
}
class GameElement {
int posx, posy; // screen coordinates
void paint() {}; // method to draw this element to the screen
virtual void update();
}
class Football: public GameElement {
bool kicked;
int anglex, angley;
double velocity;
void update() {
if(kicked){
// update position, angle, velocity; slow it down, check for bounce, whatever
posx = new x position;
posy = new y position;
if(velocity == 0)
kicked = false;
}
paint(); // call the paint method after the new position has been found
}
}
Assume you have another class that inherits from GameElement, Player, with a method kick(football) that sets the passed football into motion--i.e., sets kicked=True. So to initialize the game, you'd set it up with something like:
Game game = Game();
game.add(new Football());
game.add(new Player());
while(true) {
if(user_input==X)
game.currentPlayer.kick(football);
game.update();
sleep(1);
}
This could be changed to maintain, for example, layers instead of the entire game, then a higher level class could call update of each layer in order, allowing things to be painted over each other and children to only interact with siblings. There are a lot of possibilities.
Ran into similar questions working on a poker game: Here's the way I did it:
In your example, add a scene * the_scene to the constructor of person. Then, when person is initialized pass it a pointer to scene. Since you said parent and child, if the parent Is scene then it would just use "this" and it would send the address of the parent.
Then again, it seems like that's how you were going to do it anyway. One more thing, if you need person to interact with more than one class that is not directly inside it you can make some kind of container class that would store the pointers to all of them and just pass person that one to avoid having a constructor with too many parameters.