C++ class inherit (game structure) - c++

I'm trying to make some game engine (I know, should do an actual game instead).
Sadly have defeat at project structure. it looks like this (footage from my fifth attempt):
#include <iostream>
#include <vector>
#include <windows.h>
using namespace std;
class Player;
class Engine {
private:
CHAR_INFO *chiBuffer;
int width = 0;
int height = 0;
vector <Player> players;
public:
Engine(int x = 120, int y = 30) {
chiBuffer = new CHAR_INFO[x*y];
}
void addPlayer(Player player) {
players.push_back(player);
}
void render() {
for (int i = 0; i < players.size(); i++) {
Player *player = &players[i];
player->draw();
}
}
protected:
inline CHAR_INFO& getPixel(int x, int y) { return chiBuffer[x + width * y]; }
};
class Drawable : Engine {
protected:
inline CHAR_INFO& getPixel(int x, int y) { return Engine::getPixel(x, y); }
virtual void draw() = 0;
};
class Player : Drawable {
protected:
int x = 0;
int y = 0;
public:
void draw() {
getPixel(x, y).Char.UnicodeChar = L'*';
}
};
int main() {
Engine *eng = new Engine(120, 30);
Player p;
eng->addPlayer(p);
return 0;
}
I would like to make it easily extensible, so in my mind had been born an idea of creating master class (Engine) sub class Drawable which will have draw() method and later Tickable which would have onTick() etc... But I'm pretty sure I'm doing it so wrong. Could you tell me better idea of doing this? Or make this just working because this gives me too many errors to write it right here (VS 2017)

First, why use this ?
for (int i = 0; i < players.size(); i++) {
Player *player = &players[i];
player->draw();
}
It's the same as: for(...) { players[i].draw() ;}.
Don't use variables and pointers where you don't need to (like in your main, don't use the new keyword: it's pointless. Engine e = Engine(120,30) is ok.).
The for loop on a vector should use Iterators :
for (auto it = begin (vector); it != end (vector); ++it) {
it->draw;
}
In manners of good practice, you should write your code in different files.
Engine.h for Engine declaration, Engine.cpp for implementation.
Same for Player.

Related

How to reference a classes attribute inside another class method?

