C++ Breakout game using SDL











up vote
1
down vote

favorite












I did a big mistake to create procedural C++ breakout game on start and now im having trouble converting it into OOP.



As far as I can see I need classes: Loptica (eng. Ball), Splav (eng. Paddle), Blok (eng. Block), Logika (eng. Logic), Kolizija (eng, Collision), Level (eng. Level)



Definition:



#include "SDL.h"
#include "SDL_image.h"
#include <ctime>
#include <stdlib.h>
#include <iostream>
#include <Windows.h>
#include <utility>
#include <string>
#include <vector>
#include <algorithm>

#undef main
using namespace std;

SDL_Window *ekran;
SDL_Renderer * renderer = NULL;

SDL_Texture * pozadina = NULL; //background
SDL_Texture * splav = NULL; //paddle
SDL_Texture * loptica = NULL; //ball
SDL_Texture * block01 = NULL; //1st row of blocks
SDL_Texture * block02 = NULL; //2nd row of blocks
SDL_Texture * block03 = NULL; //3rd row of blocks
SDL_Texture * blockNeprobojni = NULL; //impenetrable block

SDL_Rect rectPozadina; //background rect
SDL_Rect rectSplav; //paddle rect
SDL_Rect rectLoptica; //ball rect
SDL_Rect rectBlock01; //block01 rect
SDL_Rect rectBlock02; //block02 rect
SDL_Rect rectBlock03; //block03 rect
SDL_Rect rectBlockNeprobojni; //impenetrable rect

SDL_Event problem;


const int sirinaEkrana = 1280, visinaEkrana = 720;
//sirinaEkrana= screenWidth, visinaEkrana=screenHeight
int brojZivota = 3; //number of lives
int brojBlokova = 36; //total amount of blocks on screen
vector< pair<pair<int, int>, int > > koordinateBlokovaVektor; //array for storing coordinates and impact count on every block
bool igra = true; //bool value for while loop in int main()
int gornjiOdstoj = 20; //space between top wall and 1st row of blocks
int razmakRedova = 5; //space between blocks in a row
int razmakStupaca = 5; //space between blocks in column
int sirinaBloka = 102; //width of the block
int visinaBloka = 20; //height of the block


//sirinaSplavi = paddleWidth, visinaSplavi=paddleHeight
const int sirinaSplavi = 200, visinaSplavi = 10;
//splavPocetniX=starting point X of paddle, splavPocetniY=starting point Y of paddle
const int splavPocetniX = sirinaEkrana / 2 - 100;
const int splavPocetniY = visinaEkrana - visinaSplavi;

//sirinaLoptice= ballWidth, visinaLoptice=ballHeight
const int sirinaLoptice = 20, visinaLoptice = 20;
//lopticaPocetniX = starting point X of the ball, lopticaPocetniY = starting point Y of the ball,
const int lopticaPocetniX = sirinaEkrana / 2;
const int lopticaPocetniY = visinaEkrana / 2;
//lopticaTrenutniX =current X point of the ball, lopticaTrenutniY =current Y point of the ball
int lopticaTrenutniX = 0, lopticaTrenutniY = 0;

//level
int level = 1;
int brojRedovaBlokova = 3; //number of block rows
int brojBlokovaRed = 12; //number of blocks in a row


Main function:



int main(int argc, char*args) {

loadGame();

while (igra)
{
SDL_PollEvent(&problem);

if (problem.type == SDL_QUIT)
igra = false;

Logika();
Crtaj();

}

Quit();

return 0;
}


Quit function:



void Quit() {

SDL_Quit();
}


Loading a game:



void loadGame() {

SDL_Init(SDL_INIT_EVERYTHING);
ekran = SDL_CreateWindow("Breakout", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, sirinaEkrana, visinaEkrana, SDL_WINDOW_SHOWN);
renderer = SDL_CreateRenderer(ekran, -1, 0);

pozadina = IMG_LoadTexture(renderer, "Slike/pozadina1.png");
loptica = IMG_LoadTexture(renderer,"loptica.bmp");
splav = IMG_LoadTexture(renderer, "splav.bmp");
block01 = IMG_LoadTexture(renderer, "block01.bmp");
block02 = IMG_LoadTexture(renderer, "block02.bmp");
block03 = IMG_LoadTexture(renderer, "block03.bmp");
blockNeprobojni = IMG_LoadTexture(renderer, "blockNeprobojni.bmp");

rectLoptica.x = lopticaPocetniX; rectLoptica.y =lopticaPocetniY; rectLoptica.w = sirinaLoptice; rectLoptica.h = visinaLoptice;
rectSplav.x = splavPocetniX; rectSplav.y = splavPocetniY; rectSplav.w = sirinaSplavi; rectSplav.h = visinaSplavi;
rectPozadina.x = 0; rectPozadina.y = 0; rectPozadina.w = sirinaEkrana; rectPozadina.h = visinaEkrana;

Crtaj();

srand(time(NULL));

randomPocetniSmjer();
}


Game logic:



void Logika() {

#pragma region Paddle movement
const Uint8 *tipka = SDL_GetKeyboardState(NULL);

if (tipka[SDL_SCANCODE_A] && rectSplav.x > 0)
rectSplav.x--;

if (tipka[SDL_SCANCODE_D] && rectSplav.x < 1080) //1280-200(paddle width)
rectSplav.x++;
#pragma endregion

#pragma region Ball movement

rectLoptica.x += lopticaTrenutniX;
rectLoptica.y += lopticaTrenutniY;
#pragma endregion

//UPPER WALL
if (rectLoptica.y < visinaLoptice) {

lopticaTrenutniY = -lopticaTrenutniY;
}

//DOWN WALL, RESET
if (rectLoptica.y > visinaEkrana) {
Sleep(2000);
randomPocetniSmjer();

brojZivota--;
if (brojZivota == 0) {
igra = false;

}

}

//LEFT WALL
if (rectLoptica.x < sirinaLoptice) {

lopticaTrenutniX = -lopticaTrenutniX;
}

//RIGHT WALL
if (rectLoptica.x > sirinaEkrana - sirinaLoptice) {

lopticaTrenutniX = -lopticaTrenutniX;
}

//checking collision of paddle and ball
if (provjeraKolizijeSplavi(rectSplav, rectLoptica) == true) {

lopticaTrenutniY = -lopticaTrenutniY;
}


//checking collision of ball and block
int velicinaPolja = koordinateBlokovaVektor.size();

for(int i=0;i<velicinaPolja;i++) {

if (provjeraKolizijeBloka(koordinateBlokovaVektor[i].first.first, koordinateBlokovaVektor[i].first.second,koordinateBlokovaVektor[i].second, rectLoptica) == true) {
lopticaTrenutniY = -lopticaTrenutniY;
koordinateBlokovaVektor[i].first.first = -1;
koordinateBlokovaVektor[i].first.second = -1;
koordinateBlokovaVektor[i].second--;
break;
}
}

Sleep(2);
}


Drawing function (doesnt work as it should with deleting blocks):



void Crtaj() {

SDL_RenderClear(renderer);

SDL_RenderCopy(renderer, pozadina, NULL, &rectPozadina);
SDL_RenderCopy(renderer, splav, NULL, &rectSplav);
SDL_RenderCopy(renderer, loptica, NULL, &rectLoptica);

SDL_SetRenderTarget(renderer, pozadina);
SDL_SetRenderTarget(renderer, loptica);
SDL_SetRenderTarget(renderer, splav);

int prviRedBrojac = 0, drugiRedBrojac = 11, treciRedBrojac = 23;
#pragma region LVL 1
for (int j = 0; j < brojBlokovaRed; j++) {

int block1X = j*sirinaBloka + j*razmakRedova, block1Y = gornjiOdstoj;
int block2X = j*sirinaBloka + j*razmakRedova, block2Y = gornjiOdstoj + visinaBloka + razmakStupaca;
int block3X = j*sirinaBloka + j*razmakRedova, block3Y = gornjiOdstoj + 2 * visinaBloka + 2 * razmakStupaca;

spremiKoordinate(block1X, block1Y,1);

if (koordinateBlokovaVektor[j].first.first != -1 && koordinateBlokovaVektor[j].first.second != -1 && koordinateBlokovaVektor[j].second != 0) {
rectBlock01 = initRectBlock(block1X, block1Y, sirinaBloka, visinaBloka);
SDL_RenderCopy(renderer, block01, NULL, &rectBlock01);
SDL_SetRenderTarget(renderer, block01);
prviRedBrojac++;
}
else {
SDL_SetRenderTarget(renderer, NULL);
}

if ((j + 1) % 3 == 0) { //if its a impenetrable block

spremiKoordinate(block2X, block2Y,-1); //store -1 if its imprenetrable

if (koordinateBlokovaVektor[j+1].first.first != -1 && koordinateBlokovaVektor[j+1].first.second != -1 && koordinateBlokovaVektor[j+1].second != 0) {
rectBlock02 = initRectBlock(block2X, block2Y, sirinaBloka, visinaBloka);
SDL_RenderCopy(renderer, blockNeprobojni, NULL, &rectBlock02);
SDL_SetRenderTarget(renderer, blockNeprobojni);
drugiRedBrojac++;
}
else {
SDL_SetRenderTarget(renderer, NULL);
}

}
else {

spremiKoordinate(block2X, block2Y,2);

if (koordinateBlokovaVektor[j+1].first.first != -1 && koordinateBlokovaVektor[j+1].first.second != -1 && koordinateBlokovaVektor[j+1].second != 0) {
rectBlock02 = initRectBlock(block2X, block2Y, sirinaBloka, visinaBloka);
SDL_RenderCopy(renderer, block02, NULL, &rectBlock02);
SDL_SetRenderTarget(renderer, block02);
drugiRedBrojac++;
}
else {
SDL_SetRenderTarget(renderer, NULL);
}
}

spremiKoordinate(block3X, block3Y, 1);
if (koordinateBlokovaVektor[j+2].first.first != -1 && koordinateBlokovaVektor[j+2].first.second != -1 && koordinateBlokovaVektor[j+2].second != 0) {
rectBlock03 = initRectBlock(block3X, block3Y, sirinaBloka, visinaBloka);
SDL_RenderCopy(renderer, block01, NULL, &rectBlock03);
SDL_SetRenderTarget(renderer, block01);
}
else {
SDL_SetRenderTarget(renderer, NULL);
}


}

#pragma endregion

SDL_SetRenderTarget(renderer, NULL);
SDL_RenderPresent(renderer);

}


