This question already has answers here:
Resolve build errors due to circular dependency amongst classes
(12 answers)
C++ circular include
(4 answers)
Closed 3 years ago.
I am working on a game, and right now I have followed a GameState manager tutorial but I'm not sure why isn't the code working. It might be because it's an older version of c++ in the tutorial but I can't seem to find how can I fix it.
#pragma once
#include "GameEngine.h"
class GameState
{
public:
virtual void Init() = 0;
virtual void Cleanup() = 0;
virtual void SplashScreen() = 0;
virtual void Pause() = 0;
virtual void Resume() = 0;
virtual void HandleEvents(GameEngine *game) = 0;
virtual void Update(GameEngine *game) = 0;
virtual void Draw(GameEngine *game) = 0;
void ChageState(GameEngine* game,
GameState* state) {
game->ChangeState(state);
}
protected: GameState() {}
};
If I don't game the GameEgine *game and GameState *state and remove every line that uses them my program works okay, my window appears but I can't change the game states which is really important.
If nobody has an answer that's okay :)
EDIT: I forgot to show the GameEngine.h file
#pragma once
#include "GameState.h"
#include "include.h"
class GameEngine
{
public:
Recources recource;
void Init(std::string name, int x, int y);
void Cleanup();
void SplashScreen();
void ChangeState(GameState* state);
void PushState(GameState* state);
void PopState();
void HandleEvents();
void Update();
void Draw(sf::RenderWindow &widnow);
bool Running() { return m_running; }
void Quit() { m_running = false; }
private:
// the stack of states
std::vector<GameState*> states;
bool m_running;
};
Variable game(which you pass to function) in ChangeState must be object GameEngine(which has function ChangeState,which is different from ChangeState of GameState), so you can call game->ChangeState, so if GameEngine object which you use have neccessary function and you pass correct arguments, all will be fine.
Related
This question already has answers here:
What is object slicing?
(18 answers)
Range based loop: get item by value or reference to const?
(5 answers)
Closed 10 months ago.
What am I doing?
I'm trying to do some basic inheritance for the game I'm working on. The idea is to have a base Entity class that the Player will inherit from. The Entity class has a virtual update or think method that each child will override to fit it's needs.
This is how the engine handles the update loop:
void Engine::update() {
for (Entity entity : entities) {
entity.update(deltaTime);
}
}
The code:
Entity.hpp
#pragma once
#include "Position.hpp"
#include "AssetManager.hpp"
#include "Logger.hpp"
#define SPATIAL 1
#define VISUAL 1 << 1
class Entity {
public:
Entity(Position *position, const char *visualPath);
int flags;
const char *visualPath;
Position position;
virtual void update(float deltaTime);
};
Entity.cpp
#include "Entity.hpp"
Entity::Entity(Position *position, const char *visualPath) {
flags = 0;
if (position) {
flags |= SPATIAL;
this->position = *position;
}
if (visualPath) {
flags |= VISUAL;
this->visualPath = visualPath;
}
}
void Entity::update(float deltaTime){
Logger::log("No update method");
};
Player.hpp
#pragma once
#include "../Entity.hpp"
#include "../Logger.hpp"
class Player : public Entity {
public:
Player();
void update(float deltaTime) override;
};
Player.cpp
#include "Player.hpp"
Player::Player() : Entity(new Position(0, 0), "assets/player.png") {}
void Player::update(float deltaTime) {
this->position.x += 10;
Logger::log("Player says hi");
}
What's the issue?
Even tho I have overridden the update method on the Entity within Player, Player still prints "No update method". It seems the override didn't do anything.
Change this:
void Engine::update() {
for (Entity entity : entities) {
entity.update(deltaTime);
}
}
To this:
void Engine::update() {
for (Entity& entity : entities) {
entity.update(deltaTime);
}
}
In the original implementation, your for loop makes a copy of the item in entities. You probably didn't want that, but more importantly, entity is just a copy of the base class, so the derived class information is lost. Pass by reference to avoid this issue and other bugs.
I need to create a thread to run the Networking portion of my game. I would prefer to use SFML threads as my compiler doesn't yet support C++11 threads. However the class which contains the thread is created with make_shared(). Here is the code:
Game.cpp (not all the code just the declaration of GameScreen)
std::shared_ptr<Screen> Game::screen = std::make_shared<GameScreen>();
Screen is just a base class containing pure virtual functions. You should be able to figure out which ones are virtual based off the override keywords.
GameScreen.h
#ifndef GAMESCREEN_H
#define GAMESCREEN_H
#include <SFML/Graphics.hpp>
#include "Events.h"
#include "Screen.h"
#include "Map.h"
#include "Network.h"
class GameScreen : public Screen
{
public:
GameScreen();
void handleInput(sf::RenderWindow&) override;
void update(sf::RenderWindow&, sf::View&) override;
void render(sf::RenderWindow&) override;
private:
Map m_map;
Network network;
Events eventManager;
sf::Thread networkThread;
};
#endif // GAMESCREEN_H
GameScreen.cpp
#include <memory>
#include <iostream>
#include "GameScreen.h"
#include "Game.h"
GameScreen::GameScreen()
: networkThread(network.receive(eventManager))
{
network.Connect();
}
void GameScreen::handleInput(sf::RenderWindow& window)
{
/*Code*/
}
void GameScreen::update(sf::RenderWindow& window, sf::View& view)
{
/*Code*/
}
void GameScreen::render(sf::RenderWindow& window)
{
/*Code*/
}
Network.cpp (receive function only)
void Network::Recieve(Events& eManager)
{
sf::Packet m_rPacket;
m_socket.receive(m_rPacket, m_serverIP, port);
m_rPacket >> /*Data*/
eManager.addEvent(tmp);
}
You can use this in the constructor's initialization list:
MyClass::MyClass()
: AClass(&MyFunction(*this))
{
/*do stuff*/
}
However, this doesn't make sense in your example, because you are trying to pass a pointer to MyFunction (or its non-existent return value) to AClass(), and you can't quality a pointer with parameters. You can only pass parameters to MyFunction() when actually calling MyFunction(). Are you sure you don't actually mean something more like this instead:
MyClass::MyClass()
: AClass()
{
/*do stuff*/
MyFunction(*this);
}
Without seeing what AClass() actually is, or what it expects as input, it is difficult to know for sure what you are trying to do.
Update clearly you have not read the SFML documentation or SFML Tutorial on threading. The Thread constructor takes a pointer to a function/method as one input parameter, and an optional input value for the function/method as a separate parameter. Try this instead:
class MyClass : public sf::Thread
{
private:
static void MyFunction(MyClass &cls);
public:
MyClass();
};
MyClass::MyClass()
: sf::Thread(&MyClass::MyFunction, *this)
{
/*do stuff*/
}
void MyClass::MyFunction(MyClass &cls)
{
/*do stuff with 'cls'*/
}
Or this, as you can use a non-static class method with an SFML thread:
class MyClass : public sf::Thread
{
private:
void MyFunction();
public:
MyClass();
};
MyClass::MyClass()
: sf::Thread(&MyClass::MyFunction, *this)
{
/*do stuff*/
}
void MyClass::MyFunction()
{
/*do stuff with 'this'*/
}
Update: based on your new code, you are still not even close to constructing the sf::Thread object correctly (did you read the documentation/tutorial I linked to?). Also, your thread needs access to multiple objects owned by GameScreen, so you can't pass them all to the sf::Thread constructor. You need to do something more like this instead:
class GameScreen : public Screen
{
public:
GameScreen();
...
private:
...
Network network;
Events eventManager;
sf::Thread networkThread;
void networkThreadFunc();
};
GameScreen::GameScreen()
: networkThread(&GameScreen::networkThreadFunc, *this)
{
network.Connect();
}
void GameScreen::networkThreadFunc()
{
network.Receive(eventManager);
}
I'm new with cocos2d-x. I'm getting error in this line :
Button* btnRegister=static_cast<Button*>(Helper::seekWidgetByName(m_pLayout, "btnRegister"));
btnRegister->addTouchEventListener(CC_CALLBACK_0(LoginScene::GameLoginTest, this));//get error no matching member function for call to addtoucheventlistener
I don't know why cause i have already create one constructor below
Please help, what should i do to fix that
File LoginScene.h
#include "cocos2d.h"
#include "cocos-ext.h"
#include "CocosGUI.h"
USING_NS_CC;
USING_NS_CC_EXT;
using namespace ui;
class LoginScene : public Scene
{
public:
LoginScene(bool pPortrait=false);
~LoginScene();
// there's no 'id' in cpp, so we recommend returning the class instance pointer
//static cocos2d::Scene* createScene();
// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
//virtual bool init();
virtual void onEnter();
virtual void onExit();
// a selector callback
virtual void GameLogin();
void GameLoginTest(Ref* pSender,TouchEventType type);
//virtual void runThisTest()=0;
protected:
Layer* m_pUILayer;
Layout* m_pLayout;
int authenticate();
//int authenticate(const char* username, const char* password);
// implement the "static create()" method manually
//CREATE_FUNC(LoginScene);
};
File LoginScene.cpp
#include "LoginScene.h"
#include "cocostudio/CCSSceneReader.h"
#include "cocostudio/CCSGUIReader.h"
#include "cocostudio/CCActionManagerEx.h"
#include "LoadingScene.h"
#include "MainScene.h"
#include "curl/curl.h"
LoginScene::LoginScene(bool pPortrait):m_pUILayer(NULL),m_pLayout(NULL)
{
Scene::init();
}
LoginScene::~LoginScene()
{
}
void LoginScene::onEnter()
{
Scene::onEnter();
m_pUILayer=Layer::create();
m_pUILayer->scheduleUpdate();
this->addChild(m_pUILayer);
m_pLayout=dynamic_cast<Layout*>(cocostudio::GUIReader::getInstance()->widgetFromJsonFile("LoginScene.json"));
m_pUILayer->addChild(m_pLayout);
Button* btnLogin = static_cast<Button*>(Helper::seekWidgetByName(m_pLayout, "btnLogin"));
btnLogin->addTouchEventListener(CC_CALLBACK_0(LoginScene::GameLogin, this));//it's okay
Button* btnRegister=static_cast<Button*>(Helper::seekWidgetByName(m_pLayout, "btnRegister"));
btnRegister->addTouchEventListener(CC_CALLBACK_0(LoginScene::GameLoginTest, this));
//get error no matching member function for call to addtoucheventlistener
}
void LoginScene::GameLogin()
{
auto scene=LoadingScene::createScene();
Director::getInstance()->pushScene(scene);
}
void LoginScene::GameLoginTest(Ref* pSender,TouchEventType type)
{
if (type==TOUCH_EVENT_ENDED)
{
if (authenticate()==1)
{
auto scene=MainScene::createScene();
Director::getInstance()->pushScene(TransitionFade::create(2.3f, scene));
}
}
}
for LoginScene::GameLoginTest, maybe you can use CC_CALLBACK_2,like this:
btnRegister->addTouchEventListener(CC_CALLBACK_2(LoginScene::GameLoginTest, this));
The prototype of the functor you are sending is
(LoginScene* , Ref* , TouchEventType)
Since LoginTest is not a static method, it has an implicit parameter called "this".
You have two options :
make the function static
change the prototype to just TouchEventType (I believe that Ref* is meant to be "this").
class Game {
private:
string title;
bool running;
State currentState;
public:
sf::RenderWindow window;
void setup();
void run();
};
I have a variable called currentState. This is State:
#ifndef STATE_HPP
#define STATE_HPP
using namespace std;
class State {
private:
public:
void start();
void update();
void render();
};
#endif
And then I have a class called PlayState, which inherits State:
#ifndef PLAY_STATE_HPP
#define PLAY_STATE_HPP
#include <SFML/Graphics.hpp>
#include "Game.hpp"
#include "State.hpp"
using namespace std;
class PlayState : public State {
private:
sf::CircleShape shape;
Game game;
public:
PlayState();
void start();
void update();
void render();
};
#endif
On my Game.cpp, I am creating currentState, by doing:
currentState = PlayState();
The problem is, though, that it's not working. currentState.update() is state.update(). It seems that I am not overriding the State methods when I create PlayState.
Here's PlayState.cpp:
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <stdio.h>
#include "PlayState.hpp"
PlayState::PlayState() {
printf("heyyy\n");
}
void PlayState::start() {
shape.setRadius(100.f);
shape.setOrigin(20.0f, 20.0f);
shape.setFillColor(sf::Color::Green);
}
void PlayState::update() {
sf::Event event;
while (game.window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
game.window.close();
//running = false;
}
}
printf("here\n");
}
void PlayState::render() {
printf("here\n");
game.window.clear();
game.window.draw(shape);
game.window.display();
}
Any ideas about how I can 'override' those methods? Thank you.
EDIT
I had to make State.cpp functions virtual so that they can be overriden.
I also had to define State *currentState as a pointer and create PlayState with "currentState = new PlayState();".
Also, now I access .update and .draw with ->update() and ->draw().
Two problems. As #McAden said, the functions in State that are to be overridden in PlayState need to be marked virtual. The other problem is that the data member currentState in Game has type State. When you assign an object of type PlayState to it, it gets the State part of the PlayState object, but not the derived parts. This is called "slicing". To prevent it, make currentState a pointer to State, and when you create that PlayState object, assign its address to the Game object's currentState.
What you're looking for is the concept of virtual functions.
Wikipedia entry
State needs:
virtual void update();
PlayState needs:
void update();
You need to make your function's with the virtual modifier ie.
virtual void Update();
When calling currentState->Update() this will call the topmost overridden function, if you desire to call any of the parent classes functions inside of the classes methods simply specify ie. State::Update(); when calling the function.
i need help with my attempt at writing a reusable game engine. it's not the best engine, but i definitely think it will be reusable once i am done. i am not asking for code or to be spoonfed, but i am asking for some advice :-).
my current layout:
i have an engine class, a game class, and an event manager class. the engine class extends the event manager class, and the game class extends the engine class. here is my current code for these 3 classes (ignore the Graphics class--it is just a reusable class i use to avoid rewriting fullscreen, initialize, and resize screen functions).
ENGINE.HPP
#ifndef _ENGINE_HPP
#define _ENGINE_HPP
#pragma once
#include <SDL/SDL.h>
#include "event_manager.hpp"
enum
{
ENGINE_SUCCESS = 0,
ENGINE_INITIALIZATION_ERROR
};
class Engine : public EventManager
{
public:
Engine();
virtual ~Engine();
int exec();
void handle_event(SDL_Event *);
void update_engine();
virtual bool init();
virtual void render();
virtual void update();
virtual void clean();
bool running_;
};
ENGINE.CPP
#include "./engine.hpp"
Engine::Engine()
{
running_ = false;
}
Engine::~Engine()
{
}
int Engine::exec()
{
if (!init())
{
clean();
return ENGINE_INITIALIZATION_ERROR;
}
SDL_Event event;
while (running_)
{
while (SDL_PollEvent(&event))
handle_event(&event);
update();
render();
}
clean();
return ENGINE_SUCCESS;
}
void update_engine()
{
}
void handle_event(SDL_Event *event)
{
EventManager::handle_event(event);
}
bool init() {return true;}
void render() {}
void update() {}
void clean() {}
EVENT_MANAGER.HPP
#ifndef _EVENT_MANAGER_HPP
#define _EVENT_MANAGER_HPP
#pragma once
#include <SDL/SDL.h>
class EventManager
{
public:
EventManager();
virtual ~EventManager();
virtual void handle_event(SDL_Event *);
// events here
virtual void event_exit();
};
#endif
EVENT_MANAGER.CPP
#include "./event_manager.hpp"
EventManager::EventManager()
{
}
EventManager::~EventManager()
{
}
void EventManager::handle_event(SDL_Event *event)
{
switch (event->type)
{
case SDL_QUIT:
event_exit();
break;
}
}
void on_exit() {}
GAME.HPP
#ifndef _GAME_HPP
#define _GAME_HPP
#include "./engine.hpp"
#include "./entity.hpp"
#include "./graphics.hpp"
class Game : public Engine
{
public:
Game();
bool init();
void render();
void update();
void clean();
private:
Graphics g;
};
#endif
GAME.CPP
#include "./game.hpp"
int main(int argc, char **argv)
{
Engine engine;
return engine.exec();
}
Game::Game() {}
bool Game::init()
{
if (!g.init(800, 600, 32, g.screen_flags()))
{
return false;
}
SDL_WM_SetCaption("Title", NULL);
return true;
}
void Game::update()
{
Engine::update_engine();
}
void Game::clean()
{
SDL_FreeSurface(g.screen_);
SDL_Quit();
}
void Game::render()
{
SDL_Flip(g.screen_);
}
i am getting this error:
engine.cpp: In function ‘void handle_event(SDL_Event*)’:
engine.cpp:40: error: cannot call member function ‘virtual void
EventManager::handle_event(SDL_Event*)’ without object
why is this happening? shouldn't i be able to do EventManager:: if the I did
class Engine : public EventManager
???
that is the only error i get, i am sure it is something simple. now i need a little bit of advice.
instead of handling events like
void Engine::event_exit()
in the engine, i'd rather do it in the game class.
class Game : public Engine
void Game::event_exit()
if that doesn't make sense, notice how i made Engine extend EventManager, and my Game class extends Engine
class Engine : public EventManager
class Game : public Engine
would it work if i called the snippet above these ^ two snippets? i can't test it because i get that error.
Happens to the best of us, but I think it's just a matter of forgetting to specify namespaces. When you implement the functions in engine.cpp, you forgot to prepend Engine::, so the code should be:
void Engine::update_engine()
{
}
void Engine::handle_event(SDL_Event *event)
{
EventManager::handle_event(event);
}
It's a classic case of C++ error messages not really telling you the root of the error.
A short explanation, just in case:
The compiler tried to compile the function void handle_event(SDL_Event *event), and saw a call to a method EventManager::handle_event(event);. Since the compiler thought the function was not part of the Engine class, it would expect you to call the method of a particular instance of the EventManager class, i.e.
someEventManager->handle_event(event);
As soon as you specify that the implementation you wrote is that of a method, belonging to the class Engine, the compiler essentially deduces:
void Engine::handle_event(SDL_Event *event)
{
this->EventManager::handle_event(event);
}
And therefore is happy.