How to use variables in other class members?

Pages: 12
So I decided to write a game and use classes to better strengthen my class knowledge, and it was going well, however I have one problem I cannot seem to figure out. How do I use variables with other classes when they need to interact? I have a Game Class and a Player class, I need to use some of the player variables in the game class members but I cant seem to figure out how without breaking encapsulation. I have all the code written in main, it works exactly how i want and now im just trying to break it up into smaller chunks.

I was going to have Player class inherit from Game class which is why certain variables are protected, but idk about using inheritance. Not sure if its needed here or not.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#include <iostream>
#include <string>

using namespace std;

class Game
{
    public:
        Game() = default;
        ~Game() = default;

        void DrawMap();
        void DrawObstacles();

    private:
        int mapColSize = 10;
        int mapRowSize = 22;

    protected:
        char mapArray[0][0];

        char mapGrid = 'o';
        char rockObstacle = '#';
};

class Player
{
    public:
        Player() = default;
        ~Player() = default;

        void SetPlayerOnMap();
        int GetPlayerXYPosition() const;
        void MovePlayer();
        void BoundCheck();
        void PlayerCollision();

    private:
        char playerChar = '*';
        int playerXPos = 3;
        int playerYPos = 3;
};


void Game::DrawMap()
{
    int choice = 0;

    Player player;

    while(choice != -1)
    {
        for(int col = 0; col < mapColSize; col++)
        {
            for(int row = 0; row < mapRowSize; row++)
            {
               mapArray[col][row] = mapGrid;
               mapArray[playerYPos][playerXPos] = playerChar;

               cout << mapArray[col][row];
            }
            cout << endl;
        }
}


int main()
{
    int mapColSize = 10;
    int mapRowSize = 22;

    char mapArray[mapColSize][mapRowSize];

    char mapGrid = 'o';
    char playerChar = '*';
    char rockObstacle = '#';

    int playerXPos = 3;
    int playerYPos = 3;

    int choice = 0;

    while(choice != -1)
    {
        for(int col = 0; col < mapColSize; col++)
        {
            for(int row = 0; row < mapRowSize; row++)
            {
               mapArray[col][row] = mapGrid;
               mapArray[playerYPos][playerXPos] = playerChar;

               cout << mapArray[col][row];
            }
            cout << endl;
        }

        cout << "\nWhat direction would you like to move?\n" << endl;

        cout << "1) UP" << endl;
        cout << "2) DOWN" << endl;
        cout << "3) LEFT" << endl;
        cout << "4) RIGHT" << endl;
        cout << ">";
        cin >> choice;

        switch(choice)
        {
            case 1:
                if(playerYPos > 0)
                {
                    playerYPos -= 1;
                    cout << "Player Y Pos: " << playerYPos << endl;
                }
                else if(playerYPos == 0)
                {
                    playerYPos -= 0;
                    cout << "You cannot go any further North!\n" << endl;
                }
                break;
            case 2:
                if(playerYPos < mapColSize -1)
                {
                    playerYPos += 1;
                    cout << "Player Y Pos: " << playerYPos << endl;
                }
                else if(playerYPos == mapColSize -1)
                {
                    playerYPos += 0;
                    cout << "You cannot go any further South!" << endl;
                }
                break;
            case 3:
                if(playerXPos > 0)
                {
                    playerXPos -= 1;
                    cout << "Player X Pos: " << playerXPos << endl;
                }
                else if(playerXPos == 0)
                {
                    playerXPos -= 0;
                    cout << "You cannot go any further West!" << endl;
                }
                break;
            case 4:
                if(playerXPos < mapRowSize -1)
                {
                    playerXPos += 1;
                }
                else if(playerXPos == mapRowSize -1)
                {
                    playerXPos += 0;
                    cout << "You cannot go any further East!" << endl;
                }
                break;
            default:
                cout << "Not a valid option" << endl;
        }
    }

    return 0;
}
Last edited on
Using the friend declaration, http://en.cppreference.com/w/cpp/language/friend. Or just using getter and setters.
hmm, what about something like this:

I made another class that inherits the other two to act like a bridge between them. This way the two classes can communicate without exposing variables to the outside world. I think the concept may be right but the implementation is wrong, im just inheriting two classes and still using the ClassLink Class. I was thinking of just having it bridge communication between the two but i dont think its doing that. Although this may be a wrong approach altogether. I'm just trying to create a nice clean interface for them all to cooperate through without having to type out a bunch of convoluted kludge duct tape code to do it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <iostream>
#include <string>

using namespace std;

class ClassLink;

class Game
{
    public:
        Game() = default;
        ~Game() = default;

        void DrawMap();
        void DrawObstacles();

    protected:
        int mapColSize = 10;
        int mapRowSize = 22;

        char mapArray[0][0];

        char mapGrid = 'o';
        char rockObstacle = '#';
};

class Player
{
    public:
        Player() = default;
        ~Player() = default;

        void SetPlayerOnMap();
        int GetPlayerXYPosition() const;
        void MovePlayer();
        void BoundCheck();
        void PlayerCollision();
        int GetPlayerInput();

    protected:
        char playerChar = '*';
        int playerXPos = 3;
        int playerYPos = 3;
};



class ClassLink : public Game, Player
{
    public:
        ClassLink() = default;
        ~ClassLink() = default;

        void DrawMap();
};


void ClassLink::DrawMap()
{
    int choice = 0;

    while(choice != -1)
    {
        for(int col = 0; col < mapColSize; col++)
        {
            for(int row = 0; row < mapRowSize; row++)
            {
               mapArray[col][row] = mapGrid;
               mapArray[ClassLink::playerYPos][ClassLink::playerXPos] = playerChar;

               cout << mapArray[col][row];
            }
            cout << endl;
        }
    }
}
Last edited on
Ok so i decided to just delete that link class and type some pseudocode to get a shell, it doesnt work, and im still unsure how to do that. Is there a way without using inheritance and friend? with friend i have to make every single thing i want to use a friend, that seems counter intuitive. It would be fine if there was only 1 or two but theres pretty much everything in the class. Unless everything in the class can be made friend, but at that point it seems like using inheritance would be a better option.

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include <iostream>
#include <string>

#include "Game.h"
#include "Player.h"

using namespace std;


int main()
{
    /*
    int mapColSize = 10;
    int mapRowSize = 22;

    char mapArray[mapColSize][mapRowSize];

    char mapGrid = 'o';
    char playerChar = '*';
    char rockObstacle = '#';

    int playerXPos = 3;
    int playerYPos = 3;

    int choice = 0;

    while(choice != -1)
    {
        for(int col = 0; col < mapColSize; col++)
        {
            for(int row = 0; row < mapRowSize; row++)
            {
               mapArray[col][row] = mapGrid;
               mapArray[playerYPos][playerXPos] = playerChar;

               cout << mapArray[col][row];
            }
            cout << endl;
        }

        cout << "\nWhat direction would you like to move?\n" << endl;

        cout << "1) UP" << endl;
        cout << "2) DOWN" << endl;
        cout << "3) LEFT" << endl;
        cout << "4) RIGHT" << endl;
        cout << ">";
        cin >> choice;

        switch(choice)
        {
            case 1:
                if(playerYPos > 0)
                {
                    playerYPos -= 1;
                    cout << "Player Y Pos: " << playerYPos << endl;
                }
                else if(playerYPos == 0)
                {
                    playerYPos -= 0;
                    cout << "You cannot go any further North!\n" << endl;
                }
                break;
            case 2:
                if(playerYPos < mapColSize -1)
                {
                    playerYPos += 1;
                    cout << "Player Y Pos: " << playerYPos << endl;
                }
                else if(playerYPos == mapColSize -1)
                {
                    playerYPos += 0;
                    cout << "You cannot go any further South!" << endl;
                }
                break;
            case 3:
                if(playerXPos > 0)
                {
                    playerXPos -= 1;
                    cout << "Player X Pos: " << playerXPos << endl;
                }
                else if(playerXPos == 0)
                {
                    playerXPos -= 0;
                    cout << "You cannot go any further West!" << endl;
                }
                break;
            case 4:
                if(playerXPos < mapRowSize -1)
                {
                    playerXPos += 1;
                }
                else if(playerXPos == mapRowSize -1)
                {
                    playerXPos += 0;
                    cout << "You cannot go any further East!" << endl;
                }
                break;
            default:
                cout << "Not a valid option" << endl;
        }
    }

    */

    return 0;
}



Game.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#ifndef GAME_H
#define GAME_H


class Game
{
    public:
        Game() = default;
        ~Game() = default;

        void DrawMap();
        void DrawObstacles();
        void GameLoop();

    private:
        int mapColSize = 10;
        int mapRowSize = 22;

        char mapArray[0][0];

        char mapGrid = 'o';
        char rockObstacle = '#';
};

#endif // GAME_H 



Game.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include "Game.h"
#include "Player.h"

#include <iostream>

using std::cout;
using std::endl;
using std::cin;

void Game::GameLoop()
{
    int choice = 0;

    while(choice != -1)
    {
        cout << "\nWhat direction would you like to move?\n" << endl;

        cout << "1) UP" << endl;
        cout << "2) DOWN" << endl;
        cout << "3) LEFT" << endl;
        cout << "4) RIGHT" << endl;
        cout << ">";

        cin >> choice;

        /*Call CheckPlayerScreenBounds()*/
    }
}

void Game::DrawMap()
{
        for(int col = 0; col < mapColSize; col++)
        {
            for(int row = 0; row < mapRowSize; row++)
            {
                mapArray[col][row] = mapGrid;
                /*Call DrawPlayer() function*/
                cout << mapArray[col][row];
            }
            cout << endl;
        }
}



Player.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#ifndef PLAYER_H
#define PLAYER_H


class Player
{
    public:
        Player() = default;
        ~Player() = default;

        void SetPlayerOnMap();
        int GetPlayerXYPosition() const;
        void CheckScreenBounds(int choice);
        void CheckObstacleBounds();
        int GetPlayerInput();
        inline int MoveUp();
        inline int MoveDown();
        inline int MoveLeft();
        inline int MoveRight();


    private:
        char playerChar = '*';
        int playerXPos = 3;
        int playerYPos = 3;
        int playerMovement = 1;
};

#endif // PLAYER_H 


Player.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include "Player.h"

#include <iostream>

using std::cout;
using std::endl;

inline int Player::MoveUp()
{
    playerYPos -= playerMovement;

    return playerYPos;
}

inline int Player::MoveDown()
{
    playerYPos += playerMovement;

    return playerYPos;
}

inline int Player::MoveLeft()
{
    playerXPos -= playerMovement;

    return playerXPos;
}

inline int Player::MoveRight()
{
    playerXPos += playerMovement;

    return playerXPos;
}


void Player::CheckScreenBounds(int choice)
{
    switch(choice)
    {
        case 1: //Move Up
            if(playerYPos > 0)
            {
                MoveUp();
                cout << "Player Y Pos: " << playerYPos << endl;
            }
            else if(playerYPos == 0)
            {
                MoveDown();
                cout << "You cannot go any further North!\n" << endl;
            }
            break;
        case 2: //Move Down
            if(playerYPos < mapColSize -1)
            {
                MoveDown();
                cout << "Player Y Pos: " << playerYPos << endl;
            }
            else if(playerYPos == mapColSize -1)
            {
                MoveUp();
                cout << "You cannot go any further South!" << endl;
            }
            break;
        case 3: //Move Left
            if(playerXPos > 0)
            {
                MoveLeft();
                cout << "Player X Pos: " << playerXPos << endl;
            }
            else if(playerXPos == 0)
            {
                MoveRight();
                cout << "You cannot go any further West!" << endl;
            }
            break;
        case 4: //Move Right
            if(playerXPos < mapRowSize -1)
            {
                MoveRight();
            }
            else if(playerXPos == mapRowSize -1)
            {
                MoveLeft();
                cout << "You cannot go any further East!" << endl;
            }
            break;
        default:
            cout << "Not a valid option" << endl;
    }
    Game::DrawMap();
}

inline void Player::SetPlayerOnMap()
{
    mapArray[playerYPos][playerXPos] = playerChar;
}
Last edited on
Player should not implement game rules. Those should go in Game, since the game rules are conceptually part of the definition of the Game.

Friend classes should normally be used sparingly in a codebase, as they tend to significantly increase coupling. A friend declaration is often a sign that your design is inadequate.
The thing you said about a "bridge" class is totally unacceptable. In a code review I'd reject it summarily.

You're way overthinking the problem. Consider this example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
bool Chess::move_piece(Piece &piece, const Point &destination){
    if (!this->place_is_free(destination))
        return false;
    if (!this->move_is_valid(piece.get_type(), piece.get_position(), destination))
        return false;
    piece.set_position(destination);
    return true;
}

bool Chess::move_is_valid(PieceType type, const Point &location, const Point &destination){
    switch (type){
        case PieceType::Pawn:
            //...
        case PieceType::Bishop:
            //...
        //And so on.
    }
}
ok, but player position is in the player class and the map is in the game class. if im going to set the location of the player in the games map then I have to put it in the brackets of the array, I cant do that now. I'm not really sure what to do or even what to ask.
Last edited on
What do you mean? "In the brackets of the array"?
I'm starting to think you have just too many classes. Player can just go away entirely. It seems like you're trying to create a maze game with only 1 player. All of the data members and methods in player can just be put into Game. Player position can just be represented with std::pair. If this game has more than one player you can keep the Player object and have the Game class keep an array of player objects. Looking at how this works the only thing the player should have are their coordinates. Bound checking or moving up and down, left or right should be in game.
Last edited on
I don't quite agree. While moving the data in Player into Game is not "bad" for this simple game, since the player and the game itself are separate entities, it makes sense to keep both classes.
"What do you mean? "In the brackets of the array"?"

Yes, since the players X and Y coords are part of the player class, it needs to be able to be put in the mapArray brackets so the array knows where the player is and where to place them. I have solved the issue by creating a player object in game class and game object in player class. I was told

"Then, in order to access Game from within Player member functions, perhaps Player could store a pointer to the Game object that owns the Player object. "

Although im not quite sure why this is needed when i can just make a game object in player and that works fine.
Last edited on
I agree.
Last edited on
I don't.

You're writing a game. Creating a class named "Game" is redundant at best, because what's a game if not the whole program?

Although I'm not quite sure why this is needed when i can just make a game object in player and that works fine.

Including a Game in the definition of Player directly implies that a player is composed of a Game, which is ridiculous. Including a parent pointer (from Player to Game) is less wrong, but it doesn't avoid the issue with trying to create a class named Game, and is definitely not optimal.

You have a board upon which pieces may appear. Maybe the player's character is a piece?
Last edited on
I was agreeing to helios' comment. Seems these forums are still buggy in terms of updating posts on threads. And as I stated earlier, and may be others could chime in. I think all of the methods besides updating player coordinates should be included in Game.
You're writing a game. Creating a class named "Game" is redundant at best, because what's a game if not the whole program?
In this particular instance it may be redundant (but then again, this particular game is so simple that there may not be any need for OOP in the first place), but it's not redundant in the general case.
Within the same running process there will usually be only one instance of a game running concurrently, but there could be none (e.g. before a game is started or resumed) or many (e.g. if the program is a server hosting games between other players).
"In this particular instance it may be redundant (but then again, this particular game is so simple that there may not be any need for OOP in the first place), but it's not redundant in the general case."

This is just what I have so far. I want to make this a full fledged Console RPG, I just wrote the basics so I could make sure it worked. If I can just figure out how I can use objects in other classes, I can continue unabated.

So, with that said, I decided to just open a new file and write the classes with little in them so I dont lose sight of what im trying to do. So step by step here:

Step one: Create Player Object in Game and Pointer to Game Object:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>

using namespace std;


class Player;


class Game
{
    public:
        Game(Player player);
        ~Game();


    private:
        char gme_mapArray[0][0];
};


class Player
{
    public:
        Player(Game* game);
        ~Player();


    private:
        int plr_XPos = 0;
        int plr_YPos = 0;
};


int main()
{
    cout << "Hello world!" << endl;
    return 0;
}


Is this correct so far? I was told since Player is part of a game I can create an object in the Game class, but I cant create an object in the player class because then its saying that game object contains a player object and player object contains a game object, and that goes on for infinity, so thats a problem. HOWEVER, The solution I was given is that I can make a pointer to a game object which contains a player object and that would work.
The question is whether Player needs to know about Game at all. Since Player has no methods, I would default to "no".

Note that your class definitions do not say "Game contains a Player and Player contains a pointer to a Player". What they say is "the constructor for Game takes a Player by value and the constructor for Player takes a Game pointer by value". Neither class is able to store the parameters to their constructors.
Last edited on
Right but I'll need to set the players X and Y value in the map array to set the player on the map though so Game and Player will have to come into contact somehow. Disregard the fact that there isnt a player char yet, this is just an example.
Last edited on
What you'll need to do is place a representation of the player in the map to show the player's location in the world. I.e. you'll need to "draw" the player. Player does not need to know about Game to do this. Game just needs to be able to query Player's position, which can be done using a getter.
1
2
3
4
void Game::draw_player(){
    auto pos = this->player.get_position();
    this->gme_mapArray[pos.x][pos.y] = PlayerRepresentation;
}
Ok, thats exactly what im looking to do. so the player.get_position() is just a representation or is the actual player character? I assume its part of Game because this-> is pointing to it so it must be a member. then give it a player representation, but how does the code know what the actual player "sprite" is if its just a representation?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <iostream>

using namespace std;


class Player;

class Game
{
    public:
        Game(Player player);
        ~Game();

        void DrawPlayer();


    private:
        char mapArray[0][0];
        char mapTile = '-';
};

void Game::DrawPlayer()
{

}

class Player
{
    public:
        Player(Game* game);
        ~Player();

        int GetPlayerPositionX(int plrPosX);
        int GetPlayerPositionY(int plrPosY);


    private:
        int posX = 0;
        int posY = 0;
        char playerChar = 'o';
};

int Player::GetPlayerPositionX(int plrPosX)
{
    posX = plrPosX;

    return plrPosX;
}

int Player::GetPlayerPositionY(int arg_plrPosY)
{
    posY = arg_plrPosY;

    return arg_plrPosY;
}

int main()
{
    cout << "Hello world!" << endl;
    return 0;
}
'this->player' is a Player, which in the example is a member of Game, 'Player::get_position()' is a member function of Player, and 'this->player.get_position()' calls Player::get_position() passing 'this->player' as it's 'this' parameter.

Player::get_position() returns as a single object both the x and y coordinates of Player. You can use std::pair<int, int> for this, or write a class specifically for this.
Player should also not expose its x and y coordinates individually. The fact that Player stores them separately is an implementation detail which other classes need not know about. Also, this is unrelated, but the way you've written GetPlayerPositionX() and GetPlayerPositionY() makes them setters, not getters. There's no way for the caller to obtain the old values, since just calling the functions overwrites the values.

playerChar does not belong as a member of Player. Player should not be concerned how it's displayed on the screen. Ideally, not even Game should be concerned about the how, just about the where or the whether.
Pages: 12