Storing coordinates in array:



void spremiKoordinate(int x, int y,int brojUdaraca) { 

if (koordinateBlokovaVektor.size() < 36 ) {
koordinateBlokovaVektor.push_back(make_pair(make_pair(x,y), brojUdaraca));
sort(koordinateBlokovaVektor.begin(), koordinateBlokovaVektor.end());
}
}


Initialize SDL_Rect:



SDL_Rect initRectBlock(int x, int y, int sirina, int visina) { 

SDL_Rect blok;
blok.x = x;
blok.y = y;
blok.w = sirina;
blok.h = visina;

return blok;
}


Define starting direction of the ball:



void randomPocetniSmjer() { 

//reset ball
rectLoptica.x = lopticaPocetniX;
rectLoptica.y = lopticaPocetniY;

//reset paddle
rectSplav.x = splavPocetniX;
rectSplav.y = splavPocetniY;


int smjerKretanja = (rand() % 2 + 1);
int kutGibanjaX1 = -1;
int kutGibanjaY1 = 1;

switch (smjerKretanja)
{
case 1:
lopticaTrenutniX = -kutGibanjaX1;
lopticaTrenutniY = -kutGibanjaY1;
break;

case 2:
lopticaTrenutniX = kutGibanjaX1;
lopticaTrenutniY = -kutGibanjaY1;
break;

default:
break;
}

}


Next in code is collision:



bool tocnaUnutarSplavi(int objektX, int objektY, SDL_Rect loptica) {

if ((objektX + sirinaSplavi >= loptica.x && objektY >= loptica.y) && (objektX <= loptica.x + visinaLoptice && objektY <= loptica.y + visinaLoptice)) {

return true;
}

else
return false;

}
bool tocnaUnutarBloka(int objektX, int objektY, SDL_Rect loptica) {

if ((objektX + sirinaBloka >= loptica.x && objektY >= loptica.y) && (objektX <= loptica.x + sirinaLoptice && objektY <= loptica.y + visinaLoptice)) {
return true;
}
else
return false;

}


bool provjeraKolizijeSplavi(SDL_Rect splav, SDL_Rect r2) {

//when ball hits paddle for direction DOWNLEFT
if (tocnaUnutarSplavi(splav.x, splav.y, r2) == true) {
cout << "KOLIZIJA: Splav[" << rectSplav.x << "," << rectSplav.y << "]" << endl;
return true;
}

//when ball hits paddle for direction DOWNRIGHT
else if (tocnaUnutarSplavi(splav.x, splav.y + splav.h, r2) == true) {
return true;
}

else
return false;
}

bool provjeraKolizijeBloka(int x, int y, int brojUdaraca, SDL_Rect r2) {

//when ball hits block from direction UPLEFT
if (tocnaUnutarBloka(x, y, r2) == true) {
return true;
}

//when ball hits block from direction UPRIGHT
else if (tocnaUnutarBloka(x, y + visinaBloka, r2) == true) {
return true;
}

else
return false;
}


If someone could give me some direction to start with because im just confused how to even convert it into OOP .










share|improve this question














bumped to the homepage by Community 11 mins ago


This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.















  • I don't know if it suits your needs but I made this breakout clone using SDL in the past It's from my noob days into programming, so it's mostly shitty, so take it as it is. Maybe it will guide you in the direction you seek.
    – RandomOne
    Oct 10 at 19:39















up vote
1
down vote

favorite












I did a big mistake to create procedural C++ breakout game on start and now im having trouble converting it into OOP.



As far as I can see I need classes: Loptica (eng. Ball), Splav (eng. Paddle), Blok (eng. Block), Logika (eng. Logic), Kolizija (eng, Collision), Level (eng. Level)



Definition:



#include "SDL.h"
#include "SDL_image.h"
#include <ctime>
#include <stdlib.h>
#include <iostream>
#include <Windows.h>
#include <utility>
#include <string>
#include <vector>
#include <algorithm>

#undef main
using namespace std;

SDL_Window *ekran;
SDL_Renderer * renderer = NULL;

SDL_Texture * pozadina = NULL; //background
SDL_Texture * splav = NULL; //paddle
SDL_Texture * loptica = NULL; //ball
SDL_Texture * block01 = NULL; //1st row of blocks
SDL_Texture * block02 = NULL; //2nd row of blocks
SDL_Texture * block03 = NULL; //3rd row of blocks
SDL_Texture * blockNeprobojni = NULL; //impenetrable block

SDL_Rect rectPozadina; //background rect
SDL_Rect rectSplav; //paddle rect
SDL_Rect rectLoptica; //ball rect
SDL_Rect rectBlock01; //block01 rect
SDL_Rect rectBlock02; //block02 rect
SDL_Rect rectBlock03; //block03 rect
SDL_Rect rectBlockNeprobojni; //impenetrable rect

SDL_Event problem;


const int sirinaEkrana = 1280, visinaEkrana = 720;
//sirinaEkrana= screenWidth, visinaEkrana=screenHeight
int brojZivota = 3; //number of lives
int brojBlokova = 36; //total amount of blocks on screen
vector< pair<pair<int, int>, int > > koordinateBlokovaVektor; //array for storing coordinates and impact count on every block
bool igra = true; //bool value for while loop in int main()
int gornjiOdstoj = 20; //space between top wall and 1st row of blocks
int razmakRedova = 5; //space between blocks in a row
int razmakStupaca = 5; //space between blocks in column
int sirinaBloka = 102; //width of the block
int visinaBloka = 20; //height of the block


//sirinaSplavi = paddleWidth, visinaSplavi=paddleHeight
const int sirinaSplavi = 200, visinaSplavi = 10;
//splavPocetniX=starting point X of paddle, splavPocetniY=starting point Y of paddle
const int splavPocetniX = sirinaEkrana / 2 - 100;
const int splavPocetniY = visinaEkrana - visinaSplavi;

//sirinaLoptice= ballWidth, visinaLoptice=ballHeight
const int sirinaLoptice = 20, visinaLoptice = 20;
//lopticaPocetniX = starting point X of the ball, lopticaPocetniY = starting point Y of the ball,
const int lopticaPocetniX = sirinaEkrana / 2;
const int lopticaPocetniY = visinaEkrana / 2;
//lopticaTrenutniX =current X point of the ball, lopticaTrenutniY =current Y point of the ball
int lopticaTrenutniX = 0, lopticaTrenutniY = 0;

//level
int level = 1;
int brojRedovaBlokova = 3; //number of block rows
int brojBlokovaRed = 12; //number of blocks in a row


Main function:



int main(int argc, char*args) {

loadGame();

while (igra)
{
SDL_PollEvent(&problem);

if (problem.type == SDL_QUIT)
igra = false;

Logika();
Crtaj();

}

Quit();

return 0;
}


Quit function:



void Quit() {

SDL_Quit();
}


Loading a game:



