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);
Related
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.)
I have class Walls in my program. Inside of class are objects Wall1, Wall2 etc.
I want to do something like this:
class definition:
class Walls {
public:
Walls(){
nPositionX = nMapWidth - 1;
nHoleSize = 1;
nHolePosition = rand()%(nMapHeight - nHoleSize);
count++;
}
static int getCount() {
return count;
}
int getPositionX()
{
return nPositionX;
}
private:
int nPositionX;
int nHolePosition;
int nHoleSize;
static int count;
};
access to object
for (int i = 0; i < Walls::getCount(); i++) {
int nPosx = Wall"i".getPositionX();
}
}
Is that possible in c++?
Ok big thanks for everyone for help. I don't know why I didn't tried it before.
You can use an array or std::vector for that, eg:
std::array<Wall, MAX_WALLS> m_walls;
or
std::vector<Wall> m_walls;
...
// initialize m_walls[0], m_walls[1], etc as needed...
...
for (size_t i = 0; i < m_walls.size(); i++) {
int nPosx = m_walls[i].getPositionX();
...
}
Or, you can use a std::map, eg:
std::map<std::string, Wall> m_walls;
...
// initialize m_walls["Wall1"], m_walls["Wall2"], etc as needed...
...
for (int i = 1; i <= getCount(); i++) {
int nPosx = m_walls["Wall" + std::to_string(i)].getPositionX();
...
}
The code is not executed until you execute your program, but in the executable there are no variable names anymore. Hence, no.
You can use an array or vector:
struct Wall { int get_position() const { return 42; } };
using Walls = std::vector<Wall>;
Walls walls;
for (const auto& wall : walls) {
int nPosx = wall.get_position();
}
Or if you really want to map names to objects, use a std::map:
std::map<std::string,Wall> named_walls;
named_walls["stone wall"] = Wall();
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.
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.
I am a beginner in threading with C++. Tried to create a thread t1 inside the class, but I want it not to be initialized. For this I did:
In the class variable, thread *t1 as if were to declare the class variable without initializing it.
Then from the constructor, I did:
t1 = new Thread(functionName);
But, there's some error that I didn't get. I previously had simple working experience with threading in Java.
Will this strategy cause an interlocking problem, assuming the solution exists to the way I want to implement it. (if I want to access the same variable without modifying it). Code goes like this:
class game:protected gameObjects
{
thread *t1;
///-------------------- Variables-------------------///
char keyPressed = NULL;
/// structure for holding player information.
struct player
{
int x, y0, y1,color;
};
player player1, player2;
/// for ball
int ballX, ballY, ballColor, ballBorderColor;
///--------------------------------------------------///
void initializeData()
{
ballX = 42;
ballY = 130;
player1.color = LIGHTCYAN;
player1.x = 30;
player1.y0 = 100;
player1.y1 = 200;
player2.color = LIGHTMAGENTA;
player2.x = 600;
player2.y0 = 100;
player2.y1 = 200;
/// Basic setUp For Game and Game Screen
ballBorderColor = RED;
ballColor = GREEN;
}
void updateScoreBoard()
{
/// whole score board border.
drawRect(20,10,620,50,RED);
/// left score board
drawRect(21,11,321,49,CYAN);
setfillstyle(SOLID_FILL,CYAN);
floodfill(30,40,CYAN);
setbkcolor(CYAN);
setcolor(LIGHTGREEN);
outtextxy(35,20,"Score:0");
///right score board.
drawRect(323,11,619,49,LIGHTMAGENTA);
setfillstyle(SOLID_FILL,LIGHTMAGENTA);
floodfill(330,40,LIGHTMAGENTA);
setbkcolor(LIGHTMAGENTA);
setcolor(LIGHTGREEN);
outtextxy(350,20,"Score:1");
}
void ballPosition()
{
setfillstyle(SOLID_FILL,ballColor);
drawCircle(ballX,ballY,10,ballBorderColor); ///ball for game
floodfill(ballX,ballY,ballBorderColor);
}
void playerBatPosition()
{
drawLine(player1.x,player1.y0,player1.x,player1.y1,player1.color);
drawLine(player2.x,player2.y0,player2.x,player2.y1,player2.color);
}
void setBackground()
{
setfillstyle(SOLID_FILL,background);
drawRect(0,0,getmaxx(),getmaxy(),RED);
floodfill(getmaxx()/2,getmaxy()/2,RED);
drawRect(20,60,620,470,WHITE); ///white line.
}
void updateScreenActivity()
{
playerBatPosition();
}
void startPlaying()
{
do
{
keyPressed = _getch();
if(keyPressed == 'w')
{
if(player1.y0 > 60)
{
drawLine(player1.x,player1.y0,player1.x,player1.y1,background);
player1.y0-=5;
player1.y1-=5;
}
}
else if(keyPressed == 's')
{
if(player1.y1 < 470)
{
drawLine(player1.x,player1.y0,player1.x,player1.y1,background);
player1.y0+=5;
player1.y1+=5;
}
}
if(keyPressed == 't')
{
if(player2.y0 > 60)
{
drawLine(player2.x,player2.y0,player2.x,player2.y1,background);
player2.y0-=5;
player2.y1-=5;
}
}
else if(keyPressed == 'g')
{
if(player2.y1 < 470)
{
drawLine(player2.x,player2.y0,player2.x,player2.y1,background);
player2.y0+=5;
player2.y1+=5;
}
}
updateScreenActivity();
}
while(keyPressed != 'q');
}
///-------------------Threading call --------------///
void startBallMovement(){
cout<<"Hello world"<<endl;
}
///-----------------------------------------------///
public:
game()
{
cleardevice();
initializeData();
setBackground();
updateScoreBoard();
playerBatPosition();
ballPosition();
startPlaying();
t1 = new thread(startBallMovement);
}
};
What I want to do is create a movement of a circle in different paths from the thread. I might sometimes need to access the variables from the thread to simulate the movement in different directions as per the user's strategy.
Error:
Your class implementation looks a bit lousy. But try something like this.
class game
{
private: thread* t;
public:
game()
{
t = new thread([this]() {startBallMovement();} );
}
~game()
{
if(t != nullptr)
{
t->join();
delete t;
}
}
void startBallMovement()
{
}
};