



My portfolio: https://www.artstation.com/artist/marcusaseth
My first suggestion is that you don't need to have a list of classes up-front. If we tried to do that for AAA games we'd never start coding.
My other comments:
I usually start at the global picture, instead of the small details. What data do you have, what activities must be done (at high level, so "game map", "textures", "character", and "drawing the screen" is more than enough.
Make big building blocks (eg on a single sheet of paper) where those things roughly go. It should give you an overview of the program as a whole, even though your picture may be wrong, but the only way to find out is by trying to build it.
You will hit dead ends, but it's part of the process. Programs are so complicated, it is impossible to get all the details right on the first try. Don't be afraid of it, learn to recognize it happening, and how to recover from it.
Finally, nobody says you must do all coding in one project. If you want to figure out how to do some detail, eg movement with keys or so, and you don't know how, use paper and your grey matter to work it out. If it needs experimenting, make a small side-program for experiments. When done, apply the knowledge in your main project (which may include code of the experiment, but in general rewriting improves code).
A classic issue for a lot of people (myself included) is the tendency to over engineer things. Frankly the best way to learn what you need is to just make something and set small goals, milestones if you will. I used to create these really complicated classes before even knowing what I needed, but often it either got thrown away or simply went unused or the architecture changed somewhat so I had to rewrite it anyway. For example, since you're making a breakout game you might just want to start simple, "well I need a game loop and a window, now I need to draw something onscreen, now I need to make a ball, okay now the ball needs to bounce against the edges of the screen and re-spawn."
The first two things you mentioned are fine, for the texture manager I would question if you even need one. Is the game complex enough that sprites require managing? Honestly in most arcade games that isn't the case, sprites may be used only once and the entire game contains a small enough number of them for you to simply load them all in some function and pass them around. Important questions are things like -when- to load them too, if you can you might as well load them all at the start. Frankly unless you KNOW for a fact that you need something to be complex, it is almost always better to start off simple and build up from there.
Thank you for answering guys
QuoteThe first two things you mentioned are fine, for the texture manager I would question if you even need one. Is the game complex enough that sprites require managing?
Frankly unless you KNOW for a fact that you need something to be complex, it is almost always better to start off simple and build up from there.
I see that point, though my point would be that all the games in the list of games a begginner should make seems like they don't require a TextureManager as well, so even if I don't need a TextureManager right now or to learn how to make a Singleton, when do I get to learn it then?!
I am kind of throwing extra stuff in exactly because the project is simple, so the scale is small and I can learn this concepts in realive comfort/safety.
So from my point of view, I actually value something that over-complicate the project if it is just for the sake of learning a new thing, basically making this game is not really the main goal. So if you guys think I could research and apply an interesting design pattern to this project feel free to suggest, because for me is an opportunity to fiinally learn a new/useful thing
My portfolio: https://www.artstation.com/artist/marcusaseth
3 minutes ago, MarcusAseth said:I see that point, though my point would be that all the games in the list of games a begginner should make seems like they don't require a TextureManager as well, so even if I don't need a TextureManager right now or to learn how to make a Singleton, when do I get to learn it then?!
I am kind of throwing extra stuff in exactly because the project is simple, so the scale is small and I can learn this concepts in realive comfort/safety.
So from my point of view, I actually value something that over-complicate the project if it is just for the sake of learning a new thing, basically making this game is not really the main goal. So if you guys think I could research and apply an interesting design pattern to this project feel free to suggest, because for me is an opportunity to fiinally learn a new/useful thing
Which is fine, I experiment with ideas myself on a regular basis, the problem is it becomes easy for you to start doing that for everything. Particularly when it is that, experimenting, you can quickly get in over your head and make the code a mess of things you aren't sure are good architecture, and dig yourself into a corner that it feels frustrating to get out of.
Sometimes it might be better to experiment on standalone tech demos and things, or to save writing something complex like that until you actually need it. That's a bit of an unspoken rule that people don't often actually explain, software only gets complicated because it needs to. If you could write the next Battlefield game just by making a function that loads all the game data at the start and not bother with subsystems dedicated to managing things, then they probably would.
You might want to consider that the faster you finish a game the faster you get to try another project as well, and possibly explore more concepts or have more challenging rules to write for.
6 minutes ago, MarcusAseth said:all the games in the list of games a begginner should make seems like they don't require a TextureManager as well, so even if I don't need a TextureManager right now or to learn how to make a Singleton, when do I get to learn it then?!
Done some progress, I'm thinking to paste here the code I write during this project in case someone notices and point out some ugly stuff I may end up doing so that I avoid ending up with bad coding habits.
I'll put it into spoiler just to not flood the entire page with a single reply
The only problem I am currently having is inside Game.cpp, code below:
#define BACKGROUND "Graphics/Background.png";
#define PADDLE "Graphics/Paddle.png";
#define BALL "Graphics/Ball.png";
Game::Game(SDL_Window* Window, SDL_Renderer* Renderer)
:Window{ Window }, Renderer{ Renderer }
{
LoadImage(BACKGROUND);
LoadImage(PADDLE);
LoadImage(BALL);
}
LoadImage takes a const char* but those 3 macro are not expanding into that for some reason, since VS is giving me a red squigly line... what argument type should that function take in order to work with my Macros?
main.cpp
#include <iostream>
#include "SDL2\SDL.h"
#include "SDL2\SDL_image.h"
#include "App.h"
int main(int argc, char* argv[])
{
App GameClient;
while (GameClient.IsRunning())
{
}
return 0;
}
App.h
#pragma once
#include "SDL2\SDL.h"
#include "Game.h"
class App
{
bool Running = false;
Uint32 Width = 1280;
Uint32 Height = 960;
Uint32 WinFlags = 0;
Uint32 RenFlags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC;
SDL_Window* Window;
SDL_Renderer* Renderer;
Game* GameInstance;
bool Init();
bool CreateWindow();
bool CreateRenderer();
public:
App();
~App();
App(const App&) = delete;
App& operator=(const App&) = delete;
App(App&&) = delete;
App& operator=(App&&) = delete;
////
inline bool IsRunning()const { return Running; }
};
App.cpp
#include "App.h"
#include "Utility.h"
App::App()
:Window{ nullptr }, Renderer{ nullptr }
{
Running = Init();
if (Running)
{GameInstance = new Game(Window, Renderer);}
}
App::~App()
{
if (Window) { SDL_DestroyWindow; }
if (Renderer) { SDL_DestroyRenderer; }
delete GameInstance;
SDL_Quit();
}
bool App::Init()
{
if ( 0 != SDL_Init(SDL_INIT_EVERYTHING)){ return Error(SDL_GetError()); }
return CreateWindow() ? (CreateRenderer() ? true : false) : (false);
}
bool App::CreateWindow()
{
Window = SDL_CreateWindow("Breakout",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
Width, Height, WinFlags);
return Window ? true : Error(SDL_GetError());
}
bool App::CreateRenderer()
{
Renderer = SDL_CreateRenderer(Window, -1, RenFlags);
return Renderer ? true : Error(SDL_GetError());
}
Game.h
#pragma once
#include <map>
#include <string>
#include "SDL2\SDL.h"
class Game
{
SDL_Window* Window;
SDL_Renderer* Renderer;
std::map<std::string, SDL_Texture*> Textures;
bool LoadImage(const char* path);
public:
Game(SDL_Window* Window, SDL_Renderer* Renderer);
~Game();
Game(const Game&) = delete;
Game& operator=(const Game&) = delete;
Game(Game&&) = delete;
Game& operator=(Game&&) = delete;
////
SDL_Texture* GetTexture(const char* path)const;
};
Game.cpp
#include "Game.h"
#include "Utility.h"
#include "SDL2\SDL_image.h"
#define BACKGROUND "Graphics/Background.png";
#define PADDLE "Graphics/Paddle.png";
#define BALL "Graphics/Ball.png";
Game::Game(SDL_Window* Window, SDL_Renderer* Renderer)
:Window{ Window }, Renderer{ Renderer }
{
LoadImage(BACKGROUND);
LoadImage(PADDLE);
LoadImage(BALL);
}
Game::~Game()
{
for (auto& elem : Textures)
{ SDL_DestroyTexture(elem.second); }
}
bool Game::LoadImage(const char * path)
{
if (Textures.find(path) != Textures.end())
{ return Error("Ettempting to Load an already Loaded Texture."); }
SDL_Surface* Surface = IMG_Load(path);
if (Surface)
{
Textures[path] = SDL_CreateTextureFromSurface(Renderer, Surface);
SDL_FreeSurface(Surface);
return true;
}
else
{ return Error(SDL_GetError()); }
}
SDL_Texture* Game::GetTexture(const char* path)const
{
auto& Texture = Textures.find(path);
return (Texture != Textures.end()) ? Texture->second : nullptr;
}
Actor.h
#pragma once
#include "SDL2\SDL.h"
#include "Game.h"
enum class PivotMode: Uint8 {CENTER,TOP_LEFT};
class Actor
{
SDL_Texture* RequestTexture(const char* path)const;
void SetSpriteRect(Uint32 x, Uint32 y, PivotMode InputMode);
protected:
Uint32 XCenter;
Uint32 YCenter;
SDL_Rect SpriteRect;
SDL_Texture* Sprite;
Game* GameRef;
public:
Actor(Game* GameRef, PivotMode InputMode, Uint32 x, Uint32 y, const char* path);
virtual ~Actor();
Actor(const Actor&) = delete;
Actor& operator=(const Actor&) = delete;
Actor(Actor&&) = delete;
Actor& operator=(Actor&&) = delete;
////
};
Actor.cpp
#include "Actor.h"
#define BACKGROUND "Graphics/Background.png";
#define PADDLE "Graphics/Paddle.png";
#define BALL "Graphics/Ball.png";
Actor::Actor(Game* GameRef,PivotMode InputMode, Uint32 x, Uint32 y, const char* path)
:GameRef{ GameRef }
{
if (GameRef)
{Sprite = RequestTexture(path);}
if (Sprite)
{SetSpriteRect(x, y, InputMode);}
}
Actor::~Actor()
{
}
SDL_Texture* Actor::RequestTexture(const char* path)const
{
return GameRef->GetTexture(path);
}
void Actor::SetSpriteRect(Uint32 x, Uint32 y, PivotMode InputMode)
{
SDL_QueryTexture(Sprite, NULL, NULL, &SpriteRect.w, &SpriteRect.h);
switch (InputMode)
{
case PivotMode::CENTER:
{
SpriteRect.x = x - SpriteRect.w / 2;
SpriteRect.y = y - SpriteRect.h / 2;
XCenter = x;
YCenter = y;
}break;
case PivotMode::TOP_LEFT:
{
SpriteRect.x = x;
SpriteRect.y = y;
XCenter = x + SpriteRect.w / 2;
YCenter = y + SpriteRect.h / 2;
}break;
}
}
My portfolio: https://www.artstation.com/artist/marcusaseth
53 minutes ago, MarcusAseth said:Done some progress, I'm thinking to paste here the code I write during this project in case someone notices and point out some ugly stuff I may end up doing so that I avoid ending up with bad coding habits.
Don't use macros for constants. Use "const" or "constexpr" (if your version of C++ has it).
What is the actual error you're getting when you compile? The "red underlines" produced by Visual Studio are produced by the Intellisense compiler, which is (a) different from the compiler that actually builds your code and (b) often wrong.
I didn't had tried to compile so far (until you asked), otherwise I would have realized that I shouldn't put the ';' at the end of the macro, which was expanding the ';' into LoadImage("Graphics/Background";); :P
Anyway I'll go with constexpr then, thanks
My portfolio: https://www.artstation.com/artist/marcusaseth