void loadGame() {

SDL_Init(SDL_INIT_EVERYTHING);
ekran = SDL_CreateWindow("Breakout", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, sirinaEkrana, visinaEkrana, SDL_WINDOW_SHOWN);
renderer = SDL_CreateRenderer(ekran, -1, 0);

pozadina = IMG_LoadTexture(renderer, "Slike/pozadina1.png");
loptica = IMG_LoadTexture(renderer,"loptica.bmp");
splav = IMG_LoadTexture(renderer, "splav.bmp");
block01 = IMG_LoadTexture(renderer, "block01.bmp");
block02 = IMG_LoadTexture(renderer, "block02.bmp");
block03 = IMG_LoadTexture(renderer, "block03.bmp");
blockNeprobojni = IMG_LoadTexture(renderer, "blockNeprobojni.bmp");

rectLoptica.x = lopticaPocetniX; rectLoptica.y =lopticaPocetniY; rectLoptica.w = sirinaLoptice; rectLoptica.h = visinaLoptice;
rectSplav.x = splavPocetniX; rectSplav.y = splavPocetniY; rectSplav.w = sirinaSplavi; rectSplav.h = visinaSplavi;
rectPozadina.x = 0; rectPozadina.y = 0; rectPozadina.w = sirinaEkrana; rectPozadina.h = visinaEkrana;

Crtaj();

srand(time(NULL));

randomPocetniSmjer();
}


Game logic:



void Logika() {

#pragma region Paddle movement
const Uint8 *tipka = SDL_GetKeyboardState(NULL);

if (tipka[SDL_SCANCODE_A] && rectSplav.x > 0)
rectSplav.x--;

if (tipka[SDL_SCANCODE_D] && rectSplav.x < 1080) //1280-200(paddle width)
rectSplav.x++;
#pragma endregion

#pragma region Ball movement

rectLoptica.x += lopticaTrenutniX;
rectLoptica.y += lopticaTrenutniY;
#pragma endregion

//UPPER WALL
if (rectLoptica.y < visinaLoptice) {

lopticaTrenutniY = -lopticaTrenutniY;
}

//DOWN WALL, RESET
if (rectLoptica.y > visinaEkrana) {
Sleep(2000);
randomPocetniSmjer();

brojZivota--;
if (brojZivota == 0) {
igra = false;

}

}

//LEFT WALL
if (rectLoptica.x < sirinaLoptice) {

lopticaTrenutniX = -lopticaTrenutniX;
}

//RIGHT WALL
if (rectLoptica.x > sirinaEkrana - sirinaLoptice) {

lopticaTrenutniX = -lopticaTrenutniX;
}

//checking collision of paddle and ball
if (provjeraKolizijeSplavi(rectSplav, rectLoptica) == true) {

lopticaTrenutniY = -lopticaTrenutniY;
}


//checking collision of ball and block
int velicinaPolja = koordinateBlokovaVektor.size();

for(int i=0;i<velicinaPolja;i++) {

if (provjeraKolizijeBloka(koordinateBlokovaVektor[i].first.first, koordinateBlokovaVektor[i].first.second,koordinateBlokovaVektor[i].second, rectLoptica) == true) {
lopticaTrenutniY = -lopticaTrenutniY;
koordinateBlokovaVektor[i].first.first = -1;
koordinateBlokovaVektor[i].first.second = -1;
koordinateBlokovaVektor[i].second--;
break;
}
}

Sleep(2);
}


Drawing function (doesnt work as it should with deleting blocks):



void Crtaj() {

SDL_RenderClear(renderer);

SDL_RenderCopy(renderer, pozadina, NULL, &rectPozadina);
SDL_RenderCopy(renderer, splav, NULL, &rectSplav);
SDL_RenderCopy(renderer, loptica, NULL, &rectLoptica);

SDL_SetRenderTarget(renderer, pozadina);
SDL_SetRenderTarget(renderer, loptica);
SDL_SetRenderTarget(renderer, splav);

int prviRedBrojac = 0, drugiRedBrojac = 11, treciRedBrojac = 23;
#pragma region LVL 1
for (int j = 0; j < brojBlokovaRed; j++) {

int block1X = j*sirinaBloka + j*razmakRedova, block1Y = gornjiOdstoj;
int block2X = j*sirinaBloka + j*razmakRedova, block2Y = gornjiOdstoj + visinaBloka + razmakStupaca;
int block3X = j*sirinaBloka + j*razmakRedova, block3Y = gornjiOdstoj + 2 * visinaBloka + 2 * razmakStupaca;

spremiKoordinate(block1X, block1Y,1);

if (koordinateBlokovaVektor[j].first.first != -1 && koordinateBlokovaVektor[j].first.second != -1 && koordinateBlokovaVektor[j].second != 0) {
rectBlock01 = initRectBlock(block1X, block1Y, sirinaBloka, visinaBloka);
SDL_RenderCopy(renderer, block01, NULL, &rectBlock01);
SDL_SetRenderTarget(renderer, block01);
prviRedBrojac++;
}
else {
SDL_SetRenderTarget(renderer, NULL);
}

if ((j + 1) % 3 == 0) { //if its a impenetrable block

spremiKoordinate(block2X, block2Y,-1); //store -1 if its imprenetrable

if (koordinateBlokovaVektor[j+1].first.first != -1 && koordinateBlokovaVektor[j+1].first.second != -1 && koordinateBlokovaVektor[j+1].second != 0) {
rectBlock02 = initRectBlock(block2X, block2Y, sirinaBloka, visinaBloka);
SDL_RenderCopy(renderer, blockNeprobojni, NULL, &rectBlock02);
SDL_SetRenderTarget(renderer, blockNeprobojni);
drugiRedBrojac++;
}
else {
SDL_SetRenderTarget(renderer, NULL);
}

}
else {

spremiKoordinate(block2X, block2Y,2);

if (koordinateBlokovaVektor[j+1].first.first != -1 && koordinateBlokovaVektor[j+1].first.second != -1 && koordinateBlokovaVektor[j+1].second != 0) {
rectBlock02 = initRectBlock(block2X, block2Y, sirinaBloka, visinaBloka);
SDL_RenderCopy(renderer, block02, NULL, &rectBlock02);
SDL_SetRenderTarget(renderer, block02);
drugiRedBrojac++;
}
else {
SDL_SetRenderTarget(renderer, NULL);
}
}

spremiKoordinate(block3X, block3Y, 1);
if (koordinateBlokovaVektor[j+2].first.first != -1 && koordinateBlokovaVektor[j+2].first.second != -1 && koordinateBlokovaVektor[j+2].second != 0) {
rectBlock03 = initRectBlock(block3X, block3Y, sirinaBloka, visinaBloka);
SDL_RenderCopy(renderer, block01, NULL, &rectBlock03);
SDL_SetRenderTarget(renderer, block01);
}
else {
SDL_SetRenderTarget(renderer, NULL);
}


}

#pragma endregion

SDL_SetRenderTarget(renderer, NULL);
SDL_RenderPresent(renderer);

}


Storing coordinates in array:



void spremiKoordinate(int x, int y,int brojUdaraca) { 

if (koordinateBlokovaVektor.size() < 36 ) {
koordinateBlokovaVektor.push_back(make_pair(make_pair(x,y), brojUdaraca));
sort(koordinateBlokovaVektor.begin(), koordinateBlokovaVektor.end());
}
}


Initialize SDL_Rect:



SDL_Rect initRectBlock(int x, int y, int sirina, int visina) { 

SDL_Rect blok;
blok.x = x;
blok.y = y;
blok.w = sirina;
blok.h = visina;

return blok;
}


Define starting direction of the ball:



void randomPocetniSmjer() { 

//reset ball
rectLoptica.x = lopticaPocetniX;
rectLoptica.y = lopticaPocetniY;

//reset paddle
rectSplav.x = splavPocetniX;
rectSplav.y = splavPocetniY;


int smjerKretanja = (rand() % 2 + 1);
int kutGibanjaX1 = -1;
int kutGibanjaY1 = 1;

switch (smjerKretanja)
{
case 1:
lopticaTrenutniX = -kutGibanjaX1;
lopticaTrenutniY = -kutGibanjaY1;
break;

case 2:
lopticaTrenutniX = kutGibanjaX1;
lopticaTrenutniY = -kutGibanjaY1;
break;

default:
break;
}

}


Next in code is collision:



bool tocnaUnutarSplavi(int objektX, int objektY, SDL_Rect loptica) {

if ((objektX + sirinaSplavi >= loptica.x && objektY >= loptica.y) && (objektX <= loptica.x + visinaLoptice && objektY <= loptica.y + visinaLoptice)) {

return true;
}

else
return false;

}
bool tocnaUnutarBloka(int objektX, int objektY, SDL_Rect loptica) {

if ((objektX + sirinaBloka >= loptica.x && objektY >= loptica.y) && (objektX <= loptica.x + sirinaLoptice && objektY <= loptica.y + visinaLoptice)) {
return true;
}
else
return false;

}


bool provjeraKolizijeSplavi(SDL_Rect splav, SDL_Rect r2) {

//when ball hits paddle for direction DOWNLEFT
if (tocnaUnutarSplavi(splav.x, splav.y, r2) == true) {
cout << "KOLIZIJA: Splav[" << rectSplav.x << "," << rectSplav.y << "]" << endl;
return true;
}

//when ball hits paddle for direction DOWNRIGHT
else if (tocnaUnutarSplavi(splav.x, splav.y + splav.h, r2) == true) {
return true;
}

else
return false;
}