I'm trying to create a little ascii game where I can run around kill enemies etc. However I'm new to C++ and I would like to do something if the players location is at a certain point.
Below is a simpler version of the code and a picture of the problem:
#include <iostream>
using namespace std;
struct Game
{
bool bGameOver = false;
int iWidth = 20;
int iHeight = 40;
void Draw() {
if (player.x == 5)
{
cout << "Hello"
}
}
};
struct Player
{
bool bGameOver = false;
int x = 0;
int y = 0;
};
void Setup()
{
}
int main()
{
Game game;
Player player;
while (!game.bGameOver)
{
Setup();
}
}
Picture of the error
The variable player is local in function main, so it's not visible where you tried to use it in Game::Draw.
One solution could be to make player a global variable. You'll need to switch the order of the structs:
struct Player
{
bool bGameOver = false;
int x = 0;
int y = 0;
};
Player player;
struct Game
{
bool bGameOver = false;
int iWidth = 20;
int iHeight = 40;
void Draw() {
if (player.x == 5)
{
cout << "Hello"
}
}
};
But I'd prefer to instead model things so a Game "has a" Player. So make Player a member of the Game:
struct Player
{
bool bGameOver = false;
int x = 0;
int y = 0;
};
struct Game
{
Player player;
bool bGameOver = false;
int iWidth = 20;
int iHeight = 40;
void Draw() {
if (player.x == 5)
{
cout << "Hello"
}
}
};
(Aside: You probably don't want two different values called bGameOver, since keeping them in sync would be extra work. It sounds more like a game property than a player property to me.)

Array of arrays of different types of shapes

I want to create a "3D console game" using RayCasting. To begin with, I needed a container with all the information about the world. First of all, I started with just two shapes, a rectangle and a circle. Actually, here's how I implemented them:
enum POINTS
{
POINT_1,
POINT_2
};
enum ASIXS
{
ASIX_X,
ASIX_Y,
};
class Point
{
private:
double properties[2];
public:
Point()
{
properties[ASIX_X] = 0;
properties[ASIX_Y] = 0;
}
Point(double x, double y)
{
properties[ASIX_X] = x;
properties[ASIX_Y] = y;
}
double& operator[] (int index)
{
return properties[index];
}
};
class Rectangle
{
private:
Point base[2];
public:
//Points getter
Point& operator[](int index)
{
return base[index];
}
};
class Circle
{
private:
Point center;
double radius = 0;
public:
Point& getCenter()
{
return center;
}
double& getRadius()
{
return radius;
}
};
Next, I need a generic container. Obviously this should be a pattern:
template<typename T>
class ObjectArr
{
protected:
int qty;
T* objs;
public:
ObjectArr()
{
qty = 0;
objs = nullptr;
}
~ObjectArr()
{
delete[] objs;
}
void add()
{
T* temp = new T[++qty];
for (int i = 0; i < qty - 1; i++)
temp[i] = objs[i];
delete[] objs;
objs = temp;
}
T getObj(int index)
{
return objs[index];
}
};
Here's what it will look like:
#include <iostream>
using namespace std;
int main()
{
ObjectArr<Rectangle> rect;
rect.add();
//rect.getObj(id)[point][asix]
rect.getObj(0)[POINT_1][ASIX_X] = 5;
cout << rect.getObj(0)[POINT_1][ASIX_X]; //Out 5
ObjectArr<Circle> cir;
cir.add();
//cir.getObj(id).getCenter()[asix]//getRadius()
cir.getObj(0).getCenter() = {0, 0};
return 0;
}
And in the end, I would like one common container that would store ObjectArr<>. From the beginning I thought about polymorphism. Something like this:
#include <vector>
class Container
{
//...
};
template<typename T>
class ObjectArr : public Container
{
//...
};
int main()
{
vector<Container*> test;
test.push_back(new ObjectArr<Rectangle>);
test.push_back(new ObjectArr<Circle>);
test[0]->add();
//...
return 0;
}
But with this approach, the function T getObj(int index) cannot be used from such a container. And writing it as a virtual one will not work either because of the template. And I also don’t want to prescribe every possible shape, so that it would be easier to add new shapes. Wrote a class of a new figure and all. Tell me, please, how should I be and what should I do, maybe I need to completely change the approach?

How to use classes inside another class function independently of where it is declared in C++?

I'm trying to create a Monopoly game in C++ and I've been messing with object-oriented-programming, the problem happens with the classes "Game" and "Player", I would like to know how to use "Game"'s functions inside "Player" and "Player"'s functions inside "Game", but I've been getting a compiler error saying that the class is not defined.
Switching class positions won't work (obviously) but I tried anyways.
Code (reduced and minimized to the Game and Player classes):
namespace Monopoly {
typedef enum { normal, train, company, incometax, luxurytax, start, chancecard, chestcard, jail } type;
class Game {
private:
bool running = false;
int turn = 1;
int currentPlayerID;
int startingMoney = 1000;
std::vector<Player> players;
public:
// Functions
void createPlayer() {
++currentPlayerID;
Player newPlayer(currentPlayerID, startingMoney);
players.push_back(newPlayer);
++currentPlayerID;
}
void createPlayers(int playerAmount) {
for (int i = 0; i <= playerAmount; ++i) {
createPlayer();
}
}
Player getPlayer(int index) {
Player p = players[index];
return p;
}
};
class Player {
private:
int playerID;
int money;
std::vector<int> propertiesOwned;
void addProperty(int id) {
this->propertiesOwned.push_back(id);
}
public:
// Constructor
Player(int pID, int sMoney) {
this->playerID = pID;
this->money = sMoney;
}
// Functions
Player payMoney(int payAmount, unsigned int destinationID, Game engine) {
this->money -= payAmount;
if (destinationID > 0) {
// Checks if you're paying to a player or bank
bool playerFound = false;
for (int i = 0; i <= engine.getPlayerAmount(); ++i) {
if (engine.getPlayer(i).getID() == destinationID) {
playerFound = true;
break;
}
}
if (playerFound) {
// Player was found
engine.getPlayer(destinationID).giveMoney(payAmount);
return;
}
else {
std::cout << "\nERROR: Invalid player ID at function payMoney\n";
return;
}
}
else {
// You're paying to the bank
}
return;
}
void buyProperty(int id, int price, Game engine) {
payMoney(price, 0, engine);
addProperty(id);
}
void giveMoney(int payMoney) {
this->money += payMoney;
}
// Returns
inline int getMoney() { return this->money; }
inline int getID() { return this->playerID; }
inline auto getProperties(int index) {
auto p = propertiesOwned[index];
return p;
}
inline int getPropertyAmount() {
int amount = std::size(propertiesOwned);
return amount;
}
};
}
I expected the classes to run the other classes function normally, but it seens like that in C++, classes are defined in certain order, and you can only access classes (in a class) declared before the class you're using, feedback and alternatives that fix this would help
You are correct that in C++ declaration order matters, and that is the cause of your errors, however there are a few other issues with the code.
Firstly, you should swap the order that Game and Player are defined. This will make it easier, as Player relies on Game fewer times than Game relies on Player.
Next, add a forward declaration for Game before the definition of Player:
class Game;
This tells the compiler that a class named Game exists and allows you to use it in scenarios where it doesn't need to know the contents (i.e. definition) of the class.
Next, make payMoney and buyProperty accept their engine parameter by reference instead of by value by changing the parameter specifier to Game &engine. This is important for two reasons. First, passing by value can only be done if you have already defined the type, which we have not (we've only declared it). Second, passing by value creates a copy of the object, which in this case means a completely new vector of completely new Player objects, and the changes will not synchronize back to the old object. See here for a better explanation of references.
Next, you need to extract the definition of payMoney to after the definition of Game. The reason is that while the parameter list of payMoney no longer relies on the definition of Game, the code in the function body does (because it calls functions on the engine object). See the end for what this looks like.
This fixes all the problems with declaration/definition order. You also should make payMoney return void as its return value is never provided and never used, pick a consistent type for IDs (either int or unsigned int, not a mix), and add the getPlayerAmount to Game.
Here's what the final code could look like:
namespace Monopoly {
typedef enum { normal, train, company, incometax, luxurytax, start, chancecard, chestcard, jail } type;
class Game;
class Player {
private:
int playerID;
int money;
std::vector<int> propertiesOwned;
void addProperty(int id) {
this->propertiesOwned.push_back(id);
}
public:
// Constructor
Player(int pID, int sMoney) {
this->playerID = pID;
this->money = sMoney;
}
// Functions
void payMoney(int payAmount, int destinationID, Game &engine);
void buyProperty(int id, int price, Game &engine) {
payMoney(price, 0, engine);
addProperty(id);
}
void giveMoney(int payMoney) {
this->money += payMoney;
}
// Returns
inline int getMoney() { return this->money; }
inline int getID() { return this->playerID; }
inline auto getProperties(int index) {
auto p = propertiesOwned[index];
return p;
}
inline int getPropertyAmount() {
int amount = std::size(propertiesOwned);
return amount;
}
};
class Game {
private:
bool running = false;
int turn = 1;
int currentPlayerID;
int startingMoney = 1000;
std::vector<Player> players;
public:
// Functions
void createPlayer() {
++currentPlayerID;
Player newPlayer(currentPlayerID, startingMoney);
players.push_back(newPlayer);
++currentPlayerID;
}
void createPlayers(int playerAmount) {
for (int i = 0; i <= playerAmount; ++i) {
createPlayer();
}
}
Player getPlayer(int index) {
Player p = players[index];
return p;
}
int getPlayerAmount() {
int amount = players.size();
return amount;
}
};
void Player::payMoney(int payAmount, int destinationID, Game &engine) {
this->money -= payAmount;
if (destinationID > 0) {
// Checks if you're paying to a player or bank
bool playerFound = false;
for (int i = 0; i <= engine.getPlayerAmount(); ++i) {
if (engine.getPlayer(i).getID() == destinationID) {
playerFound = true;
break;
}
}
if (playerFound) {
// Player was found
engine.getPlayer(destinationID).giveMoney(payAmount);
return;
}
else {
std::cout << "\nERROR: Invalid player ID at function payMoney\n";
return;
}
}
else {
// You're paying to the bank
}
return;
}
}
Side note: it's technically better C++ to use size_t instead of int for variables storing the size of vectors, as that is what the size functions return (and it's an unsigned integer type whereas int is signed), but that's not especially important.

Passing an array of objects into another class constructor (Arduino IDE)

I am trying to pass an array of objects into another array, I am using the Arduino IDE, so I don't think using Vectors is possible.
The code complies, however it does not do what I wanted it to. (To use the the method of the passed object)
class Menu_Manager
{
private:
int _currentPage;
Main_Menu *main_menus[];
public:
//Problem
Menu_Manager(Main_Menu *main[], int numberOfMenus)
{
for (int x = 0; x <= numberOfMenus; x++)
{
*main_menus[x] = *main[x];
}
_currentPage = 0;
}
void start()
{
main_menus[_currentPage]->start();
if (_currentPage >= main_menus[0]->getTotalPage())
{
_currentPage = 0;
}
else if (_currentPage < 0)
{
_currentPage = main_menus[0]->getTotalPage();
}
}
};
Main file:
Main_Menu timer(1, lcd);
Main_Menu setting(2, lcd);
Main_Menu *allMM[] = { &timer, &setting };
Menu_Manager manager(&allMM[2], 2);

Accessing parent classes through composition

In my program i have a very simple structure to represent a map in an RPG game. I have a Map class, with a 2d Array, "Grid", made out of Area objects, like so:
#pragma once
#include "Area.h"
class Map
{
public:
Map();
~Map();
Area Grid[10][10];
};
Then in the Map constructor:
Map::Map()
{
for (int y = 0; y < 10; y++) {
for (int x = 0; x < 10; x++) {
Grid[x][y] = Area();
}
}
}
I would like for the Area objects to be able to access certain values from the Map object, and I've read that i could include a reference to the map class when constructing the area object, so that it can refer back to its parent. But to do this, i would have to
#include "Map.h" in Area.h, which would create an include loop, and just not be very good in general. So how would i go about injecting a reference to the area's parent in each area object? Thanks for any help in advance.
// Area.h
#pragma once
struct Map;
struct Area {
Map* map = nullptr;
Area() {}
explicit Area( Map* m) : map(m) {}
};
Note that you may want to have some of the functions of Area defined in Area.cpp (that includes Map.h). I just left it out for simplicity of example code.
// Map.h
#pragma once
#include "Area.h"
struct Map
{
Map();
~Map();
Area Grid[10][10];
};
// Map.cpp
#include "Map.h"
Map::Map()
{
for (int y = 0; y < 10; y++) {
for (int x = 0; x < 10; x++) {
Grid[x][y] = Area(this);
}
}
}
Map::~Map() {}
// main.cpp
#include "Map.h"
int main()
{
Map m;
return 0;
}