0

I am coding the arcade game pong for an introduction to c++ project at university. The game has a one player practice mode where the ball simply bounces off the opposite side of the screen and a two player mode using the w and s keys for player 1's paddle movement and up and down keys for player 2's movement. I had originally written the game in one class but after consultation with my lecturer he had suggested to construct the game using three classes for extra merit.

Fl_Window
 ^
 |
Game Interface
^            ^
|            |
One Player   Two Player

The diagram my lecturer sent me can be seen above.

I have a game interface class that contains methods common to both game modes (e.g. drawing the ball, collisions off the top and bottom of the screen and moving player 1's paddle) and two other classes for the one player and two player modes that contain methods specific to the mode (e.g. moving player 2's paddle, a scoring system and drawing player 2's paddle).

Initially I create an instance of the game interface class and run an initialise game menu function which creates a menu with choice of game mode. When either mode is selected a function within the game interface class wipes the menu widgets, draws player 1's paddle, draws the ball and sends the ball off in a random direction with constant speed.

What I then wish to happen is for an instance of the correct game mode class to be created and another specific initialise function (either one player or two player) from within that class to run.

I also want to be able to return from any game mode to the main menu and be able to select another mode.

This is my first ever c++ large scale project so forgive me for poor overall conceptual understanding!

How and where would I create these instances of the specific game mode classes? Within the base game interface class or in main?

I intialise the game menu like this:

//Main Function
int main()
{
GameInterface MyInterface(GameInterface::WindowSizeX,
GameInterface::WindowSizeY, "PONG");
MyInterface . InitialiseMenu();                                                             

return Fl::run();                                                                           
} 

Which runs the function:

void GameInterface :: InitialiseMenu()
{
begin();

MenuTitle = new Fl_Box (400, 50, 100, 50, "Welcome to PONG");
MenuTitle -> labelcolor (FL_WHITE);
MenuTitle -> labelsize (MenuTitleTextSize);
MenuTitle -> box (FL_NO_BOX);
MenuTitle -> show();

TwoPlayerMode = new Fl_Button (400, 300, 150, 50, "Two Player Mode");
TwoPlayerMode -> callback(TwoPlayerMode_cb, this);
TwoPlayerMode -> show();

show();
}

(Note: I'm currently just attempting to get the 2 player class to work with the game interface before I try and get all three classes working)

The callback function used is:

//Define two player mode button call back function
void GameInterface :: TwoPlayerMode_cb(Fl_Widget* w,void* data )
{
((GameInterface*) data) -> TwoPlayerMode_cb_i(w);  
} 

void GameInterface :: TwoPlayerMode_cb_i(Fl_Widget* w)
{
TwoPlayerMode -> hide();
MenuTitle -> hide();
InitialiseGameObjects();

}

The initialise game object function is:

//Define initialise game objects
void GameInterface :: InitialiseGameObjects()
{
Fl::add_timeout(0.01, GameInterfaceUpdate_cb, this);

begin();

Ball =  new Fl_Box (400, 300, 10, 10);
Ball -> box(FL_FLAT_BOX);
Ball -> color (FL_WHITE);
Ball -> show();    

Player1Paddle = new Fl_Box(0, 300, PaddleSizeX, PaddleSizeY);
Player1Paddle -> box(FL_FLAT_BOX);
Player1Paddle -> color(FL_WHITE);
Player1Paddle -> show();

InitialBallDirectionGenerator();

BallVelocityX = InitialBallDirectionX * InitialBallSpeed;


BallVelocityY = InitialBallDirectionY * InitialBallSpeed;

//TwoPlayerModeInitialise_i();

end(); 

}

At the point where it reads //TwoPlayerModeInitialise_i(); I wish for a method contained in the two player class to run that initialises the other objects, functions etc that are required for the two player game mode. I assume I need to make the instance of that class at this point? I then wish for the methods from both classes to control the game (e.g. player 1's paddle movement comes from the game interface class and player 2's paddle movement comes from the two player mode class).

My classes are made like this:

//Game Interface Class
class GameInterface : public Fl_Window
{
//Defining Public Members
public:                                                 
GameInterface(int width, int height, const char* title=0) : Fl_Window(width, height, title)     
{
color(FL_BLACK);                                                                        
show();                                                                                 
}
...
};

&

class TwoPlayerMode : public GameInterface 
{
...
};

Any help would be greatly appreciated as I really have got stuck at where to go next! Thanks.

2 Answers2

0

I would recommend adding the public function GameInterface getBaseClass() { return *this; } to GameInterface, and then when it is called on a subclass' instance, it should return the main base class.

Then, you can make a constructor in one or two player that takes a GameInterface and sends that up the line:

OnePlayer(GameInterface base) : GameInterface(base) {
    //here you could call any additional init functions
}

EDIT: An abstract example that works when I test it

class Base {
protected:
    int x;

public:
    Base(int x) : x(x) {}
    Base getBaseClass() { return *this; }
    virtual int getX() {
        return x + 1;
    }
};

class Derived : public Base {
public:
    Derived(Base b) : Base(b) {}

    Base getBaseClass() {

    }

    int getX() {
        return x;
    }
};

int main() {
    Base t(6);
    Derived d(t);
    std::cout << d.getX() << '\n'; //6

    Base y = d.getBaseClass();
    std::cout << y.getX() << '\n'; //7
}
Eadword
  • 160
  • 1
  • 11
  • Thanks for the help but I still don't understand the following: 1) Do I have to make an instance of a class in order to use its methods? 2) If so, how and where would I create this instance for the subclass? – Sam Clatworthy Jan 01 '15 at 23:18
  • 1. If they are static they can be run without an instance, but these are not. Note that the Constructor is an exception because it returns the new object. 2. The subclass would be made when you want to convert over because they made the choice. With player one as an example it would be OnePlayer gamedata(gameinterface); – Eadword Jan 02 '15 at 00:50
  • I've attempted to create the instance of the subclass the way you suggested but I can't then seem to call methods from it at all, why is there such difficulty creating an instance of a derived class from a base class that is derived from Fl_Window? – Sam Clatworthy Jan 06 '15 at 15:59
  • I am adding an example that I had made... When you are attempting to construct it, are you using a pointer? If so use the asterisk *nameofref to get the object, which is what you need to construct with. – Eadword Jan 07 '15 at 14:24
0

You should design the game mode so that it initialises the players in an array. In one-player mode the array only has one Player object in it. In two-player mode it has 2. This way many functions can be the same in both classes.

Any functions that you want to override in the derived classes should be declared virtual in the base class to allow it to be polymorphic. Remember to declare the destructor as virtual in the base class too!

You should use a POINTER to a GameInterface object because pointers are polymorphic and can then be either game mode...

// create a pointer to a GameInterface object
GameInterface *game;

// start one player mode
game = new OnePlayer();
game->run();

// before you change the game mode delete the current game
delete game;

// start two player mode
game = new TwoPlayer();
game->run();

You could create a wrap around class for the menu if you didn't want to have any code in the main. Then just create a menu object in the main and run it:

int main()
{
// assuming default constructor exists, create the menu
GameSelectMenu menu;

// run the menu
menu.run();

return 0;
}

The menu class itself would hold the GameInterface pointer and it would be responsible for managing memory when switching game modes. You can create functions for running different modes that would assign the GameInterface* as either a OnePlayer or TwoPlayer object. It would also be where you create the user interface for the actual menu so the user can actually change the game mode...

//.. Within run() function of menu class

std::string input;
std::cout << "choose a game (enter 'a' or 'b'): "
std::cin>> input;

// check input for errors
...

// run a mode depending on input
if (input == "a") startOnePlayer();
else if (input == "b") startTwoPlayer();

 // remember to delete the GameInterface object when you have finished with it if it has been initialised
if (game != NULL) delete game;

...
user2796283
  • 273
  • 4
  • 8