bool provjeraKolizijeBloka(int x, int y, int brojUdaraca, SDL_Rect r2) {

//when ball hits block from direction UPLEFT
if (tocnaUnutarBloka(x, y, r2) == true) {
return true;
}

//when ball hits block from direction UPRIGHT
else if (tocnaUnutarBloka(x, y + visinaBloka, r2) == true) {
return true;
}

else
return false;
}


If someone could give me some direction to start with because im just confused how to even convert it into OOP .










share|improve this question














bumped to the homepage by Community 11 mins ago


This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.















  • I don't know if it suits your needs but I made this breakout clone using SDL in the past It's from my noob days into programming, so it's mostly shitty, so take it as it is. Maybe it will guide you in the direction you seek.
    – RandomOne
    Oct 10 at 19:39













up vote
1
down vote

favorite









up vote
1
down vote

favorite











I did a big mistake to create procedural C++ breakout game on start and now im having trouble converting it into OOP.



As far as I can see I need classes: Loptica (eng. Ball), Splav (eng. Paddle), Blok (eng. Block), Logika (eng. Logic), Kolizija (eng, Collision), Level (eng. Level)



Definition:



#include "SDL.h"
#include "SDL_image.h"
#include <ctime>
#include <stdlib.h>
#include <iostream>
#include <Windows.h>
#include <utility>
#include <string>
#include <vector>
#include <algorithm>

#undef main
using namespace std;

SDL_Window *ekran;
SDL_Renderer * renderer = NULL;

SDL_Texture * pozadina = NULL; //background
SDL_Texture * splav = NULL; //paddle
SDL_Texture * loptica = NULL; //ball
SDL_Texture * block01 = NULL; //1st row of blocks
SDL_Texture * block02 = NULL; //2nd row of blocks
SDL_Texture * block03 = NULL; //3rd row of blocks
SDL_Texture * blockNeprobojni = NULL; //impenetrable block

SDL_Rect rectPozadina; //background rect
SDL_Rect rectSplav; //paddle rect
SDL_Rect rectLoptica; //ball rect
SDL_Rect rectBlock01; //block01 rect
SDL_Rect rectBlock02; //block02 rect
SDL_Rect rectBlock03; //block03 rect
SDL_Rect rectBlockNeprobojni; //impenetrable rect

SDL_Event problem;


const int sirinaEkrana = 1280, visinaEkrana = 720;
//sirinaEkrana= screenWidth, visinaEkrana=screenHeight
int brojZivota = 3; //number of lives
int brojBlokova = 36; //total amount of blocks on screen
vector< pair<pair<int, int>, int > > koordinateBlokovaVektor; //array for storing coordinates and impact count on every block
bool igra = true; //bool value for while loop in int main()
int gornjiOdstoj = 20; //space between top wall and 1st row of blocks
int razmakRedova = 5; //space between blocks in a row
int razmakStupaca = 5; //space between blocks in column
int sirinaBloka = 102; //width of the block
int visinaBloka = 20; //height of the block


//sirinaSplavi = paddleWidth, visinaSplavi=paddleHeight
const int sirinaSplavi = 200, visinaSplavi = 10;
//splavPocetniX=starting point X of paddle, splavPocetniY=starting point Y of paddle
const int splavPocetniX = sirinaEkrana / 2 - 100;
const int splavPocetniY = visinaEkrana - visinaSplavi;

//sirinaLoptice= ballWidth, visinaLoptice=ballHeight
const int sirinaLoptice = 20, visinaLoptice = 20;
//lopticaPocetniX = starting point X of the ball, lopticaPocetniY = starting point Y of the ball,
const int lopticaPocetniX = sirinaEkrana / 2;
const int lopticaPocetniY = visinaEkrana / 2;
//lopticaTrenutniX =current X point of the ball, lopticaTrenutniY =current Y point of the ball
int lopticaTrenutniX = 0, lopticaTrenutniY = 0;

//level
int level = 1;
int brojRedovaBlokova = 3; //number of block rows
int brojBlokovaRed = 12; //number of blocks in a row


Main function:



int main(int argc, char*args) {

loadGame();

while (igra)
{
SDL_PollEvent(&problem);

if (problem.type == SDL_QUIT)
igra = false;

Logika();
Crtaj();

}

Quit();

return 0;
}


Quit function:



void Quit() {

SDL_Quit();
}


Loading a game:



void loadGame() {

SDL_Init(SDL_INIT_EVERYTHING);
ekran = SDL_CreateWindow("Breakout", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, sirinaEkrana, visinaEkrana, SDL_WINDOW_SHOWN);
renderer = SDL_CreateRenderer(ekran, -1, 0);

pozadina = IMG_LoadTexture(renderer, "Slike/pozadina1.png");
loptica = IMG_LoadTexture(renderer,"loptica.bmp");
splav = IMG_LoadTexture(renderer, "splav.bmp");
block01 = IMG_LoadTexture(renderer, "block01.bmp");
block02 = IMG_LoadTexture(renderer, "block02.bmp");
block03 = IMG_LoadTexture(renderer, "block03.bmp");
blockNeprobojni = IMG_LoadTexture(renderer, "blockNeprobojni.bmp");

rectLoptica.x = lopticaPocetniX; rectLoptica.y =lopticaPocetniY; rectLoptica.w = sirinaLoptice; rectLoptica.h = visinaLoptice;
rectSplav.x = splavPocetniX; rectSplav.y = splavPocetniY; rectSplav.w = sirinaSplavi; rectSplav.h = visinaSplavi;
rectPozadina.x = 0; rectPozadina.y = 0; rectPozadina.w = sirinaEkrana; rectPozadina.h = visinaEkrana;

Crtaj();

srand(time(NULL));

randomPocetniSmjer();
}


Game logic:



void Logika() {

#pragma region Paddle movement
const Uint8 *tipka = SDL_GetKeyboardState(NULL);

if (tipka[SDL_SCANCODE_A] && rectSplav.x > 0)
rectSplav.x--;

if (tipka[SDL_SCANCODE_D] && rectSplav.x < 1080) //1280-200(paddle width)
rectSplav.x++;
#pragma endregion

#pragma region Ball movement

rectLoptica.x += lopticaTrenutniX;
rectLoptica.y += lopticaTrenutniY;
#pragma endregion

//UPPER WALL
if (rectLoptica.y < visinaLoptice) {

lopticaTrenutniY = -lopticaTrenutniY;
}

//DOWN WALL, RESET
if (rectLoptica.y > visinaEkrana) {
Sleep(2000);
randomPocetniSmjer();

brojZivota--;
if (brojZivota == 0) {
igra = false;

}

}

//LEFT WALL
if (rectLoptica.x < sirinaLoptice) {

lopticaTrenutniX = -lopticaTrenutniX;
}

//RIGHT WALL
if (rectLoptica.x > sirinaEkrana - sirinaLoptice) {

lopticaTrenutniX = -lopticaTrenutniX;
}

//checking collision of paddle and ball
if (provjeraKolizijeSplavi(rectSplav, rectLoptica) == true) {

lopticaTrenutniY = -lopticaTrenutniY;
}


//checking collision of ball and block
int velicinaPolja = koordinateBlokovaVektor.size();

for(int i=0;i<velicinaPolja;i++) {

if (provjeraKolizijeBloka(koordinateBlokovaVektor[i].first.first, koordinateBlokovaVektor[i].first.second,koordinateBlokovaVektor[i].second, rectLoptica) == true) {
lopticaTrenutniY = -lopticaTrenutniY;
koordinateBlokovaVektor[i].first.first = -1;
koordinateBlokovaVektor[i].first.second = -1;
koordinateBlokovaVektor[i].second--;
break;
}
}

Sleep(2);
}


Drawing function (doesnt work as it should with deleting blocks):



