im tryng to realize a litte fight game that use Allegro as a third part framework. I have some problem in class design, i have divided the game in 4 classes, GameCore, MainMenu, Fight, Fighter. In my mind GameCore is responsible to Initialize the game and make it run and release all the Allegro resource ( destroy display etc ). MainMenu handle the first menu, there is only 2 option Play and Option. Fight initialize the fight and draw the fighter inside the display. I'm here to improve my knowledge and find better solution so if you are reading please be patient and just give me some advice to have a better class design. I woudl like to know if exist a different way to use the class MainMenu and have player list back or modify some option related to GameCore class. The design of MainMenu class is correct or I shoudl do it different? I woudl like to know if in general is a good design or if i need to do something better considering i want it to be very clean :)
GameCore class
// This is tring to be a common game core for all fight game
#ifndef __GAMECORE_H__
#define __GAMECORE_H__
#include <allegro5/allegro.h>
#include <allegro5/allegro_image.h>
#include <allegro5/allegro_primitives.h>
#include <assert.h>
#include <allegro5/allegro_audio.h>
#include <allegro5/allegro_acodec.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_ttf.h>
// class include
#include "./Menus/MainMenu.h"
#include "./Fight/Fight.h"
#include <iostream>
#include <string>
#include <vector>
// Game core handle the init and the start of the game
class GameCore
{
private:
// game costruction variables
int screenWidth;
int screenHeight;
int fps;
bool fullscreen;
// game variable
bool running;
// allegro variables
ALLEGRO_DISPLAY *display = NULL; // display pointer
ALLEGRO_TIMER *timer = NULL; // timer pointer
ALLEGRO_EVENT_QUEUE *event_queue = NULL; // event queue pointer
public:
// definizioni costruttori
GameCore(const int screenWidth, const int screenHeight, const int fps, const bool fullscreen);// costruttore, prende in ingresso le impostazioni di default
bool Init(); // inizialize everithing we need for allegro, create pointers etc
void StartGame(); // Start Game
void Release(); // release everithing we need for allegro, destroy pointers etc
};
#endif
GameCore function implemntation
#include "GameCore.h"
GameCore::GameCore(int screenWidth, int screenHeight, int fps, bool fullscreen)
{
// initialize variables
this->screenWidth = screenWidth;
this->screenHeight = screenHeight;
this->fps = fps;
this->fullscreen = fullscreen;
}
bool GameCore::Init()
{
// initialize allegro
if (!al_init())
{
std::cout << "failed to initialize allegro!" << std::endl;
return false;
}
// initialize graphics primitives
if (!al_init_primitives_addon())
{
std::cout << "failed to initialize primitives addon!" << std::endl;
return false;
}
// install keyboard
if (!al_install_keyboard())
{
std::cout << "failed to initialize the keyboard!" << std::endl;
return false;
}
// install mouse
if (!al_install_mouse())
{
std::cout << "failed to initialize the mouse!" << std::endl;
return false;
}
// create the display with the resolution that i set
if (fullscreen)
{
al_set_new_display_flags(ALLEGRO_FULLSCREEN);
}
else
{
al_set_new_display_flags(ALLEGRO_WINDOWED);
}
display = al_create_display(screenWidth, screenHeight);
// display error if display is not created
if (!display)
{
std::cout << "failed to create display!" << std::endl;
return false;
}
// allegro event queue
event_queue = al_create_event_queue();
if (!event_queue)
{
std::cout << "Failed to create event_queue!" << std::endl;
al_destroy_display(display);
return false;
}
// allegro timer
timer = al_create_timer(1.0 / fps);
if (!timer)
{
std::cout << "failed to create timer!" << std::endl;
al_destroy_display(display);
al_destroy_event_queue(event_queue);
return false;
}
// init audio addon
if (!al_init_image_addon())
{
std::cout << "failed to initialize image addon!" << std::endl;
al_destroy_display(display);
al_destroy_event_queue(event_queue);
al_destroy_timer(timer);
return false;
}
// init font addon
if (!al_init_font_addon())
{
std::cout << "failed to initialize font addon!" << std::endl;
al_destroy_display(display);
al_destroy_event_queue(event_queue);
al_destroy_timer(timer);
return false;
}
// init ttf addon
if (!al_init_ttf_addon())
{
std::cout << "failed to initialize ttf addon!" << std::endl;
al_destroy_display(display);
al_destroy_event_queue(event_queue);
al_destroy_timer(timer);
return false;
}
// timer start
al_start_timer(timer);
running = true;
return true;
}
void GameCore::StartGame()
{
// Create main menu scene
MainMenu mainMenu(screenWidth, screenHeight, display, timer, event_queue);
// load menu scene
mainMenu.OnSceneLoad();
// run Menu loop
std::vector<std::string> players = mainMenu.RunMenu();
// Create fight scene
Fight fight(screenWidth, screenHeight, players, display, timer, event_queue);
// load fight scene
fight.OnSceneLoad();
// run fight loop
std::vector<std::string> result = fight.RunFight();
// print result trought an exit menu
}
void GameCore::Release()
{
// destroy the timer
if (timer)
{
al_destroy_timer(timer);
}
// destroy the event queue
if (event_queue)
{
al_destroy_event_queue(event_queue);
}
// destroy the display
if (display)
{
al_destroy_display(display);
}
// unistall allegro keyboard
al_uninstall_keyboard();
// unistall allegro mouse
al_uninstall_mouse();
}
MainMenu class
#ifndef __MAIN_MENU_H__
#define __MAIN_MENU_H__
#include <vector>
#include <string>
#include <iostream>
#include <functional>
#include <allegro5/allegro.h>
#include <allegro5/allegro_image.h> // to use the bitmap structure
#include <allegro5/allegro_font.h> // to use the font structure
#include <allegro5/allegro_ttf.h> // to use the font structure
class MainMenu
{
private:
// draw variables
int width;
int height;
// allegro variables
ALLEGRO_EVENT_QUEUE *event_queue = NULL;
ALLEGRO_EVENT event;
ALLEGRO_DISPLAY *display = NULL;
ALLEGRO_TIMER *timer = NULL;
// fonts
ALLEGRO_FONT *TitleFont = NULL;
ALLEGRO_FONT *OptionFont = NULL;
// background
ALLEGRO_BITMAP *background = NULL;
// menu variables
bool running;
int selectedOption;
std::vector<std::string> selection;
// draw function
void DrawMenu();
// keyboard inputhandling
void HandleKeyboardInput(ALLEGRO_EVENT ev);
public:
MainMenu(const int& width, const int& height, ALLEGRO_DISPLAY*& display, ALLEGRO_TIMER*& timer, ALLEGRO_EVENT_QUEUE*& event_queue); // create menu with options and flags
void OnSceneLoad(); // load the menu
std::vector<std::string> RunMenu(); // start the menu return always the list of player selected
~MainMenu(); // destroy the menu and free memory
};
#endif```
MainMenu function implementation
#include "./MainMenu.h"
MainMenu::MainMenu(const int& width, const int& height, ALLEGRO_DISPLAY*& display, ALLEGRO_TIMER*& timer, ALLEGRO_EVENT_QUEUE*& event_queue)
{
this->width = width;
this->height = height;
this->display = display;
this->timer = timer;
this->event_queue = event_queue;
this->running = true;
this->selectedOption = 0;
}
void MainMenu::OnSceneLoad()
{
// load title font
TitleFont = al_load_ttf_font("/home/jimmy/Documents/project/FistsOfFury/Fonts/ARCADE_I.TTF", 100, 0);
if (!TitleFont)
{
std::cout << "Error loading Title font" << std::endl;
exit(1);
}
// load option font
OptionFont = al_load_ttf_font("/home/jimmy/Documents/project/FistsOfFury/Fonts/ARCADE_I.TTF", 50, 0);
if (!OptionFont)
{
std::cout << "Error loading Option font" << std::endl;
exit(1);
}
// load background
/* background = al_load_bitmap("/home/jimmy/Documents/project/FistsOfFury/GameCore/Menus/Asset/MenuBackground.png");
if (!background)
{
std::cout << "Error loading Main menu background" << std::endl;
exit(1);
}
*/
// register events
al_register_event_source(event_queue, al_get_keyboard_event_source());
al_register_event_source(event_queue, al_get_mouse_event_source());
al_register_event_source(event_queue, al_get_display_event_source(display));
al_register_event_source(event_queue, al_get_timer_event_source(timer));
std::cout << "Main MenuScene Loaded" << std::endl;
}
std::vector<std::string> MainMenu::RunMenu()
{
// player slected
std::vector<std::string> selection;
while (running)
{
// wait for event
al_wait_for_event(event_queue, &event);
// draw the menu
if (event.type == ALLEGRO_EVENT_TIMER)
{
DrawMenu();
}
// close the game if the player cloase window
if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
{
running = false;
exit(0);
}
// if the event is a keyboard event then we check if the user pressed a key
if (event.type == ALLEGRO_EVENT_KEY_DOWN)
{
HandleKeyboardInput(event);
}
}
return selection;
}
void MainMenu::DrawMenu()
{
// clear the display
al_clear_to_color(al_map_rgb(0, 0, 0));
// draw the background and adapt it to the screen size
// al_draw_scaled_bitmap(background, 0, 0, al_get_bitmap_width(background), al_get_bitmap_height(background), 0, 0, width, height, 0);
// draw the title
al_draw_text(TitleFont, al_map_rgb(255, 255, 255), width / 2, height / 4, ALLEGRO_ALIGN_CENTER, "Fists Of Fury");
// draw the options
al_draw_text(OptionFont, al_map_rgb(255, 255, 255), width / 2, height / 2, ALLEGRO_ALIGN_CENTER, "Play");
al_draw_text(OptionFont, al_map_rgb(255, 255, 255), width / 2, height / 2 + 100, ALLEGRO_ALIGN_CENTER, "Options");
// draw pointer to the selected option
al_draw_text(OptionFont, al_map_rgb(255, 255, 255), width / 2 - 300, height / 2 + 100 * selectedOption, ALLEGRO_ALIGN_CENTER, ">");
// flip the display
al_flip_display();
}
// function that handle Keyboard input
void MainMenu::HandleKeyboardInput(ALLEGRO_EVENT ev){
switch (ev.keyboard.keycode) // if the user pressed enter then we check which option is selected
{
case ALLEGRO_KEY_UP:
selectedOption--;
if (selectedOption < 0)
{
selectedOption = 1;
}
break;
case ALLEGRO_KEY_DOWN:
selectedOption++;
if (selectedOption > 1)
{
selectedOption = 0;
}
break;
case ALLEGRO_KEY_ENTER: // if the user pressed enter then we check which option is selected
switch (selectedOption) //switch betwin the option
{
case 0:
std::cout << "Play" << std::endl;
selection = {"Ninja", "Samurai", "Pirate"};
running = false;
break;
case 1:
std::cout << "Options" << std::endl;
// I NEED TO CREATE A OPTIONS MENU
break;
}
break;
}
}
// distructor function to deallocate allegro thing
MainMenu::~MainMenu()
{
// destroy the title font
al_destroy_font(TitleFont);
// destroy the option font
al_destroy_font(OptionFont);
// destroy the background
al_destroy_bitmap(background);
}
Fight class
#ifndef __FIGHT_H__
#define __FIGHT_H__
#include <vector>
#include <iterator>
#include <string>
#include <iostream>
#include <allegro5/allegro.h>
#include <allegro5/allegro_image.h> // to use the bitmap structure
#include <allegro5/allegro_font.h> // to use the font structure
#include <allegro5/allegro_ttf.h> // to use the font structure
#include "../Fighter/Fighter.h"
class Fight
{
private:
// fight variable
std::vector<Fighter *> fighters;
// draw variables
int width;
int height;
ALLEGRO_FONT *scoreFont;
// Allegro variables
ALLEGRO_BITMAP *background;
ALLEGRO_EVENT_QUEUE *event_queue;
ALLEGRO_EVENT event;
ALLEGRO_DISPLAY *display;
ALLEGRO_TIMER *timer;
void DrawFight(); // draw the fight scene
public:
// create fight scene with options and flags, fighters and width and height
Fight(const int& width, const int& height, std::vector<std::string>& players, ALLEGRO_DISPLAY*& display, ALLEGRO_TIMER*& timer, ALLEGRO_EVENT_QUEUE*& event_queue);
void OnSceneLoad(); // load the fight scene
std::vector<std::string> RunFight(); // start the fight scene
};
#endif
Fight function implementation
#include "./Fight.h"
Fight::Fight(const int& width, const int& height, std::vector<std::string>& players, ALLEGRO_DISPLAY*& display, ALLEGRO_TIMER*& timer, ALLEGRO_EVENT_QUEUE*& event_queue)
{
this->width = width;
this->height = height;
this->display = display;
this->timer = timer;
this->event_queue = event_queue;
// create player array
for (std::vector<std::string>::const_iterator i = players.begin(); i != players.end(); ++i)
{
Fighter *fighter = new Fighter(*i);
fighters.push_back(fighter);
}
}
void Fight::OnSceneLoad()
{
// load score font
scoreFont = al_load_ttf_font("/home/jimmy/Documents/project/FistsOfFury/Fonts/ARCADE_I.TTF", 50, 0);
// load background
background = al_load_bitmap("/home/jimmy/Documents/project/FistsOfFury/Assets/Backgrounds/FightBackground.png");
if (!background)
{
std::cout << "Error loading Fight background" << std::endl;
exit(1);
}
// register events
al_register_event_source(event_queue, al_get_keyboard_event_source());
al_register_event_source(event_queue, al_get_mouse_event_source());
al_register_event_source(event_queue, al_get_display_event_source(display));
al_register_event_source(event_queue, al_get_timer_event_source(timer));
std::cout << "Fight Scene Loaded" << std::endl;
}
std::vector<std::string> Fight::RunFight(){
// start the fight scene
}
i've just try to do the best i can