-1

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

  • 1
    Questions about code that works but you think can work better should be asked at [Code Review](https://codereview.stackexchange.com/help/asking). Give the link a read and see if your question meets their requirements. If this is a question about a problem with the code, it doesn't qualify for Code Review, but you'll have to be a lot more explicit about the problem for the question to fit in here. – user4581301 Aug 29 '23 at 18:01
  • Side note: Give [What are the rules about using an underscore in a C++ identifier?](https://stackoverflow.com/q/228783/4581301) a read because you are breaking them. It probably won't bite you, but when it does, it's an extreme mind that's best avoided completely. – user4581301 Aug 29 '23 at 18:02

0 Answers0