void Crtaj() {

SDL_RenderClear(renderer);

SDL_RenderCopy(renderer, pozadina, NULL, &rectPozadina);
SDL_RenderCopy(renderer, splav, NULL, &rectSplav);
SDL_RenderCopy(renderer, loptica, NULL, &rectLoptica);

SDL_SetRenderTarget(renderer, pozadina);
SDL_SetRenderTarget(renderer, loptica);
SDL_SetRenderTarget(renderer, splav);

int prviRedBrojac = 0, drugiRedBrojac = 11, treciRedBrojac = 23;
#pragma region LVL 1
for (int j = 0; j < brojBlokovaRed; j++) {

int block1X = j*sirinaBloka + j*razmakRedova, block1Y = gornjiOdstoj;
int block2X = j*sirinaBloka + j*razmakRedova, block2Y = gornjiOdstoj + visinaBloka + razmakStupaca;
int block3X = j*sirinaBloka + j*razmakRedova, block3Y = gornjiOdstoj + 2 * visinaBloka + 2 * razmakStupaca;

spremiKoordinate(block1X, block1Y,1);

if (koordinateBlokovaVektor[j].first.first != -1 && koordinateBlokovaVektor[j].first.second != -1 && koordinateBlokovaVektor[j].second != 0) {
rectBlock01 = initRectBlock(block1X, block1Y, sirinaBloka, visinaBloka);
SDL_RenderCopy(renderer, block01, NULL, &rectBlock01);
SDL_SetRenderTarget(renderer, block01);
prviRedBrojac++;
}
else {
SDL_SetRenderTarget(renderer, NULL);
}

if ((j + 1) % 3 == 0) { //if its a impenetrable block

spremiKoordinate(block2X, block2Y,-1); //store -1 if its imprenetrable

if (koordinateBlokovaVektor[j+1].first.first != -1 && koordinateBlokovaVektor[j+1].first.second != -1 && koordinateBlokovaVektor[j+1].second != 0) {
rectBlock02 = initRectBlock(block2X, block2Y, sirinaBloka, visinaBloka);
SDL_RenderCopy(renderer, blockNeprobojni, NULL, &rectBlock02);
SDL_SetRenderTarget(renderer, blockNeprobojni);
drugiRedBrojac++;
}
else {
SDL_SetRenderTarget(renderer, NULL);
}

}
else {

spremiKoordinate(block2X, block2Y,2);

if (koordinateBlokovaVektor[j+1].first.first != -1 && koordinateBlokovaVektor[j+1].first.second != -1 && koordinateBlokovaVektor[j+1].second != 0) {
rectBlock02 = initRectBlock(block2X, block2Y, sirinaBloka, visinaBloka);
SDL_RenderCopy(renderer, block02, NULL, &rectBlock02);
SDL_SetRenderTarget(renderer, block02);
drugiRedBrojac++;
}
else {
SDL_SetRenderTarget(renderer, NULL);
}
}

spremiKoordinate(block3X, block3Y, 1);
if (koordinateBlokovaVektor[j+2].first.first != -1 && koordinateBlokovaVektor[j+2].first.second != -1 && koordinateBlokovaVektor[j+2].second != 0) {
rectBlock03 = initRectBlock(block3X, block3Y, sirinaBloka, visinaBloka);
SDL_RenderCopy(renderer, block01, NULL, &rectBlock03);
SDL_SetRenderTarget(renderer, block01);
}
else {
SDL_SetRenderTarget(renderer, NULL);
}


}

#pragma endregion

SDL_SetRenderTarget(renderer, NULL);
SDL_RenderPresent(renderer);

}


Storing coordinates in array:



void spremiKoordinate(int x, int y,int brojUdaraca) { 

if (koordinateBlokovaVektor.size() < 36 ) {
koordinateBlokovaVektor.push_back(make_pair(make_pair(x,y), brojUdaraca));
sort(koordinateBlokovaVektor.begin(), koordinateBlokovaVektor.end());
}
}


Initialize SDL_Rect:



SDL_Rect initRectBlock(int x, int y, int sirina, int visina) { 

SDL_Rect blok;
blok.x = x;
blok.y = y;
blok.w = sirina;
blok.h = visina;

return blok;
}


Define starting direction of the ball:



void randomPocetniSmjer() { 

//reset ball
rectLoptica.x = lopticaPocetniX;
rectLoptica.y = lopticaPocetniY;

//reset paddle
rectSplav.x = splavPocetniX;
rectSplav.y = splavPocetniY;


int smjerKretanja = (rand() % 2 + 1);
int kutGibanjaX1 = -1;
int kutGibanjaY1 = 1;

switch (smjerKretanja)
{
case 1:
lopticaTrenutniX = -kutGibanjaX1;
lopticaTrenutniY = -kutGibanjaY1;
break;

case 2:
lopticaTrenutniX = kutGibanjaX1;
lopticaTrenutniY = -kutGibanjaY1;
break;

default:
break;
}

}


Next in code is collision:



bool tocnaUnutarSplavi(int objektX, int objektY, SDL_Rect loptica) {

if ((objektX + sirinaSplavi >= loptica.x && objektY >= loptica.y) && (objektX <= loptica.x + visinaLoptice && objektY <= loptica.y + visinaLoptice)) {

return true;
}

else
return false;

}
bool tocnaUnutarBloka(int objektX, int objektY, SDL_Rect loptica) {

if ((objektX + sirinaBloka >= loptica.x && objektY >= loptica.y) && (objektX <= loptica.x + sirinaLoptice && objektY <= loptica.y + visinaLoptice)) {
return true;
}
else
return false;

}


bool provjeraKolizijeSplavi(SDL_Rect splav, SDL_Rect r2) {

//when ball hits paddle for direction DOWNLEFT
if (tocnaUnutarSplavi(splav.x, splav.y, r2) == true) {
cout << "KOLIZIJA: Splav[" << rectSplav.x << "," << rectSplav.y << "]" << endl;
return true;
}

//when ball hits paddle for direction DOWNRIGHT
else if (tocnaUnutarSplavi(splav.x, splav.y + splav.h, r2) == true) {
return true;
}

else
return false;
}

bool provjeraKolizijeBloka(int x, int y, int brojUdaraca, SDL_Rect r2) {

//when ball hits block from direction UPLEFT
if (tocnaUnutarBloka(x, y, r2) == true) {
return true;
}

//when ball hits block from direction UPRIGHT
else if (tocnaUnutarBloka(x, y + visinaBloka, r2) == true) {
return true;
}

else
return false;
}


If someone could give me some direction to start with because im just confused how to even convert it into OOP .










share|improve this question













I did a big mistake to create procedural C++ breakout game on start and now im having trouble converting it into OOP.



As far as I can see I need classes: Loptica (eng. Ball), Splav (eng. Paddle), Blok (eng. Block), Logika (eng. Logic), Kolizija (eng, Collision), Level (eng. Level)



Definition:



#include "SDL.h"
#include "SDL_image.h"
#include <ctime>
#include <stdlib.h>
#include <iostream>
#include <Windows.h>
#include <utility>
#include <string>
#include <vector>
#include <algorithm>

#undef main
using namespace std;

SDL_Window *ekran;
SDL_Renderer * renderer = NULL;

SDL_Texture * pozadina = NULL; //background
SDL_Texture * splav = NULL; //paddle
SDL_Texture * loptica = NULL; //ball
SDL_Texture * block01 = NULL; //1st row of blocks
SDL_Texture * block02 = NULL; //2nd row of blocks
SDL_Texture * block03 = NULL; //3rd row of blocks
SDL_Texture * blockNeprobojni = NULL; //impenetrable block

SDL_Rect rectPozadina; //background rect
SDL_Rect rectSplav; //paddle rect
SDL_Rect rectLoptica; //ball rect
SDL_Rect rectBlock01; //block01 rect
SDL_Rect rectBlock02; //block02 rect
SDL_Rect rectBlock03; //block03 rect
SDL_Rect rectBlockNeprobojni; //impenetrable rect

SDL_Event problem;


const int sirinaEkrana = 1280, visinaEkrana = 720;
//sirinaEkrana= screenWidth, visinaEkrana=screenHeight
int brojZivota = 3; //number of lives
int brojBlokova = 36; //total amount of blocks on screen
vector< pair<pair<int, int>, int > > koordinateBlokovaVektor; //array for storing coordinates and impact count on every block
bool igra = true; //bool value for while loop in int main()
int gornjiOdstoj = 20; //space between top wall and 1st row of blocks
int razmakRedova = 5; //space between blocks in a row
int razmakStupaca = 5; //space between blocks in column
int sirinaBloka = 102; //width of the block
int visinaBloka = 20; //height of the block


//sirinaSplavi = paddleWidth, visinaSplavi=paddleHeight
const int sirinaSplavi = 200, visinaSplavi = 10;
//splavPocetniX=starting point X of paddle, splavPocetniY=starting point Y of paddle
const int splavPocetniX = sirinaEkrana / 2 - 100;
const int splavPocetniY = visinaEkrana - visinaSplavi;

//sirinaLoptice= ballWidth, visinaLoptice=ballHeight
const int sirinaLoptice = 20, visinaLoptice = 20;
//lopticaPocetniX = starting point X of the ball, lopticaPocetniY = starting point Y of the ball,
const int lopticaPocetniX = sirinaEkrana / 2;
const int lopticaPocetniY = visinaEkrana / 2;
//lopticaTrenutniX =current X point of the ball, lopticaTrenutniY =current Y point of the ball
int lopticaTrenutniX = 0, lopticaTrenutniY = 0;

//level
int level = 1;
int brojRedovaBlokova = 3; //number of block rows
int brojBlokovaRed = 12; //number of blocks in a row


Main function:



int main(int argc, char*args) {

loadGame();

while (igra)
{
SDL_PollEvent(&problem);

if (problem.type == SDL_QUIT)
igra = false;

Logika();
Crtaj();

}

Quit();

return 0;
}


Quit function:



void Quit() {

SDL_Quit();
}


