C++ Event handler with derived classes through a base class array - c++
I have been trying to make a game engine for some time, and for the most part it has been turning out quite well, considering it's the first one i've made. But when I started to make an event send/recieve system with derived classes contained in a base class pointer vector array, I had some trouble making the reciever get the class type and use the proper function; here's what I have:
This is my base class Object:
object.h:
#include "all.h" //Contains '#include "SDL/SDL.h"' and constant variables.
#include <vector>
#include "mask.h" //An unimportant class used for collision checking
class Body;
class Room;
class Object//Objects that belong here are those without step events.
{
public:
vector<vector<Room> > *world_map;//Should hold the address of the world map.
Room *room;//The room holding this object.
unsigned int x;
unsigned int y;
unsigned int pos;//Position of the object in the room's list.
int depth;//The deeper it is, the later it will be drawn.
virtual void draw(SDL_Surface *buffer,int viewx, int viewy){}
virtual void interact(Body *body);//Sends a pointer of this object to the
//the obj_event function of the body calling it.
Object(unsigned int xx=0, unsigned int yy=0,int d=0):x(xx),y(yy),depth(d){}
};
#endif // INSTANCE_H_INCLUDED
object.cpp:
#include "object.h"
#include "body.h"
void Object::interact(Body *body)
{
body->obj_event(this);
}
This is my derived class Body:
body.h:
#ifndef BODY_H_INCLUDED
#define BODY_H_INCLUDED
#include "all.h"
#include "object.h"
class Entity;
class Enemy;
class Player;
class Body : public Object//Objects that belong here are those with step events.
{
public:
int priority;//Decides which body will perform their step event first.
virtual void step()=0;
Body(int xx=0, int yy=0, int d=0, int p=0):Object(xx,yy,d),priority(p){}
//These scripts are for handling objects and bodies it has called through
//interact()
virtual void obj_event(Object *object){}
virtual void obj_event(Entity *entity){}
virtual void obj_event(Enemy *enemy){}
virtual void obj_event(Player *player){}
};
#endif // BODY_H_INCLUDED
there is no body.cpp
This is my derived class of Body, Entity:
entity.h:
#ifndef ENTITY_H_INCLUDED
#define ENTITY_H_INCLUDED
#include "all.h"
#include "body.h"
#include "items.h"
#include <vector>
#include "mask.h"
class Entity : public Body
{
public:
vector<Item> inv;
unsigned int width;
unsigned int height;
Mask mask;
Entity(int xx,int yy,int w,int h,int d=0,int p=0);
void step();
void collide_action(Entity *entity);
virtual void obj_event(Player *player);
virtual void obj_event(Enemy *enemy);
};
#endif // ENTITY_H_INCLUDED
entity.cpp:
#include "entity.h"
#include "room.h"
#include "player.h"
#include "enemy.h"
Entity::Entity(int xx,int yy,int w,int h,int d,int p):Body(xx,yy,d,p),width(w),height(h),mask(xx,yy,w,h,m_rectangle)
{}
void Entity::step()
{
for(int iii=0;iii<room->inv.size();iii++)//Iterates through objects
{
room->inv[iii]->interact(this);
mask.update(x,y,width,height);
}
for(int iii=0;iii<room->index.size();iii++)//Iterates through bodies
{
room->index[iii]->interact(this);
mask.update(x,y,width,height);
}
}
void Entity::collide_action(Entity *entity)
{
if(entity!=this)
{
if (mask_collide(mask,entity->mask))
{
short xchange;
short ychange;
if (entity->x<x)
{
xchange=width-(x-entity->x);
}
else
{
xchange=(entity->x-x)-width;
}
if (entity->y<y)
{
ychange=height-(y-entity->y);
}
else
{
ychange=(entity->y-y)-height;
}
if(abs(xchange)<abs(ychange))
x+=xchange;
else
y+=ychange;
}
}
}
void Entity::obj_event(Player *player)
{
collide_action(player);
}
void Entity::obj_event(Enemy *enemy)
{
collide_action(enemy);
}
This is my derived class of Entity, Player:
player.h:
#ifndef PLAYER_H_INCLUDED
#define PLAYER_H_INCLUDED
#include "all.h"
#include "body.h"
#include "items.h"
#include <vector>
#include "mask.h"
#include "entity.h"
enum keylist
{
kl_left=0,
kl_up=1,
kl_right=2,
kl_down=3,
};
class Player : public Entity
{
public:
SDLKey keys[4]; //List of action's corresponding keys.
Player(int xx,int yy,int w,int h,int d=0,int p=0);
void step();
void draw(SDL_Surface *buffer,int viewx,int viewy);
void interact(Body *body);
};
#endif // PLAYER_H_INCLUDED
player.cpp:
#include "player.h"
#include "room.h"
Player::Player(int xx,int yy,int ww,int hh,int dd,int pp):Entity(xx,yy,ww,hh,dd,pp)
{
//Default keys, can be changed.
keys[kl_left]=SDLK_LEFT;
keys[kl_up]=SDLK_UP;
keys[kl_right]=SDLK_RIGHT;
keys[kl_down]=SDLK_DOWN;
}
void Player::step()
{
Uint8 *key=SDL_GetKeyState(NULL);
if (key[keys[kl_left]])
x-=1;
if (key[keys[kl_right]])
x+=1;
if (key[keys[kl_up]])
y-=1;
if (key[keys[kl_down]])
y+=1;
mask.update(x,y,width,height);
Entity::step();
}
void Player::draw(SDL_Surface *buffer,int viewx,int viewy)
{
FillRect(buffer,x-viewx,y-viewy,width,height,0xFF0000);
}
void Player::interact(Body *body){body->obj_event(this);}
I have another class Enemy, but it's pretty much exactly like player (without the keyboard controls).
Now here's my problem (not error), for every object I want any body to perform an event for, I need to make virtual functions of ALL of them in this base class, that way if any object calls body->obj_event(this), it will pick the proper function with the most derived argument.
For example, if Player called object->interact(this) of an enemy, the enemy would first use it's base class Object's virtual function interact(Body*), which would then check the derived classes if they have an identical function (which enemy does), and then enemy calls body->obj_event(this) of the player body through it's base class, Body. The player body would then first use it's base class Body's virtual function obj_event(Enemy*), which would then check the derived classes if they have an identical function (which Entity does), and then Entity executes obj_event(Enemy*). At least that's how I understand it.
What I'd like to have is a way for any derived class to call interact of any other derived class through it's base function, and would then have it call it's obj_event function for the derived class, without having to have any of the Base classes know about their derived classes.
As I mentioned, this is my first time making an engine, and I'm probably using methods that are completely hectic and error-prone. I was thinking that templates might be able to help out in this situation, but don't know how to implement them.
Related
problem with accesing protected methods in friend class
I'm starting a new project and I have trouble with accessing protected methods of Organism inside World class. I suppose there must be some error with my definition of World being a friend of organism. I tried calling some method from Organism inside World, but the compiler says that it is inaccessible. The method was of course set as protected, so only derived classes and friends could call them. World.h: #include <vector> #include <iostream> using std::vector; #include <map> using std::map; #include "Organism.h" #pragma once class World { private: map<int, std::shared_ptr<Organism>> organims_map; vector <std::shared_ptr<Organism>> animals_vector; int x_size, y_size; void initiate_aniamals(); public: World(); World(int x, int y); void make_turn(); }; Organism.h: #pragma once #include "World.h" class Organism { friend class World; private: int strength, vigor; int x_pos, y_pos; float level; protected: int get_vigor() const; virtual void action() = 0 ; virtual void collision() = 0; /// <summary> /// compares animals by their vigor /// </summary> /// <param name="other organism"></param> /// <returns>which animal has higher vigor</returns> bool operator<(const Organism& other_organism); }; Then In file world.cpp i try to define method make_turn(): void World::make_turn() { //stable sort animals by their vigor std::stable_sort(begin(this->animals_vector), end(this->animals_vector), [](const Organism& organism_1, const Organism& organism_2) { return organism_1.get_vigor(); // }); I get error in line: return organism_1.get_vigor(); says that function get_vigor is inacessible.
The problem was the fact that #pragma once was not at the beginning of World.h But after including Organism.h. That leads to tons of weird errors including the fact that despite being friends of Organism, World couldn't use its private methods. This is correct: #pragma once #include "Organism.h" This, however is absolutely not: #include "Organism.h" #pragma once
Friending class while there's an object of friending class inside friended class
the title might seem a little bit confusing but I'll try to explain that. I've got a class CGameMode: #pragma once #include <string> #include <iostream> #include "../Hero/Hero.h" #include "../Weapon/Weapon.h" #include "../Armor/Armor.h" class CGameMode { private: CHero Hero; CWeapon Weapon; CArmor Armor; std::string FileName = "save.txt"; protected: public: void InitializeGame(); void CreateGame(); void LoadGame(); void SaveGame(); CGameMode* GetGameMode() { return this; } }; As you can see, the class contains objects of classes: CHero, CWeapon and CArmor. Let's take a look on one of these classes: #pragma once #include "../Enemy/Enemy.h" #include "../GameMode/GameMode.h" class CHero : public CEnemy { private: int Energy = 0; int ExperiencePoints = 0; int Level = 0; friend class CGameMode; protected: public: CHero(); CHero(std::string Name, int Health, int Energy, int ExperiencePoints, int Level); }; The most important is this line of code: friend class CGameMode; (CArmor and CWeapon also friend the CGameMode class). The problem is the program does not compile. But if I remove Hero, Weapon and Armor members from CGameMode class, the program compiles and everything works just fine. So the question is: How can I make the CGameMode class friended with CWeapon, CArmor and CHero and in the same time, the objects of these classes can be contained by CGameMode?
Circular Inclusion and Inheritence with Forward Declarations Leads to C2504 base class undefined
I am getting a C2504 compilation error in PlayerController.h saying that my base class (Updateable) is undefined. I have searched for several hours for a solution to a circular inclusion with inheritance problem and their solutions are to remove the circular inclusions and jsut use a forward declaration. As far as I understand, this works if no methods from the forward declared class are called. However, in my program my Updateables class calls a method on its member inherited gameObject object and the GameObjects also call methods on their member Updateables. Because of this, Updateables need to include GameObject.h and GameObjects need to include Updateables.h. This leads to a C2504 in PlayerController.h saying that the base class Updateable can not be found. Here are my relevant classes: Component.h #pragma once #include "Vector3.h" class GameObject; class Component { public: GameObject* gameObject = nullptr; Component(); }; Component.cpp #include "Component.h" Component::Component() {} Updateable.h #pragma once #include "Component.h" #include "GameObject.h" class GameObject; class Updateable : public Component { public: ~Updateable(); virtual void update() = 0; }; Updateable.cpp #include "Updateable.h" Updateable::~Updateable() { if (gameObject) { gameObject->removeUpdateable(this); } } GameObject.h #pragma once #include "Updateable.h" #include "GameManager.h" class Updateable; class GameObject { public: GameObject(); ~GameObject(); void runUpdateables(); void addUpdateable(Updateable* updateable); void removeUpdateable(Updateable* updateable); private: vector<Updateable*> updateables; }; GameObject.cpp #include "GameObject.h" GameObject::GameObject() { updateables = vector<Updateable*>(); GameManager::addGameObject(this); } GameObject::~GameObject() { GameManager::removeGameObject(this); } void GameObject::runUpdateables() { for (unsigned int i = 0; i < updateables.size(); i++) { updateables[i]->update(); } } void GameObject::addUpdateable(Updateable* updateable) { updateables.push_back(updateable); updateable->gameObject = this; } void GameObject::removeUpdateable(Updateable* updateable) { auto it = find(updateables.begin(), updateables.end(), updateable); if (it != updateables.end()) { updateables.erase(it); } } PlayerController.h #pragma once #include "Updateable.h" //#include "GameObject.h" #include "Input.h" class Updateable; class PlayerController : public Updateable { public: float speed = 5.0f; void update(); }; PlayerController.cpp #include "PlayerController.h" void PlayerController::update() { float x = 0; if (Input::getKeyDown(GLFW_KEY_A)) { x = -speed; } if (Input::getKeyDown(GLFW_KEY_D)) { x = speed; } cout << x << endl; gameObject->getRigidBody()->velocity.x = x; //yes this is a method in GameObject that I removed from this post //because it would take up more space, rigidbody.h does not create //a circular dependency } GameManager.h #pragma once #include "GameObject.h" #include "PlayerController.h" class GameManager { public: static void init(); static void addGameObject(GameObject* go); static void removeGameObject(GameObject* go); static void onFrame(); private: static vector<GameObject*> gameObjects; static GameObject* box; GameManager.cpp #include "GameManager.h" vector<GameObject*> GameManager::gameObjects; GameObject* GameManager::box; void GameManager::init() { gameObjects = vector<GameObject*>(); box = new GameObject(); box->addUpdateable(new PlayerController()); } void GameManager::addGameObject(GameObject* go) { gameObjects.push_back(go); } void GameManager::removeGameObject(GameObject* go) { auto it = find(gameObjects.begin(), gameObjects.end(), go); if (it != gameObjects.end()) { gameObjects.erase(it); } } void GameManager::onFrame() { for (unsigned int i = 0; i < gameObjects.size(); i++) { gameObjects[i]->runUpdateables(); } } Here is the exact error message: Error C2504 'Updateable': base class undefined Basic Platformer c:\users\default.sixcore-pc\documents\visual studio 2015\projects\basic platformer\basic platformer\playercontroller.h 9
A lot of your files have both #include "Class.h" and class Class; declarations. You never need both; use one or the other. A definition of a class X must be visible when: accessing the members of X creating an object of type X defining a class derived from X using X as a template argument to a template which requires the corresponding template parameter to be a complete type (such as what standard library containers require of their element type). Note that this applies when using X, not X*. In other cases (such as creating a pointer to X or declaring a function taking of returning X), a non-defining declaration (class X;) is enough. Using these rules (plus moving function bodies from headers to source files when necessary), you can solve any circular dependency issues. To directly address your files as presented: Updateable.h does not need to #include "GameObject.h". It doesn't even need the forward declaration of GameObject. GameObject.h doesn't need any of the two #includes in it. GameManager.h doesn't need any #includes. It needs a declaration of class GameObject; though.
Descendant class must know the full definition of the base class. Forward declaration is not enough and useless.
Observer pattern and inheritance: Not calling the correct function
I am trying to implement the Observer pattern for a game I am creating for a school project. I have created 2 virtual classes, Observer and Observable. Observer.h: #ifndef OBSERVER_H #define OBSERVER_H #include <vector> class Observable; class Observer { public: Observer(); virtual ~Observer(); virtual void update(Observable* ob) =0; }; #endif Observer.cpp: #include "stdafx.h" #include "Observer.h" Observer::Observer() { } Observer::~Observer() { } Observable.h: #ifndef OBSERVEABLE_H #define OBSERVEABLE_H #include <vector> #include "Observer.h" class Observable { protected: std::vector<Observer*> observers; public: Observable(); virtual ~Observable(); virtual void attach(Observer *a); virtual void detach(Observer *a); virtual void notify(); }; #endif Observable.cpp: #include "stdafx.h" #include "Observable.h" Observable::Observable() { } Observable::~Observable() { } void Observable::attach(Observer *a) { observers.push_back(a); } void Observable::detach(Observer *a) { for (auto it = this->observers.begin(); it < this->observers.end(); it++) { if (*it == a) { this->observers.erase(it); break; } } } void Observable::notify() { for (int i = 0; i < observers.size(); i++) observers[i]->update(this); } I have a Map class that inherits from Observable, and a mapView class that inherits from Observer (Map is very long, I only included the relevant functions) Map.h: #ifndef MAP_H #define MAP_H #include "Observable.h" #include <iostream> class Map : public Observable { public: Map(); ~Map(); void getLatest(); void notify(); }; #endif Map.cpp: #include "stdafx.h" #include "Map.h" Map::Map() { } Map::~Map() { } void Map::getLatest() { using namespace std; cout << "This is the latest info!" << endl; } mapView.h: #ifndef MAP_V_H #define MAP_V_H #include "Observer.h" #include "Map.h" #include "Plants.h" class mapView : public Observer { public: mapView(); ~mapView(); void update(Map* map); }; #endif mapView.cpp: #include "stdafx.h" #include "mapView.h" #include "Map.h" mapView::mapView() { } mapView::~mapView() { } void mapView::update(Map* map) { map->getLatest(); } Finally, my main simply creates a Map and a mapView, attaches the mapView, and calls map.notify() main.cpp: #include "stdafx.h" #include "setUp.h" #include "Map.h" #include "mapView.h" int main() { Map gameMap; mapView view; gameMap.attach(&view); gameMap.notify(); return 0; } I run into a number of issues here. I cannot create a mapView item because the compiler says I never implemented an override version of update(Observable* ob).... I tried with update(Map* map) but it appears that despite the fact that Map inherits from Observable, it does not seem to count as the same signature, so it won't compile. I attempted to change my mapView::update() function to take a pointer to Observable instead, but this won't work because the function calls something from Map class. I then tried changing the update function to NOT be a virtual function (with empty implementation in the virtual class), but it seems any time I try to pass a Map to update, it will call the base class function and not the mapView version. In other words, getLatest() is never called. I am now pretty confused because this sort of goes against how I thought polymorphism worked. Would appreciate some help or insight if possible! Thank you,
Your base class declares: virtual void update(Observable* ob) =0; You derived class declares: void update(Map* map); These are not the same signature. If you used the new override keyword, you would see at compile time that you were not in fact overriding the virtual method. If you know you'll only get Maps, then you can just use static_cast. But it's safer to use dynamic_cast: void update(Observable* o) override { // now we're ok if (auto map = dynamic_cast<Map*>(o)) { // okay, got a Map // .... } else { // huh? } } Super brief type theory digression. The typical rule for overrides is covariant in return and contravariant in the argument type. You can specify a more-derived return type, or a more-base argument type. Think about it this way - if you have a base class function taking and returning a Car*... your argument can be a Car* (that's exactly what's expected), or it can be a Vehicle* (since anything you can do with a Vehicle, you can do with a Car - this still works), but it can't be a SportsCar* (since the caller might pass you a Car that isn't a SportsCar and justifiably expect this to work!) It doesn't make sense for the derived class to accept only Maps - you have to be able to accept any Observables, even not Maps!
chess game - error in abstract class
#pragma once #include <string> #include <iostream> using namespace std; class Chess_tool { public: Chess_tool(string color, char name); virtual bool legal_movement(int source[], int dest[]) const = 0; private: string _color; char _name; }; Im trying to create chess game, so I create abstract class for chess tool (queen, king, rook...) I also created king tool to check my code: #pragma once #include "Chess_tool.h" class King : Chess_tool { public: King(string color, char name); virtual bool legal_movement(int source[], int dest[]); }; and I create game_board class: #pragma once #include "Game_board.h" #include "Chess_tool.h" #include <iostream> #define BOARD_SIZE 8 using namespace std; class Chess_tool; class Game_board { public: Game_board(); ~Game_board(); void move(string panel); protected: Chess_tool* _board[BOARD_SIZE][BOARD_SIZE]; }; the problem is here, when i try to add object to the matrix its show me error : 1 IntelliSense: object of abstract class type "King" is not allowed: pure virtual function "Chess_tool::legal_movement" has no overrider #pragma once #include "Chess_tool.h" #include "Game_board.h" #include "King.h" using namespace std; enum Turn { WIHTE, BLACK }; class Manager : Game_board { public: Manager(); ~Manager(); virtual bool legal_movement(int source[], int dest[]) const = 0; }; .... #include "Manager.h" Manager::Manager() { _board[0][0] = new King(); }
The member function in the base class is const-qualified, not in the derived class. So these are not the same functions through inheritance. You've declared a new virtual function, not overriden the first one. Add const to the second one so that it actually override the base class function. Remember that for virtual function overriding to kick in, there are a few condition to actually satisfy. They must have: the same name the same return type the same parameters count and type the same const-qualification (our case here) a few other minor things (for example, compatible exceptions specifications) If any condition isn't satisfied, you create a very similar, but different, function for the compiler. With C++11, you should use override for the functions you want to override, so the compiler knows your intention and tells you that you've made a mistake. E.g.: virtual bool legal_movement(int source[], int dest[]) override; // ^^^^^^^^