3
\$\begingroup\$

I'm making a simple 2D framework / engine for the first time based on two books and before the project gets too big I would like to know if I'm ordering things the right way. Maybe there are better ways of doing this. I tried to apply patterns so I could decouple as much as possible and keep things abstract.

For example this is the Game class:

#include "Game.h"

void Game::Create(int width, int height, const char * title, int window_flag, int renderer_flag){
      display.CreateWindow(800,600,"Game", SDL_WINDOW_SHOWN, SDL_RENDERER_ACCELERATED);
}

void Game::Start(){
      Uint32 first_frame_ticks; float delta_time = 0;
      SDL_Renderer * renderer = display.GetRenderer();
      while(input_handler.GetLastEvent() != SDL_QUIT){
            first_frame_ticks = SDL_GetTicks();

            bool state_manager_empty = state_manager.isEmpty();
            //update
            input_handler.Update();
            if(!state_manager_empty) state_manager.GetGameState()->onUpdate(delta_time);

            //render
            SDL_RenderClear(renderer);
            if(!state_manager_empty) state_manager.GetGameState()->onRender();
            SDL_RenderPresent(renderer);

            delta_time = (SDL_GetTicks() - first_frame_ticks) / 1000.0f;
      }

      display.Clear();
}

void Game::AddState(GameState* state){
      state->Set(display.GetRenderer(), &input_handler);
      state_manager.Add(state);
}

Or the Drawer class (wich I have some doubts about, the DrawEntity method is static)

#include "Drawer.h"

void Drawer::DrawEntity(Entity& entity, TextureManager* texture_manager, SDL_Renderer * renderer){
      texture_manager->Draw(entity.GetSprite(), entity.GetPosition(), renderer);
}

It acts like a mediator between TexureManager(wich draws texures) and Entity wich has all the information like position, scale, etc.

Finally the example input class

#include "InputHandler.h"
#include <cstdio>

InputHandler::InputHandler(){
      keyboard_state = SDL_GetKeyboardState(NULL);
      printf("Event handler initialized\n");
}

void InputHandler::Update(){
      SDL_Event ev;
      while(SDL_PollEvent(&ev)){
            if(ev.type == SDL_KEYUP || ev.type == SDL_KEYDOWN){
                  keyboard_state = SDL_GetKeyboardState(NULL);
            }else last_event = ev.type;
      }
}

bool InputHandler::isKeyPressed(SDL_Scancode key){
      if(keyboard_state[key]) return true;
      else return false;
}

Uint32 InputHandler::GetLastEvent(){
      return last_event;
}

I'm going to upload a dependency diagram as well as the GitHub repo: enter image description here

Github Repo with all the Code

https://github.com/grazianobolla/monke-engine

\$\endgroup\$
1
  • 4
    \$\begingroup\$ Long code isn't frowned upon on code review, you should post your full project here \$\endgroup\$
    – user228914
    Oct 13, 2020 at 21:00

1 Answer 1

0
\$\begingroup\$

Update:

Well, if someone wants to know, I've done some changes for good, one of the main problems I had was that I couldn't really "connect" the GameStates to the main Engine itself without passing a pointer to the engine (wich is messy) or individual pointers to the InputHandler, Display, etc.

The thing was that for example the InputHandler handled the Window events and the keyboard input, so for a GameState to have access to it, I would have to create a pointer to Game::InputHandler, so I did a few things:

First I created a KeyboardHandle class wich is totally independent from the Engine itself and its only function its to get keyboard input, that way I can make every game state to have an independent KeyboardHandle, also every game state has a pointer to the engine Display class, that means that from the game state you can get access to information like windows size or the SDL_Renderer without having much trouble, you add states from the Engine so the Display pointer is set at that moment.

The GameState class is the base for all games, now it looks like this:

#pragma once
#include "KeyboardHandle.h"
#include "TextureManager.h"
#include "Display.h"

class GameState{
protected:
      KeyboardHandle keyboard;
      TextureManager texture_manager;
      Display * screen_display;
public:
      GameState(Display * display){ this->screen_display = display; }
      virtual void onStart() = 0;
      virtual void handleInput() = 0;
      virtual void onUpdate(float) = 0;
      virtual void onRender() = 0;
};

As you can see is almost all independent from the Engine, it just shares the display so we can render the graphics.

Here is an example state (drawing an image on the center of the screen):

#include "GameState.h"
#include "Entity.h"

class DefaultState : public GameState{
      Entity splash_logo;
public:
      DefaultState(Display * display) : GameState(display){ }

      void onStart(){
            texture_manager.Load("textures/splash_logo.png", "splash_logo", screen_display->GetRenderer());
            splash_logo = Entity("splash_logo", Vector2i(0, 0), Vector2i(336, 336), 1.0f);

            float center_x = (screen_display->GetWindowWidth() / 2) - splash_logo.GetCollisionBox().w / 2;
            float center_y = (screen_display->GetWindowHeight() / 2) - splash_logo.GetCollisionBox().h / 2;
            splash_logo.SetPosition({center_x, center_y});
      }

      void handleInput(){

      }

      void onUpdate(float delta_time){

      }

      void onRender(){
            texture_manager.Draw(splash_logo.GetSprite(), splash_logo.GetPosition(), screen_display->GetRenderer());
      }
};

And just for fun here is the dependency diagram: Dependency Diagram

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.