Loading a game:



void loadGame() {

SDL_Init(SDL_INIT_EVERYTHING);
ekran = SDL_CreateWindow("Breakout", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, sirinaEkrana, visinaEkrana, SDL_WINDOW_SHOWN);
renderer = SDL_CreateRenderer(ekran, -1, 0);

pozadina = IMG_LoadTexture(renderer, "Slike/pozadina1.png");
loptica = IMG_LoadTexture(renderer,"loptica.bmp");
splav = IMG_LoadTexture(renderer, "splav.bmp");
block01 = IMG_LoadTexture(renderer, "block01.bmp");
block02 = IMG_LoadTexture(renderer, "block02.bmp");
block03 = IMG_LoadTexture(renderer, "block03.bmp");
blockNeprobojni = IMG_LoadTexture(renderer, "blockNeprobojni.bmp");

rectLoptica.x = lopticaPocetniX; rectLoptica.y =lopticaPocetniY; rectLoptica.w = sirinaLoptice; rectLoptica.h = visinaLoptice;
rectSplav.x = splavPocetniX; rectSplav.y = splavPocetniY; rectSplav.w = sirinaSplavi; rectSplav.h = visinaSplavi;
rectPozadina.x = 0; rectPozadina.y = 0; rectPozadina.w = sirinaEkrana; rectPozadina.h = visinaEkrana;

Crtaj();

srand(time(NULL));

randomPocetniSmjer();
}


Game logic:



void Logika() {

#pragma region Paddle movement
const Uint8 *tipka = SDL_GetKeyboardState(NULL);

if (tipka[SDL_SCANCODE_A] && rectSplav.x > 0)
rectSplav.x--;

if (tipka[SDL_SCANCODE_D] && rectSplav.x < 1080) //1280-200(paddle width)
rectSplav.x++;
#pragma endregion

#pragma region Ball movement

rectLoptica.x += lopticaTrenutniX;
rectLoptica.y += lopticaTrenutniY;
#pragma endregion

//UPPER WALL
if (rectLoptica.y < visinaLoptice) {

lopticaTrenutniY = -lopticaTrenutniY;
}

//DOWN WALL, RESET
if (rectLoptica.y > visinaEkrana) {
Sleep(2000);
randomPocetniSmjer();

brojZivota--;
if (brojZivota == 0) {
igra = false;

}

}

//LEFT WALL
if (rectLoptica.x < sirinaLoptice) {

lopticaTrenutniX = -lopticaTrenutniX;
}

//RIGHT WALL
if (rectLoptica.x > sirinaEkrana - sirinaLoptice) {

lopticaTrenutniX = -lopticaTrenutniX;
}

//checking collision of paddle and ball
if (provjeraKolizijeSplavi(rectSplav, rectLoptica) == true) {

lopticaTrenutniY = -lopticaTrenutniY;
}


//checking collision of ball and block
int velicinaPolja = koordinateBlokovaVektor.size();

for(int i=0;i<velicinaPolja;i++) {

if (provjeraKolizijeBloka(koordinateBlokovaVektor[i].first.first, koordinateBlokovaVektor[i].first.second,koordinateBlokovaVektor[i].second, rectLoptica) == true) {
lopticaTrenutniY = -lopticaTrenutniY;
koordinateBlokovaVektor[i].first.first = -1;
koordinateBlokovaVektor[i].first.second = -1;
koordinateBlokovaVektor[i].second--;
break;
}
}

Sleep(2);
}


Drawing function (doesnt work as it should with deleting blocks):



void Crtaj() {

SDL_RenderClear(renderer);

SDL_RenderCopy(renderer, pozadina, NULL, &rectPozadina);
SDL_RenderCopy(renderer, splav, NULL, &rectSplav);
SDL_RenderCopy(renderer, loptica, NULL, &rectLoptica);

SDL_SetRenderTarget(renderer, pozadina);
SDL_SetRenderTarget(renderer, loptica);
SDL_SetRenderTarget(renderer, splav);

int prviRedBrojac = 0, drugiRedBrojac = 11, treciRedBrojac = 23;
#pragma region LVL 1
for (int j = 0; j < brojBlokovaRed; j++) {

int block1X = j*sirinaBloka + j*razmakRedova, block1Y = gornjiOdstoj;
int block2X = j*sirinaBloka + j*razmakRedova, block2Y = gornjiOdstoj + visinaBloka + razmakStupaca;
int block3X = j*sirinaBloka + j*razmakRedova, block3Y = gornjiOdstoj + 2 * visinaBloka + 2 * razmakStupaca;

spremiKoordinate(block1X, block1Y,1);

if (koordinateBlokovaVektor[j].first.first != -1 && koordinateBlokovaVektor[j].first.second != -1 && koordinateBlokovaVektor[j].second != 0) {
rectBlock01 = initRectBlock(block1X, block1Y, sirinaBloka, visinaBloka);
SDL_RenderCopy(renderer, block01, NULL, &rectBlock01);
SDL_SetRenderTarget(renderer, block01);
prviRedBrojac++;
}
else {
SDL_SetRenderTarget(renderer, NULL);
}

if ((j + 1) % 3 == 0) { //if its a impenetrable block

spremiKoordinate(block2X, block2Y,-1); //store -1 if its imprenetrable

if (koordinateBlokovaVektor[j+1].first.first != -1 && koordinateBlokovaVektor[j+1].first.second != -1 && koordinateBlokovaVektor[j+1].second != 0) {
rectBlock02 = initRectBlock(block2X, block2Y, sirinaBloka, visinaBloka);
SDL_RenderCopy(renderer, blockNeprobojni, NULL, &rectBlock02);
SDL_SetRenderTarget(renderer, blockNeprobojni);
drugiRedBrojac++;
}
else {
SDL_SetRenderTarget(renderer, NULL);
}

}
else {

spremiKoordinate(block2X, block2Y,2);

if (koordinateBlokovaVektor[j+1].first.first != -1 && koordinateBlokovaVektor[j+1].first.second != -1 && koordinateBlokovaVektor[j+1].second != 0) {
rectBlock02 = initRectBlock(block2X, block2Y, sirinaBloka, visinaBloka);
SDL_RenderCopy(renderer, block02, NULL, &rectBlock02);
SDL_SetRenderTarget(renderer, block02);
drugiRedBrojac++;
}
else {
SDL_SetRenderTarget(renderer, NULL);
}
}

spremiKoordinate(block3X, block3Y, 1);
if (koordinateBlokovaVektor[j+2].first.first != -1 && koordinateBlokovaVektor[j+2].first.second != -1 && koordinateBlokovaVektor[j+2].second != 0) {
rectBlock03 = initRectBlock(block3X, block3Y, sirinaBloka, visinaBloka);
SDL_RenderCopy(renderer, block01, NULL, &rectBlock03);
SDL_SetRenderTarget(renderer, block01);
}
else {
SDL_SetRenderTarget(renderer, NULL);
}


}

#pragma endregion

SDL_SetRenderTarget(renderer, NULL);
SDL_RenderPresent(renderer);

}


Storing coordinates in array:



void spremiKoordinate(int x, int y,int brojUdaraca) { 

if (koordinateBlokovaVektor.size() < 36 ) {
koordinateBlokovaVektor.push_back(make_pair(make_pair(x,y), brojUdaraca));
sort(koordinateBlokovaVektor.begin(), koordinateBlokovaVektor.end());
}
}


Initialize SDL_Rect:



SDL_Rect initRectBlock(int x, int y, int sirina, int visina) { 

SDL_Rect blok;
blok.x = x;
blok.y = y;
blok.w = sirina;
blok.h = visina;

return blok;
}


Define starting direction of the ball:



void randomPocetniSmjer() { 

//reset ball
rectLoptica.x = lopticaPocetniX;
rectLoptica.y = lopticaPocetniY;

//reset paddle
rectSplav.x = splavPocetniX;
rectSplav.y = splavPocetniY;


int smjerKretanja = (rand() % 2 + 1);
int kutGibanjaX1 = -1;
int kutGibanjaY1 = 1;

switch (smjerKretanja)
{
case 1:
lopticaTrenutniX = -kutGibanjaX1;
lopticaTrenutniY = -kutGibanjaY1;
break;

case 2:
lopticaTrenutniX = kutGibanjaX1;
lopticaTrenutniY = -kutGibanjaY1;
break;

default:
break;
}

}


Next in code is collision:



bool tocnaUnutarSplavi(int objektX, int objektY, SDL_Rect loptica) {

if ((objektX + sirinaSplavi >= loptica.x && objektY >= loptica.y) && (objektX <= loptica.x + visinaLoptice && objektY <= loptica.y + visinaLoptice)) {

return true;
}

else
return false;

}
bool tocnaUnutarBloka(int objektX, int objektY, SDL_Rect loptica) {

if ((objektX + sirinaBloka >= loptica.x && objektY >= loptica.y) && (objektX <= loptica.x + sirinaLoptice && objektY <= loptica.y + visinaLoptice)) {
return true;
}
else
return false;

}


bool provjeraKolizijeSplavi(SDL_Rect splav, SDL_Rect r2) {

//when ball hits paddle for direction DOWNLEFT
if (tocnaUnutarSplavi(splav.x, splav.y, r2) == true) {
cout << "KOLIZIJA: Splav[" << rectSplav.x << "," << rectSplav.y << "]" << endl;
return true;
}

//when ball hits paddle for direction DOWNRIGHT
else if (tocnaUnutarSplavi(splav.x, splav.y + splav.h, r2) == true) {
return true;
}

else
return false;
}

bool provjeraKolizijeBloka(int x, int y, int brojUdaraca, SDL_Rect r2) {

//when ball hits block from direction UPLEFT
if (tocnaUnutarBloka(x, y, r2) == true) {
return true;
}

//when ball hits block from direction UPRIGHT
else if (tocnaUnutarBloka(x, y + visinaBloka, r2) == true) {
return true;
}

else
return false;
}


If someone could give me some direction to start with because im just confused how to even convert it into OOP .







c++ object-oriented game collision sdl






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Oct 10 at 19:20









Marko Petričević

165




165





bumped to the homepage by Community 11 mins ago


This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.







bumped to the homepage by Community 11 mins ago


This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.














  • I don't know if it suits your needs but I made this breakout clone using SDL in the past It's from my noob days into programming, so it's mostly shitty, so take it as it is. Maybe it will guide you in the direction you seek.
    – RandomOne
    Oct 10 at 19:39


















  • I don't know if it suits your needs but I made this breakout clone using SDL in the past It's from my noob days into programming, so it's mostly shitty, so take it as it is. Maybe it will guide you in the direction you seek.
    – RandomOne
    Oct 10 at 19:39
















I don't know if it suits your needs but I made this breakout clone using SDL in the past It's from my noob days into programming, so it's mostly shitty, so take it as it is. Maybe it will guide you in the direction you seek.
– RandomOne
Oct 10 at 19:39




I don't know if it suits your needs but I made this breakout clone using SDL in the past It's from my noob days into programming, so it's mostly shitty, so take it as it is. Maybe it will guide you in the direction you seek.
– RandomOne
Oct 10 at 19:39










1 Answer
1






active

oldest

votes

















up vote
0
down vote













This is really not that bad. Despite the variable names not being in English, I'm able to get the gist of it. Here are some useful things that I think would improve the situation.



Avoid Globals



Your first header is mainly a list of global variables. Globals are difficult to work with because they can be changed by any code anywhere in your app. So when a problem occurs with a global, good luck tracking down where it occurs since it could be anywhere. If you put your global data into classes, you'll have minimized the number of places where it could be going wrong.



Let's start with the textures you use. Textures make up a large part of most video games. It would probably make sense to have an object which handles textures. It could load them from disk, give them to code to use, cache recently used textures, etc. I would probably make either a TextureFactory class, or a TextureCache class to handle these sorts of tasks. It might not be necessary here since you only have about 5-10 textures, but any more than that and you'll probably want something to organize them.



Use struct or class to Combine Data



Notice how after the texture declarations, you have corresponding declarations of rectangles. This is a clue that you should be creating either a struct or class that holds both the texture and its rectangle.



Next you declare a bunch of variables for things like the number of lives, current level, the number of blocks on screen, spacing of various elements. These fall into 2 broad categories - game state, and rendering constants. I would make 2 classes for these: GameState which holds things like the number of lives left and the current level, and GameRenderer which holds data related to rendering. I notice there's an SDL_Renderer, so you should probably also put that into your GameRenderer class.



You make a lot of use of std::pair for storing coordinates and impact counts. std::pair is a difficult class to deal with because it's so non-specific. Its data members, first and second are meaningless. You should make a Point or Vector class to hold coordinates. You should then make a Block struct or class to hold a Point or Vector and an impact count. Then your koordinateBlockovaVektor vector would be declared as just:



std::vector<Block> koordinateBlokovaVektor;


Naming



I don't speak your language, but I assume Logika is Logic and Crtaj is Draw? If so, I would recommend using more descriptive names, like UpdateGameState() and RenderGame() (or whatever that would be in your native tongue).



I would also avoid putting the type name into the variable's name. So a std::vector doesn't need to have Vektor in it's name. If you had a class or struct for your textures, you could simply call the rectangle the bounds or frame or something along those lines. Something like this:



struct GameTexture {
SDL_Texture* image;
SDL_Rect bounds;
};


Then to access one, you could do:



GameTexture pozadina;
// ... fill it out ...
SDL_RenderCopy(renderer, pozadina.image, NULL, &pozadina.bounds);





share|improve this answer





















  • Thanks for all good tips you gave me, my question is: when we talk about global variables, in this case I want to define some const int's like ball width,height, number of blocks per lvl etc. Where do I store them in this case?RenderGame() or at definition of Block?
    – Marko Petričević
    Oct 11 at 6:20










  • It depends on how you use them. If a Block draws itself, then I'd put it in Block, but if a Renderer draws a Block, I'd put it into Renderer.
    – user1118321
    Oct 11 at 16:12











Your Answer





StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");

StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f205324%2fc-breakout-game-using-sdl%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
0
down vote













This is really not that bad. Despite the variable names not being in English, I'm able to get the gist of it. Here are some useful things that I think would improve the situation.



Avoid Globals



Your first header is mainly a list of global variables. Globals are difficult to work with because they can be changed by any code anywhere in your app. So when a problem occurs with a global, good luck tracking down where it occurs since it could be anywhere. If you put your global data into classes, you'll have minimized the number of places where it could be going wrong.



Let's start with the textures you use. Textures make up a large part of most video games. It would probably make sense to have an object which handles textures. It could load them from disk, give them to code to use, cache recently used textures, etc. I would probably make either a TextureFactory class, or a TextureCache class to handle these sorts of tasks. It might not be necessary here since you only have about 5-10 textures, but any more than that and you'll probably want something to organize them.



Use struct or class to Combine Data



Notice how after the texture declarations, you have corresponding declarations of rectangles. This is a clue that you should be creating either a struct or class that holds both the texture and its rectangle.



Next you declare a bunch of variables for things like the number of lives, current level, the number of blocks on screen, spacing of various elements. These fall into 2 broad categories - game state, and rendering constants. I would make 2 classes for these: GameState which holds things like the number of lives left and the current level, and GameRenderer which holds data related to rendering. I notice there's an SDL_Renderer, so you should probably also put that into your GameRenderer class.



You make a lot of use of std::pair for storing coordinates and impact counts. std::pair is a difficult class to deal with because it's so non-specific. Its data members, first and second are meaningless. You should make a Point or Vector class to hold coordinates. You should then make a Block struct or class to hold a Point or Vector and an impact count. Then your koordinateBlockovaVektor vector would be declared as just:



std::vector<Block> koordinateBlokovaVektor;


Naming



I don't speak your language, but I assume Logika is Logic and Crtaj is Draw? If so, I would recommend using more descriptive names, like UpdateGameState() and RenderGame() (or whatever that would be in your native tongue).



I would also avoid putting the type name into the variable's name. So a std::vector doesn't need to have Vektor in it's name. If you had a class or struct for your textures, you could simply call the rectangle the bounds or frame or something along those lines. Something like this:



struct GameTexture {
SDL_Texture* image;
SDL_Rect bounds;
};


Then to access one, you could do:



GameTexture pozadina;
// ... fill it out ...
SDL_RenderCopy(renderer, pozadina.image, NULL, &pozadina.bounds);





share|improve this answer





















  • Thanks for all good tips you gave me, my question is: when we talk about global variables, in this case I want to define some const int's like ball width,height, number of blocks per lvl etc. Where do I store them in this case?RenderGame() or at definition of Block?
    – Marko Petričević
    Oct 11 at 6:20










  • It depends on how you use them. If a Block draws itself, then I'd put it in Block, but if a Renderer draws a Block, I'd put it into Renderer.
    – user1118321
    Oct 11 at 16:12















up vote
0
down vote













This is really not that bad. Despite the variable names not being in English, I'm able to get the gist of it. Here are some useful things that I think would improve the situation.



Avoid Globals



Your first header is mainly a list of global variables. Globals are difficult to work with because they can be changed by any code anywhere in your app. So when a problem occurs with a global, good luck tracking down where it occurs since it could be anywhere. If you put your global data into classes, you'll have minimized the number of places where it could be going wrong.



Let's start with the textures you use. Textures make up a large part of most video games. It would probably make sense to have an object which handles textures. It could load them from disk, give them to code to use, cache recently used textures, etc. I would probably make either a TextureFactory class, or a TextureCache class to handle these sorts of tasks. It might not be necessary here since you only have about 5-10 textures, but any more than that and you'll probably want something to organize them.



Use struct or class to Combine Data



Notice how after the texture declarations, you have corresponding declarations of rectangles. This is a clue that you should be creating either a struct or class that holds both the texture and its rectangle.



Next you declare a bunch of variables for things like the number of lives, current level, the number of blocks on screen, spacing of various elements. These fall into 2 broad categories - game state, and rendering constants. I would make 2 classes for these: GameState which holds things like the number of lives left and the current level, and GameRenderer which holds data related to rendering. I notice there's an SDL_Renderer, so you should probably also put that into your GameRenderer class.



You make a lot of use of std::pair for storing coordinates and impact counts. std::pair is a difficult class to deal with because it's so non-specific. Its data members, first and second are meaningless. You should make a Point or Vector class to hold coordinates. You should then make a Block struct or class to hold a Point or Vector and an impact count. Then your koordinateBlockovaVektor vector would be declared as just:



std::vector<Block> koordinateBlokovaVektor;


Naming



I don't speak your language, but I assume Logika is Logic and Crtaj is Draw? If so, I would recommend using more descriptive names, like UpdateGameState() and RenderGame() (or whatever that would be in your native tongue).



I would also avoid putting the type name into the variable's name. So a std::vector doesn't need to have Vektor in it's name. If you had a class or struct for your textures, you could simply call the rectangle the bounds or frame or something along those lines. Something like this:



struct GameTexture {
SDL_Texture* image;
SDL_Rect bounds;
};


Then to access one, you could do:



GameTexture pozadina;
// ... fill it out ...
SDL_RenderCopy(renderer, pozadina.image, NULL, &pozadina.bounds);





share|improve this answer





















  • Thanks for all good tips you gave me, my question is: when we talk about global variables, in this case I want to define some const int's like ball width,height, number of blocks per lvl etc. Where do I store them in this case?RenderGame() or at definition of Block?
    – Marko Petričević
    Oct 11 at 6:20










  • It depends on how you use them. If a Block draws itself, then I'd put it in Block, but if a Renderer draws a Block, I'd put it into Renderer.
    – user1118321
    Oct 11 at 16:12













up vote
0
down vote










up vote
0
down vote









This is really not that bad. Despite the variable names not being in English, I'm able to get the gist of it. Here are some useful things that I think would improve the situation.



Avoid Globals



Your first header is mainly a list of global variables. Globals are difficult to work with because they can be changed by any code anywhere in your app. So when a problem occurs with a global, good luck tracking down where it occurs since it could be anywhere. If you put your global data into classes, you'll have minimized the number of places where it could be going wrong.



Let's start with the textures you use. Textures make up a large part of most video games. It would probably make sense to have an object which handles textures. It could load them from disk, give them to code to use, cache recently used textures, etc. I would probably make either a TextureFactory class, or a TextureCache class to handle these sorts of tasks. It might not be necessary here since you only have about 5-10 textures, but any more than that and you'll probably want something to organize them.



Use struct or class to Combine Data



Notice how after the texture declarations, you have corresponding declarations of rectangles. This is a clue that you should be creating either a struct or class that holds both the texture and its rectangle.



Next you declare a bunch of variables for things like the number of lives, current level, the number of blocks on screen, spacing of various elements. These fall into 2 broad categories - game state, and rendering constants. I would make 2 classes for these: GameState which holds things like the number of lives left and the current level, and GameRenderer which holds data related to rendering. I notice there's an SDL_Renderer, so you should probably also put that into your GameRenderer class.



You make a lot of use of std::pair for storing coordinates and impact counts. std::pair is a difficult class to deal with because it's so non-specific. Its data members, first and second are meaningless. You should make a Point or Vector class to hold coordinates. You should then make a Block struct or class to hold a Point or Vector and an impact count. Then your koordinateBlockovaVektor vector would be declared as just:



std::vector<Block> koordinateBlokovaVektor;


Naming



I don't speak your language, but I assume Logika is Logic and Crtaj is Draw? If so, I would recommend using more descriptive names, like UpdateGameState() and RenderGame() (or whatever that would be in your native tongue).



I would also avoid putting the type name into the variable's name. So a std::vector doesn't need to have Vektor in it's name. If you had a class or struct for your textures, you could simply call the rectangle the bounds or frame or something along those lines. Something like this:



struct GameTexture {
SDL_Texture* image;
SDL_Rect bounds;
};


Then to access one, you could do:



GameTexture pozadina;
// ... fill it out ...
SDL_RenderCopy(renderer, pozadina.image, NULL, &pozadina.bounds);





share|improve this answer












This is really not that bad. Despite the variable names not being in English, I'm able to get the gist of it. Here are some useful things that I think would improve the situation.



Avoid Globals



Your first header is mainly a list of global variables. Globals are difficult to work with because they can be changed by any code anywhere in your app. So when a problem occurs with a global, good luck tracking down where it occurs since it could be anywhere. If you put your global data into classes, you'll have minimized the number of places where it could be going wrong.



Let's start with the textures you use. Textures make up a large part of most video games. It would probably make sense to have an object which handles textures. It could load them from disk, give them to code to use, cache recently used textures, etc. I would probably make either a TextureFactory class, or a TextureCache class to handle these sorts of tasks. It might not be necessary here since you only have about 5-10 textures, but any more than that and you'll probably want something to organize them.



Use struct or class to Combine Data



Notice how after the texture declarations, you have corresponding declarations of rectangles. This is a clue that you should be creating either a struct or class that holds both the texture and its rectangle.



Next you declare a bunch of variables for things like the number of lives, current level, the number of blocks on screen, spacing of various elements. These fall into 2 broad categories - game state, and rendering constants. I would make 2 classes for these: GameState which holds things like the number of lives left and the current level, and GameRenderer which holds data related to rendering. I notice there's an SDL_Renderer, so you should probably also put that into your GameRenderer class.



You make a lot of use of std::pair for storing coordinates and impact counts. std::pair is a difficult class to deal with because it's so non-specific. Its data members, first and second are meaningless. You should make a Point or Vector class to hold coordinates. You should then make a Block struct or class to hold a Point or Vector and an impact count. Then your koordinateBlockovaVektor vector would be declared as just:



std::vector<Block> koordinateBlokovaVektor;


Naming



I don't speak your language, but I assume Logika is Logic and Crtaj is Draw? If so, I would recommend using more descriptive names, like UpdateGameState() and RenderGame() (or whatever that would be in your native tongue).



I would also avoid putting the type name into the variable's name. So a std::vector doesn't need to have Vektor in it's name. If you had a class or struct for your textures, you could simply call the rectangle the bounds or frame or something along those lines. Something like this:



struct GameTexture {
SDL_Texture* image;
SDL_Rect bounds;
};


Then to access one, you could do:



GameTexture pozadina;
// ... fill it out ...
SDL_RenderCopy(renderer, pozadina.image, NULL, &pozadina.bounds);






share|improve this answer












share|improve this answer



share|improve this answer










answered Oct 11 at 4:40









user1118321

10.7k11145




10.7k11145












  • Thanks for all good tips you gave me, my question is: when we talk about global variables, in this case I want to define some const int's like ball width,height, number of blocks per lvl etc. Where do I store them in this case?RenderGame() or at definition of Block?
    – Marko Petričević
    Oct 11 at 6:20










  • It depends on how you use them. If a Block draws itself, then I'd put it in Block, but if a Renderer draws a Block, I'd put it into Renderer.
    – user1118321
    Oct 11 at 16:12


















  • Thanks for all good tips you gave me, my question is: when we talk about global variables, in this case I want to define some const int's like ball width,height, number of blocks per lvl etc. Where do I store them in this case?RenderGame() or at definition of Block?
    – Marko Petričević
    Oct 11 at 6:20










  • It depends on how you use them. If a Block draws itself, then I'd put it in Block, but if a Renderer draws a Block, I'd put it into Renderer.
    – user1118321
    Oct 11 at 16:12
















Thanks for all good tips you gave me, my question is: when we talk about global variables, in this case I want to define some const int's like ball width,height, number of blocks per lvl etc. Where do I store them in this case?RenderGame() or at definition of Block?
– Marko Petričević
Oct 11 at 6:20




Thanks for all good tips you gave me, my question is: when we talk about global variables, in this case I want to define some const int's like ball width,height, number of blocks per lvl etc. Where do I store them in this case?RenderGame() or at definition of Block?
– Marko Petričević
Oct 11 at 6:20












It depends on how you use them. If a Block draws itself, then I'd put it in Block, but if a Renderer draws a Block, I'd put it into Renderer.
– user1118321
Oct 11 at 16:12




It depends on how you use them. If a Block draws itself, then I'd put it in Block, but if a Renderer draws a Block, I'd put it into Renderer.
– user1118321
Oct 11 at 16:12


















draft saved

draft discarded




















































Thanks for contributing an answer to Code Review Stack Exchange!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


Use MathJax to format equations. MathJax reference.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f205324%2fc-breakout-game-using-sdl%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Costa Masnaga

Fotorealismo

Sidney Franklin