diff --git a/.gitignore b/.gitignore index 05c7d92..35f0e66 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,11 @@ # git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. -# For a project mostly in C, the following would be a good set of -# exclude patterns (uncomment them if you want to use them): *.depend *.cbp *.layout sdl2-config *.exclude *.o -highscoretest.c *.psd *.exe !bhi.exe diff --git a/Dokumentation.pdf b/Dokumentation.pdf index bb4e4c9..32f72c0 100644 Binary files a/Dokumentation.pdf and b/Dokumentation.pdf differ diff --git a/Makefile b/Makefile index 64bd708..10e8671 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,15 @@ libs = -lmingw32 -lSDL2main -lSDL2 -lopengl32 -lSDL2_image -lSDL2_ttf includes = -I".\include" compiler = gcc -warningLevel = -Wall +warningLevel = -Wall -Wno-unused-variable -Wno-unused-but-set-variable sources = *.c linker = -L".\lib" dir = bin -target = Breakout.exe +target = Breakout args = -o all: $(compiler) $(warningLevel) $(includes) $(sources) $(linker) $(libs) $(args) $(dir)\$(target) + +run: cd $(dir) && $(target) diff --git a/bin/assets/fonts/ae-bi.ttf b/bin/assets/fonts/ae-bi.ttf new file mode 100644 index 0000000..017f3f6 Binary files /dev/null and b/bin/assets/fonts/ae-bi.ttf differ diff --git a/bin/assets/fonts/ka1.ttf b/bin/assets/fonts/ka1.ttf new file mode 100644 index 0000000..d1df852 Binary files /dev/null and b/bin/assets/fonts/ka1.ttf differ diff --git a/bin/assets/fonts/minecraft.ttf b/bin/assets/fonts/minecraft.ttf new file mode 100644 index 0000000..85c1472 Binary files /dev/null and b/bin/assets/fonts/minecraft.ttf differ diff --git a/bin/assets/fonts/monofur.ttf b/bin/assets/fonts/monofur.ttf new file mode 100644 index 0000000..9aebf80 Binary files /dev/null and b/bin/assets/fonts/monofur.ttf differ diff --git a/bin/assets/images/Texts.png b/bin/assets/images/Texts.png new file mode 100644 index 0000000..3aecc26 Binary files /dev/null and b/bin/assets/images/Texts.png differ diff --git a/bin/assets/images/ball.png b/bin/assets/images/ball.png index 0b62c40..bcd3581 100644 Binary files a/bin/assets/images/ball.png and b/bin/assets/images/ball.png differ diff --git a/bin/assets/images/blocks_debug.png b/bin/assets/images/blocks_debug.png new file mode 100644 index 0000000..27f3506 Binary files /dev/null and b/bin/assets/images/blocks_debug.png differ diff --git a/bin/assets/images/breaking_button.png b/bin/assets/images/breaking_button.png new file mode 100644 index 0000000..dea6037 Binary files /dev/null and b/bin/assets/images/breaking_button.png differ diff --git a/bin/assets/images/highscores_button.png b/bin/assets/images/highscores_button.png new file mode 100644 index 0000000..56e9ca8 Binary files /dev/null and b/bin/assets/images/highscores_button.png differ diff --git a/bin/assets/images/level_button.png b/bin/assets/images/level_button.png new file mode 100644 index 0000000..8fc77c8 Binary files /dev/null and b/bin/assets/images/level_button.png differ diff --git a/bin/assets/images/paddle.png b/bin/assets/images/paddle.png index 4d54f4b..23792c6 100644 Binary files a/bin/assets/images/paddle.png and b/bin/assets/images/paddle.png differ diff --git a/bin/assets/images/play_button.png b/bin/assets/images/play_button.png new file mode 100644 index 0000000..9bf30b9 Binary files /dev/null and b/bin/assets/images/play_button.png differ diff --git a/bin/assets/images/quit_button.png b/bin/assets/images/quit_button.png new file mode 100644 index 0000000..fa55b91 Binary files /dev/null and b/bin/assets/images/quit_button.png differ diff --git a/bin/assets/images/settings_button.png b/bin/assets/images/settings_button.png new file mode 100644 index 0000000..cff8906 Binary files /dev/null and b/bin/assets/images/settings_button.png differ diff --git a/bin/assets/images/settings_title.png b/bin/assets/images/settings_title.png new file mode 100644 index 0000000..3a274d2 Binary files /dev/null and b/bin/assets/images/settings_title.png differ diff --git a/bin/assets/images/skins_button.png b/bin/assets/images/skins_button.png new file mode 100644 index 0000000..02cb30f Binary files /dev/null and b/bin/assets/images/skins_button.png differ diff --git a/bin/assets/images/spritesheet.png b/bin/assets/images/spritesheet.png new file mode 100644 index 0000000..2c0ebff Binary files /dev/null and b/bin/assets/images/spritesheet.png differ diff --git a/bin/bhi.exe b/bin/bhi.exe index 0008cb1..b49a627 100644 Binary files a/bin/bhi.exe and b/bin/bhi.exe differ diff --git a/breakout.c b/breakout.c index 19bdec2..bb43112 100644 --- a/breakout.c +++ b/breakout.c @@ -10,23 +10,27 @@ #include "breakout.h" #include "vector.h" +#define BALL_TexturePath "assets/images/ball.png" +#define PADDLE_TexturePath "assets/images/paddle.png" +#define BLOCK_TexturePath "assets/images/spritesheet.png" + #ifndef __nullptr__ #define Nullptr(type) (type *)0 #endif // __nullptr__ +int BLOCK_TextureCount = 24; int BREAKOUT_BoxWidth, BREAKOUT_BoxHeight; SDL_Texture * BALL_Texture; -SDL_Rect * BALL_SourceRects; -Ball ball; -Paddle paddle; SDL_Texture * PADDLE_Texture; +SDL_Texture * BLOCK_Texture; +SDL_Rect * BALL_SourceRects; SDL_Rect * PADDLE_SourceRects; +SDL_Rect * BLOCK_SourceRects; Uint8 * PADDLE_MoveLeftKeys, * PADDLE_MoveRightKeys; -double BALL_Speed = 15.0f; -int PADDLE_Speed = 10; bool BREAKOUT_IsInit = false; bool BALL_IsInit = false; bool PADDLE_IsInit = false; +bool BLOCK_IsInit = false; void BREAKOUT_INITIALIZE(SDL_Renderer * renderer, int width, int height){ if (!BREAKOUT_IsInit) { @@ -36,46 +40,90 @@ void BREAKOUT_INITIALIZE(SDL_Renderer * renderer, int width, int height){ BREAKOUT_BoxHeight = height; BALL_Initialize(renderer); PADDLE_Initialize(renderer); + BLOCK_Initialize(renderer); printf("Game initialized!\n"); BREAKOUT_IsInit = true; } else printf("Game is already initialized!\n"); -} +} /* BREAKOUT_INITIALIZE */ +Scenery BREAKOUT_CreateDefault(){ + Scenery scenery; + + scenery.BlockCount = 60; + scenery.ball = BALL_CreateDefault(); + scenery.paddle = PADDLE_CreateDefault(); + scenery.blocks = malloc(scenery.BlockCount * sizeof(Block)); + int index; + for (int y = 0; y < 6; y++) { + index = 10 * y; + for (int x = 0; x < 10; x++) { + scenery.blocks[x + index] = BLOCK_CreateDefault(); + scenery.blocks[x + index].TargetRect = (SDL_Rect) {.x = ((192 * x) + 4), .y = ((96 * y) + 2), .w = 184, .h = 92 }; + scenery.blocks[x + index].TextureIndex = y + x + 2; + // printf("Block created at index: %d\n", (x + index)); + // printf("Block Target: %d %d %d %d\n", ( scenery.blocks[x + index].TargetRect.x), ( scenery.blocks[x + index].TargetRect.y), ( scenery.blocks[x + index].TargetRect.w), ( scenery.blocks[x + index].TargetRect.h)); + // printf("Block Texture index: %d\n", scenery.blocks[x + index].TextureIndex); + // system("pause"); + } + } + return scenery; +} /* BREAKOUT_CreateDefault */ + +// This Function is obsolete! Do not use it! void BREAKOUT_ChangeSize(int width, int height){ BREAKOUT_BoxWidth = width; BREAKOUT_BoxHeight = height; } -void BREAKOUT_Update(Uint8 * keystate){ - BALL_Update(&ball, &paddle); - PADDLE_Update(&paddle, keystate); +void BREAKOUT_Update(Scenery * scenery, const Uint8 * keystate){ + PADDLE_Update(&(scenery->paddle), keystate); // Update paddle before ball because paddle is not static! + BALL_Update(&(scenery->ball), &(scenery->paddle), (scenery->blocks), (scenery->BlockCount)); + for (int i = 0; i < (scenery->BlockCount); i++) { + BLOCK_Update((scenery->blocks) + i); + } } -void BREAKOUT_Draw(SDL_Renderer * renderer){ - BALL_Draw(renderer, &ball); - PADDLE_Draw(renderer, &paddle); +void BREAKOUT_Draw(Scenery * scenery, SDL_Renderer * renderer){ + for (int i = 0; i < (scenery->BlockCount); i++) { + BLOCK_Draw(renderer, &((scenery->blocks)[i])); + } + BALL_Draw(renderer, &(scenery->ball)); + PADDLE_Draw(renderer, &(scenery->paddle)); } void BREAKOUT_DEINITIALIZE(){ if (BREAKOUT_IsInit) { printf("De-initializing Game...\n"); - SDL_DestroyTexture(BALL_Texture); - SDL_DestroyTexture(PADDLE_Texture); + free(PADDLE_MoveLeftKeys); + free(PADDLE_MoveRightKeys); + free(BALL_SourceRects); + free(PADDLE_SourceRects); + free(BLOCK_SourceRects); + BALL_Deinitialize(); + PADDLE_Deinitialize(); + BLOCK_Deinitialize(); printf("Game de-initialized!\n"); BREAKOUT_IsInit = false; } else printf("Game is already de-initialized!\n"); } +void BREAKOUT_DestroyObject(Scenery * scenery){ + for (size_t i = 0; i < (scenery->BlockCount); i++) { + BLOCK_DestroyObject((scenery->blocks) + i); + } + BALL_DestroyObject(&(scenery->ball)); + PADDLE_DestroyObject(&(scenery->paddle)); + free((scenery->blocks)); +} + void BALL_Initialize(SDL_Renderer * renderer){ if (!BALL_IsInit) { printf("Initializing Ball...\n"); - BALL_Texture = IMG_LoadTexture(renderer, "assets/images/ball.png"); + BALL_Texture = IMG_LoadTexture(renderer, BALL_TexturePath); if (!BALL_Texture) printf("Ball texture failed to load!\n"); BALL_SourceRects = (SDL_Rect *)malloc(1 * sizeof(SDL_Rect)); if (!BALL_SourceRects) printf("FATAL! Memory allocation failed!\n"); BALL_SourceRects[0] = (SDL_Rect) {.x = 0, .y = 0, .w = 512, .h = 512 }; - ball = BALL_CreateDefault(); - paddle = PADDLE_CreateDefault(); printf("Ball initialized!\n"); BALL_IsInit = true; } else printf("Ball is already initialized!\n"); @@ -85,13 +133,14 @@ Ball BALL_CreateDefault(){ double rotation = (double)(rand() % 360); return (Ball) { - .Location = (Vector) {.x = BREAKOUT_BoxWidth / 2, .y = BREAKOUT_BoxHeight / 2 }, - .Momentum = (Vector) {.x = 0.0f, .y = BALL_Speed }, + .Location = (Vector) {.x = BREAKOUT_BoxWidth / 2 + 300, .y = BREAKOUT_BoxHeight / 2 }, + .Momentum = (Vector) {.x = 0.0f, .y = 15.0f }, .TargetRect = (SDL_Rect) {.x = 0, .y = 0, .w = 50, .h = 50 }, .Size = 25.0f, .Rotation = rotation, .RotationValue = 2, - .TextureIndex = 0 + .TextureIndex = 0, + .Speed = 15.0f }; // Objekt für die Eigenschaften des Balls } @@ -101,28 +150,54 @@ void BALL_Draw(SDL_Renderer * renderer, Ball * obj){ } bool BALL_CollideWithRect(Ball * obj, SDL_Rect * rect){ - SDL_Point ballCenter = (SDL_Point) {.x = ((obj->TargetRect).x) + (obj->Size), .y = ((obj->TargetRect).y) + (obj->Size) }; + SDL_Point ballCenter = BALL_GetCenter(obj); - // THIS IS CURRENTLY A RECTANGLE COLLIDE - if (((obj->TargetRect).x) + ((obj->TargetRect).w) < (rect->x)) { - return false; - } - if (((obj->TargetRect).x) > (rect->x) + (rect->w)) { - return false; - } - if (((obj->TargetRect).y) + ((obj->TargetRect).w) < (rect->y)) { - return false; - } - if (((obj->TargetRect).y) > (rect->y) + (rect->h)) { - return false; - } - // Folgender Algorithmus ist gefickt, wenn der Ballmittelpunkt - if ((ballCenter.x) < (rect->x) || (ballCenter.x) > (rect->x) + (rect->w)) { + if (((obj->TargetRect).x) + ((obj->TargetRect).w) < (rect->x)) return false; + if (((obj->TargetRect).x) > (rect->x) + (rect->w)) return false; + if (((obj->TargetRect).y) + ((obj->TargetRect).w) < (rect->y)) return false; + if (((obj->TargetRect).y) > (rect->y) + (rect->h)) return false; + // Already returned with false if square ball hitbox didnt collide with rect + Vector center = (Vector) {.x = ballCenter.x, .y = ballCenter.y }; + Vector corner; +// Folgender Algorithmus ist gefickt, wenn der Ballmittelpunkt im rechteck liegt! +// double perpendicular, oldMomentum, angle; +// oldMomentum = fmod((double)(vectorRotation(obj->Momentum) + 180), 360.0f); + + bool left, right, top, bottom, yMid = false, xMid = false; + left = (ballCenter.x) < (rect->x); + right = (ballCenter.x) > (rect->x) + (rect->w); + top = (ballCenter.y) < (rect->y); + bottom = (ballCenter.y) > (rect->y) + (rect->h); + // if (top) + // corner.y = rect->y; + // else if (bottom) + // corner.y = (rect->y) + (rect->w); + // else + // yMid = true; + // if (left) + // corner.x = rect->x; + // else if (right) + // corner.x = (rect->x) + (rect->w); + // else + // xMid = true; + yMid = !(top || bottom); + xMid = !(left || right); + if (yMid) (obj->Momentum).x = -(obj->Momentum).x; - } - if ((ballCenter.y) < (rect->y) || (ballCenter.y) > (rect->y) + (rect->h)) { + if (xMid) (obj->Momentum).y = -(obj->Momentum).y; - } + // if (yMid && xMid) printf("WARNING: Ball is completely inside block!\n"); + // if (yMid || xMid) { // Ball collides with Edge + // } else { // Ball collides with corner + // /* + // * perpendicular = vectorRotation(vectorSub(center, corner)); + // * angle = fabs(perpendicular - oldMomentum); + // * if (oldMomentum < perpendicular) + // * (obj->Momentum) = getScaledDirectionalUnitVector((oldMomentum + (2 * angle)), (obj->Speed)); + // * else + // * (obj->Momentum) = getScaledDirectionalUnitVector((oldMomentum - (2 * angle)), (obj->Speed)); + // */ + // } return true; } /* BALL_CollideWithRect */ @@ -143,56 +218,83 @@ bool RECT_Collide(SDL_Rect * rect1, SDL_Rect * rect2){ } void BALL_SteerMomentum(Ball * obj, Paddle * paddle){ - int paddleHalfLen = ((paddle->TargetRect).w / 2.0f); + double paddleHalfLen = ((double)((paddle->TargetRect).w) / 2.0f); double offset = (((obj->TargetRect).x) + (obj->Size)) - ((paddle->TargetRect).x + paddleHalfLen); - offset *= 60.0f; - offset /= (double)(paddleHalfLen); - printf("Offset = %.2f\n", offset); - (obj->Momentum) = getScaledDirectionalUnitVector(offset, BALL_Speed); + offset /= paddleHalfLen; + offset *= (paddle->SteeringAngle); + DOUBLE_Constrain(&offset, -(paddle->SteeringAngle), (paddle->SteeringAngle)); + (obj->Momentum) = getDirectionalUnitVector(offset); } -void BALL_Update(Ball * obj, Paddle * paddle){ - Vector oldMomentum = obj->Momentum; +void RECT_SetTargetPos(SDL_Rect * rect, Vector * Location){ + rect->x = (int)round(Location->x); + rect->y = (int)round(Location->y); +} - (obj->Rotation) += (obj->RotationValue); +SDL_Point BALL_GetCenter(Ball * obj){ + return (SDL_Point) {.x = ((obj->TargetRect).x) + (obj->Size), .y = ((obj->TargetRect).y) + (obj->Size) }; +} + +void BALL_Update(Ball * obj, Paddle * paddle, Block * blocks, int BlockCount){ + Vector oldMomentum = obj->Momentum; + Vector oldLocation = obj->Location; + SDL_Point ballCenter = BALL_GetCenter(obj); + + (obj->Rotation) += (obj->RotationValue); // No effect on physics (obj->Location) = vectorAdd((obj->Location), oldMomentum); - if (BALL_CollideWithRect(obj, &(paddle->TargetRect))) { - (obj->Location) = vectorSub((obj->Location), oldMomentum); // Maybe remove this - BALL_SteerMomentum(obj, paddle); - (obj->Location) = vectorAdd((obj->Location), (obj->Momentum)); // Maybe remove this + if (RECT_Collide(&(obj->TargetRect), &(paddle->TargetRect))) { + (obj->Location) = oldLocation; // Maybe remove this + BALL_SteerMomentum(obj, paddle); // Sets it to unit vector! + // Following assumes that the paddle position was udated before the ball was updated + // BUG/GLITCH: Make sure that the postition of the ball is not shifted into the borders of the game! + while (RECT_Collide(&(obj->TargetRect), &(paddle->TargetRect))) { // Move away from rect in small steps + (obj->Location) = vectorAdd((obj->Location), (obj->Momentum)); + RECT_SetTargetPos(&(obj->TargetRect), &(obj->Location)); + } + (obj->Momentum) = vectorScaleTo((obj->Momentum), (obj->Speed)); + } + for (size_t i = 0; i < BlockCount; i++) { + if (blocks[i].HP <= 0) continue; + oldMomentum = obj->Momentum; + oldLocation = obj->Location; + if (BALL_CollideWithRect(obj, &(blocks[i].TargetRect))) { + BLOCK_DealDamage(blocks + i, 1); + (obj->Location) = vectorAdd(oldLocation, (obj->Momentum)); + RECT_SetTargetPos(&(obj->TargetRect), &(obj->Location)); + } } - if ((obj->Location).y > BREAKOUT_BoxHeight) - (obj->Location) = (Vector) {.x = BREAKOUT_BoxWidth / 2, .y = BREAKOUT_BoxHeight / 2 }; // Dead - if ((obj->Location).y < 0.0f) + if ((obj->Location).y > BREAKOUT_BoxHeight) // Collide with box boundaries + (obj->Location) = (Vector) {.x = BREAKOUT_BoxWidth / 2 + 300, .y = BREAKOUT_BoxHeight / 2 }; // Dead + else if ((obj->Location).y < 0.0f) (obj->Momentum).y = -(obj->Momentum).y; if ((obj->Location).x < 0.0f || (obj->Location).x > BREAKOUT_BoxWidth - (2 * (obj->Size))) (obj->Momentum).x = -(obj->Momentum).x; - (obj->TargetRect).x = (int)round((obj->Location).x); - (obj->TargetRect).y = (int)round((obj->Location).y); + RECT_SetTargetPos(&(obj->TargetRect), &(obj->Location)); } /* BALL_Update */ + void BALL_DestroyObject(Ball * obj){ } + void BALL_Deinitialize(){ if (BALL_IsInit) { printf("De-initializing Ball...\n"); - + SDL_DestroyTexture(BALL_Texture); printf("Ball de-initialized!\n"); BALL_IsInit = false; } else printf("Ball is already de-initialized!\n"); } - void PADDLE_Initialize(SDL_Renderer * renderer){ if (!PADDLE_IsInit) { printf("Initializing Paddle...\n"); - PADDLE_Texture = IMG_LoadTexture(renderer, "assets/images/paddle.png"); + PADDLE_Texture = IMG_LoadTexture(renderer, PADDLE_TexturePath); if (!PADDLE_Texture) printf("Paddle texture failed to load!\n"); PADDLE_SourceRects = (SDL_Rect *)malloc(1 * sizeof(SDL_Rect)); if (!PADDLE_SourceRects) printf("FATAL! Memory allocation failed!\n"); - PADDLE_SourceRects[0] = (SDL_Rect) {.x = 0, .y = 0, .w = 512, .h = 512 }; + PADDLE_SourceRects[0] = (SDL_Rect) {.x = 0, .y = 0, .w = 1000, .h = 100 }; PADDLE_MoveLeftKeys = (Uint8 *)malloc(2 * sizeof(Uint8)); if (!PADDLE_MoveLeftKeys) printf("FATAL! Memory allocation failed!\n"); PADDLE_MoveRightKeys = (Uint8 *)malloc(2 * sizeof(Uint8)); @@ -203,7 +305,6 @@ void PADDLE_Initialize(SDL_Renderer * renderer){ PADDLE_MoveRightKeys[0] = 2; PADDLE_MoveRightKeys[1] = SDL_SCANCODE_RIGHT; PADDLE_MoveRightKeys[2] = SDL_SCANCODE_D; - ball = BALL_CreateDefault(); printf("Paddle initialized!\n"); PADDLE_IsInit = true; } else printf("Paddle is already initialized!\n"); @@ -214,48 +315,151 @@ Paddle PADDLE_CreateDefault(){ return (Paddle) { .TargetRect = (SDL_Rect) {.x = (BREAKOUT_BoxWidth - defaultpaddlewidth) / 2, .y = BREAKOUT_BoxHeight - 100, .w = defaultpaddlewidth, .h = 30 }, - .TextureIndex = 0 + .TextureIndex = 0, + .Speed = 10, + .SteeringAngle = 40.0f, + .Mode = KeyboardControl }; // Objekt für die Eigenschaften des Balls } void PADDLE_Draw(SDL_Renderer * renderer, Paddle * obj){ // printf("Paddle drawn at (%d|%d)!\n", (obj->TargetRect).x, (obj->TargetRect).x); - // SDL_RenderCopy(renderer, PADDLE_Texture, PADDLE_SourceRects + (obj->TextureIndex), &(obj->TargetRect)); - SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); - SDL_RenderDrawRect(renderer, &(obj->TargetRect)); + SDL_RenderCopy(renderer, PADDLE_Texture, PADDLE_SourceRects + (obj->TextureIndex), &(obj->TargetRect)); + // SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + // SDL_RenderDrawRect(renderer, &(obj->TargetRect)); } -bool KeyPressed(Uint8 * keystate, Uint8 * keyArray){ +bool KeyPressed(const Uint8 * keystate, Uint8 * keyArray){ for (int i = 0; i < (*keyArray); i++) { if (keystate[keyArray[(i + 1)]]) return true; } return false; } -void constrain(int * variable, int min, int max){ +void INT_Constrain(int * variable, int min, int max){ if (*variable > max) *variable = max; else if (*variable < min) *variable = min; } -void PADDLE_Update(Paddle * obj, Uint8 * keystate){ - bool leftKeyPressed = KeyPressed(keystate, PADDLE_MoveLeftKeys), rightKeyPressed = KeyPressed(keystate, PADDLE_MoveRightKeys); +void DOUBLE_Constrain(double * variable, double min, double max){ + if (*variable > max) + *variable = max; + else if (*variable < min) + *variable = min; +} + +void PADDLE_Update(Paddle * obj, const Uint8 * keystate){ + bool leftKeyPressed = false, rightKeyPressed = false; + int paddleXMid = (obj->TargetRect).x + ((obj->TargetRect).w / 2); + int mouseX; + + switch (obj->Mode) { + case MouseControl: + SDL_GetMouseState(&mouseX, NULL); + if (abs(mouseX - paddleXMid) > (obj->Speed)) { + if (mouseX > paddleXMid) + rightKeyPressed = true; + else + leftKeyPressed = true; + } + break; + case KeyboardControl: + leftKeyPressed = KeyPressed(keystate, PADDLE_MoveLeftKeys); + rightKeyPressed = KeyPressed(keystate, PADDLE_MoveRightKeys); + break; + default: + printf("Unknown Paddle Control Mode: %d!\n", obj->Mode); + break; + } if (leftKeyPressed && (!rightKeyPressed)) { - ((obj->TargetRect).x) -= PADDLE_Speed; + ((obj->TargetRect).x) -= (obj->Speed); } else if ((!leftKeyPressed) && rightKeyPressed) { - ((obj->TargetRect).x) += PADDLE_Speed; + ((obj->TargetRect).x) += (obj->Speed); } - constrain(&((obj->TargetRect).x), 0, (BREAKOUT_BoxWidth - ((obj->TargetRect).w))); -} + INT_Constrain(&((obj->TargetRect).x), 0, (BREAKOUT_BoxWidth - ((obj->TargetRect).w))); +} /* PADDLE_Update */ + void PADDLE_DestroyObject(Paddle * obj){ } + void PADDLE_Deinitialize(){ if (PADDLE_IsInit) { printf("De-initializing Paddle...\n"); - + SDL_DestroyTexture(PADDLE_Texture); printf("Paddle de-initialized!\n"); PADDLE_IsInit = false; } else printf("Paddle is already de-initialized!\n"); } + +void BLOCK_Initialize(SDL_Renderer * renderer){ + if (!BLOCK_IsInit) { + printf("Initializing Block...\n"); + BLOCK_Texture = IMG_LoadTexture(renderer, BLOCK_TexturePath); + if (!BLOCK_Texture) printf("Block texture failed to load!\n"); + BLOCK_SourceRects = (SDL_Rect *)malloc(BLOCK_TextureCount * sizeof(SDL_Rect)); + if (!BLOCK_SourceRects) printf("FATAL! Memory allocation failed!\n"); + BLOCK_SourceRects[0] = (SDL_Rect) {.x = 2000, .y = 1500, .w = 1000, .h = 500 }; + BLOCK_SourceRects[1] = (SDL_Rect) {.x = 2000, .y = 2000, .w = 1000, .h = 500 }; + BLOCK_SourceRects[2] = (SDL_Rect) {.x = 2000, .y = 2500, .w = 1000, .h = 500 }; + BLOCK_SourceRects[3] = (SDL_Rect) {.x = 0, .y = 3000, .w = 1000, .h = 500 }; + BLOCK_SourceRects[4] = (SDL_Rect) {.x = 1000, .y = 3000, .w = 1000, .h = 500 }; + BLOCK_SourceRects[5] = (SDL_Rect) {.x = 2000, .y = 3000, .w = 1000, .h = 500 }; + BLOCK_SourceRects[6] = (SDL_Rect) {.x = 0, .y = 3500, .w = 1000, .h = 500 }; + BLOCK_SourceRects[7] = (SDL_Rect) {.x = 1000, .y = 3500, .w = 1000, .h = 500 }; + BLOCK_SourceRects[8] = (SDL_Rect) {.x = 2000, .y = 3500, .w = 1000, .h = 500 }; + BLOCK_SourceRects[9] = (SDL_Rect) {.x = 0, .y = 500, .w = 1000, .h = 500 }; + BLOCK_SourceRects[10] = (SDL_Rect) {.x = 2000, .y = 0, .w = 1000, .h = 500 }; + BLOCK_SourceRects[11] = (SDL_Rect) {.x = 0, .y = 1000, .w = 1000, .h = 500 }; + BLOCK_SourceRects[12] = (SDL_Rect) {.x = 0, .y = 1500, .w = 1000, .h = 500 }; + BLOCK_SourceRects[13] = (SDL_Rect) {.x = 1000, .y = 0, .w = 1000, .h = 500 }; + BLOCK_SourceRects[14] = (SDL_Rect) {.x = 1000, .y = 500, .w = 1000, .h = 500 }; + BLOCK_SourceRects[15] = (SDL_Rect) {.x = 1000, .y = 1000, .w = 1000, .h = 500 }; + BLOCK_SourceRects[16] = (SDL_Rect) {.x = 1000, .y = 1500, .w = 1000, .h = 500 }; + BLOCK_SourceRects[17] = (SDL_Rect) {.x = 0, .y = 2000, .w = 1000, .h = 500 }; + BLOCK_SourceRects[18] = (SDL_Rect) {.x = 1000, .y = 2000, .w = 1000, .h = 500 }; + BLOCK_SourceRects[19] = (SDL_Rect) {.x = 0, .y = 2500, .w = 1000, .h = 500 }; + BLOCK_SourceRects[20] = (SDL_Rect) {.x = 1000, .y = 2500, .w = 1000, .h = 500 }; + BLOCK_SourceRects[21] = (SDL_Rect) {.x = 0, .y = 0, .w = 1000, .h = 500 }; + BLOCK_SourceRects[22] = (SDL_Rect) {.x = 2000, .y = 500, .w = 1000, .h = 500 }; + BLOCK_SourceRects[23] = (SDL_Rect) {.x = 2000, .y = 1000, .w = 1000, .h = 500 }; + printf("Block initialized!\n"); + BLOCK_IsInit = true; + } else printf("Block is already initialized!\n"); +} /* PADDLE_Initialize */ + +Block BLOCK_CreateDefault() { + return (Block) { + .TargetRect = (SDL_Rect) {.x = 0, .y = 0, .w = 100, .h = 50 }, + .TextureIndex = (rand() % BLOCK_TextureCount), + .HP = 1 + }; // Objekt für die Eigenschaften des Balls +} + +void BLOCK_Draw(SDL_Renderer * renderer, Block * obj){ + if ((obj->HP) > 0) { + // printf("Block drawn at (%d|%d)!\n", (obj->TargetRect).x, (obj->TargetRect).y); + SDL_RenderCopy(renderer, BLOCK_Texture, (BLOCK_SourceRects + (obj->TextureIndex)), &(obj->TargetRect)); + } +} + +void BLOCK_DealDamage(Block * obj, int dmg){ + if (((obj->HP) -= dmg) <= 0) printf("Block was destroyed!\n"); +} + +void BLOCK_Update(Block * obj){ +// Do nothing currently +} +void BLOCK_DestroyObject(Block * obj){ +} + +void BLOCK_Deinitialize(){ + if (BLOCK_IsInit) { + printf("De-initializing Block...\n"); + SDL_DestroyTexture(BLOCK_Texture); + printf("Block de-initialized!\n"); + BLOCK_IsInit = false; + } else printf("Block is already de-initialized!\n"); +} diff --git a/breakout.h b/breakout.h index 82fec60..8a638d9 100644 --- a/breakout.h +++ b/breakout.h @@ -9,48 +9,75 @@ #include "vector.h" +// Enums +typedef enum controlModeEnum {KeyboardControl = 0, MouseControl = 1} ControlMode; +// End Enums + // Structs typedef struct ballStruct { Vector Location, Momentum; SDL_Rect TargetRect; double Size, Rotation, RotationValue; int TextureIndex; + double Speed; } Ball; // Objekt für die Eigenschaften des Balls typedef struct paddleStruct { SDL_Rect TargetRect; int TextureIndex; + int Speed; + double SteeringAngle; + ControlMode Mode; } Paddle; // Objekt für die Eigenschaften des Paddles typedef struct blockStruct { - Vector Location; SDL_Rect TargetRect; - int XSize, YSize, TextureIndex; + int TextureIndex, HP; } Block; // Objekt für die Eigenschaften des Paddles + +typedef struct sceneryStruct { + Ball ball; + Paddle paddle; + Block * blocks; + int BlockCount; // Move to scenery +} Scenery; // Objekt für die Objekte und Eigenschaften einer Szenerie // End Structs // Prototypes void BREAKOUT_INITIALIZE(SDL_Renderer * renderer, int width, int height); +Scenery BREAKOUT_CreateDefault(); void BREAKOUT_ChangeSize(int width, int height); -void BREAKOUT_Update(Uint8 * keystate); -void BREAKOUT_Draw(SDL_Renderer * renderer); +void BREAKOUT_Update(Scenery * scenery, const Uint8 * keystate); +void BREAKOUT_Draw(Scenery * scenery, SDL_Renderer * renderer); void BREAKOUT_DEINITIALIZE(); +void BREAKOUT_DestroyObject(Scenery * scenery); void BALL_Initialize(SDL_Renderer * renderer); Ball BALL_CreateDefault(); void BALL_Draw(SDL_Renderer * renderer, Ball * obj); bool BALL_CollideWithRect(Ball * obj, SDL_Rect * rect); bool RECT_Collide(SDL_Rect * rect1, SDL_Rect * rect2); -void BALL_Update(Ball * obj, Paddle * paddle); +void BALL_SteerMomentum(Ball * obj, Paddle * paddle); +void RECT_SetTargetPos(SDL_Rect * rect, Vector * Location); +SDL_Point BALL_GetCenter(Ball * obj); +void BALL_Update(Ball * obj, Paddle * paddle, Block * blocks, int BlockCount); void BALL_DestroyObject(Ball * obj); void BALL_Deinitialize(); void PADDLE_Initialize(SDL_Renderer * renderer); Paddle PADDLE_CreateDefault(); void PADDLE_Draw(SDL_Renderer * renderer, Paddle * obj); -bool KeyPressed(Uint8 * keystate, Uint8 * keyArray); -void constrain(int * variable, int min, int max); -void PADDLE_Update(Paddle * obj, Uint8 * keystate); +bool KeyPressed(const Uint8 * keystate, Uint8 * keyArray); +void INT_Constrain(int * variable, int min, int max); +void DOUBLE_Constrain(double * variable, double min, double max); +void PADDLE_Update(Paddle * obj, const Uint8 * keystate); void PADDLE_DestroyObject(Paddle * obj); void PADDLE_Deinitialize(); +void BLOCK_Initialize(SDL_Renderer * renderer); +Block BLOCK_CreateDefault() ; +void BLOCK_Draw(SDL_Renderer * renderer, Block * obj); +void BLOCK_DealDamage(Block * obj, int dmg); +void BLOCK_Update(Block * obj); +void BLOCK_DestroyObject(Block * obj); +void BLOCK_Deinitialize(); // End Prototypes #endif // __breakout_h__ diff --git a/button.c b/button.c new file mode 100644 index 0000000..e69de29 diff --git a/button.h b/button.h new file mode 100644 index 0000000..6e4c663 --- /dev/null +++ b/button.h @@ -0,0 +1,14 @@ +#ifndef __button_h__ +#define __button_h__ + +// Structs +typedef struct buttonStruct { + SDL_Rect TargetRect; + void (*OnClick)(); +} Button; +// End Structs + +// Prototypes +// End Prototypes + +#endif diff --git a/gamestate.h b/gamestate.h new file mode 100644 index 0000000..fca7225 --- /dev/null +++ b/gamestate.h @@ -0,0 +1,6 @@ +#ifndef __gamestate_h__ +#define __gamestate_h__ + +typedef enum gameStateEnum { MainMenu = 1, Game = 2, LevelSelect = 3, SkinSelect = 4, Settings = 5, Highscores = 6 } GameState; + +#endif diff --git a/highscores.c b/highscores.c new file mode 100644 index 0000000..ee5d98e --- /dev/null +++ b/highscores.c @@ -0,0 +1,167 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "highscores.h" + +#define HIGHSCORES_FontFile "assets/fonts/monofur.ttf" + +int HIGHSCORES_EntriesGot = 0; +User * HIGHSCORES_UserList; +SDL_Color HIGHSCORES_FontColor; +SDL_Texture * HIGHSCORES_TableTexture; +SDL_Rect HIGHSCORES_TotalRect; +TTF_Font * HIGHSCORES_FontFamily = NULL; +SDL_Surface * tempSurface; + +void HIGHSCORES_Initialize(){ + printf("Initializing Highscores...\n"); + HIGHSCORES_FontColor = (SDL_Color) {255, 255, 255 }; + HIGHSCORES_UserList = malloc(10 * sizeof(User)); + HIGHSCORES_FontFamily = TTF_OpenFont(HIGHSCORES_FontFile, 48); + if (!HIGHSCORES_FontFamily) printf("Font could not initialize! Error: %s\n", TTF_GetError()); + else printf("Font was successfully initialized!\n"); + printFontStyle(HIGHSCORES_FontFamily); + HIGHSCORES_TotalRect = (SDL_Rect) {.x = 0, .y = 0, .w = 1920, .h = 1080 }; + printf("Highscores initialized!\n"); +} + +void printFontStyle(TTF_Font * ffont){ + int style; + + style = TTF_GetFontStyle(ffont); + printf("The font style is:"); + if (style == TTF_STYLE_NORMAL) + printf(" normal"); + else { + if (style & TTF_STYLE_BOLD) + printf(" bold"); + if (style & TTF_STYLE_ITALIC) + printf(" italic"); + if (style & TTF_STYLE_UNDERLINE) + printf(" underline"); + if (style & TTF_STYLE_STRIKETHROUGH) + printf(" strikethrough"); + } + printf("\n"); +} + +void HIGHSCORES_Draw(SDL_Renderer * renderer){ + SDL_RenderCopy(renderer, HIGHSCORES_TableTexture, &HIGHSCORES_TotalRect, &HIGHSCORES_TotalRect); +} /* HIGHSCORES_Draw */ + +void HIGHSCORES_Deinitialize(){ + printf("De-initializing Highscores...\n"); + TTF_CloseFont(HIGHSCORES_FontFamily); + HIGHSCORES_FontFamily = NULL; // to be safe... + SDL_DestroyTexture(HIGHSCORES_TableTexture); + SDL_FreeSurface(tempSurface); + free(HIGHSCORES_UserList); + printf("Highscores de-initialized!\n"); +} + +void HIGHSCORES_GenerateTexture(SDL_Renderer * renderer){ + char * buffer = calloc(100, sizeof(char)); + int count = 0; + char format[20] = "| %-58s | %-10s |"; + SDL_Rect Message_rect; + SDL_Surface * HIGHSCORES_TableSurface = SDL_CreateRGBSurface(0, 1920, 1080, 32, 0, 0, 0, 0); + + if (!HIGHSCORES_TableSurface) { + printf("Surface wasn't created!\n"); + } + sprintf(buffer, format, "Username", "Score"); + HIGHSCORES_DrawText(buffer, &Message_rect); + Message_rect.y = 70; + Message_rect.x = 50; + Message_rect.h = 50; + Message_rect.w = 50; + SDL_BlitSurface(tempSurface, NULL, HIGHSCORES_TableSurface, &Message_rect); + SDL_FreeSurface(tempSurface); + while (count < HIGHSCORES_EntriesGot) { + sprintf(buffer, format, HIGHSCORES_UserList[count].Username, HIGHSCORES_UserList[count].Score); + HIGHSCORES_DrawText(buffer, &Message_rect); + Message_rect.y = ((Message_rect.h + 15) * (count + 1)) + 140; + Message_rect.x = 50; + SDL_BlitSurface(tempSurface, NULL, HIGHSCORES_TableSurface, &Message_rect); + SDL_FreeSurface(tempSurface); + count++; + } + HIGHSCORES_TableTexture = SDL_CreateTextureFromSurface(renderer, HIGHSCORES_TableSurface); + if (!HIGHSCORES_TableTexture) { + printf("Texture wasn't created!\n"); + } + SDL_FreeSurface(HIGHSCORES_TableSurface); +} /* HIGHSCORES_GenerateSurface */ + +void HIGHSCORES_DrawText(char * text, SDL_Rect * Message_rect){ + TTF_SizeText(HIGHSCORES_FontFamily, text, &(Message_rect->w), &(Message_rect->h)); + tempSurface = TTF_RenderText_Solid(HIGHSCORES_FontFamily, text, HIGHSCORES_FontColor); +} + +void HIGHSCORES_ReloadList(){ + printf("Call BHI interface:\n"); + system("bhi top output.txt"); + printf("BHI interface quit!\nBHI output handling...\n"); + + HIGHSCORES_EntriesGot = 0; + FILE * fp; + char * line = NULL; + size_t len = 0; + ssize_t read; + char * name, * scorestring; + int nameCharCount = 0, scoreCharCount = 0; + bool switchread = false; + HIGHSCORES_UserList = malloc(10 * sizeof(User)); + fp = fopen("output.txt", "r"); + if (fp == NULL) + return; + if ((read = getline(&line, &len, fp)) != -1) + if (line[0] == 0) + return; + int counter = 0; + while ((read = getline(&line, &len, fp)) != -1) { + name = malloc(read * sizeof(char)); + scorestring = malloc(read * sizeof(char)); + nameCharCount = 0; + scoreCharCount = 0; + switchread = false; + #ifdef DEBUG + printf("Retrieved line of length %u:\n", read); + printf("%s", line); + #endif + for (ssize_t i = 0; i < read; i++) { + if (line[i] == '+') { + switchread = true; + continue; + } + if (switchread) { + if (line[i] == '\n') break; + scorestring[scoreCharCount++] = line[i]; + } else + name[nameCharCount++] = line[i]; + } + name[nameCharCount] = '\0'; + scorestring[scoreCharCount] = '\0'; + User tmp; + strcpy(tmp.Username, name); + strcpy(tmp.Score, scorestring); + HIGHSCORES_UserList[counter++] = tmp; + } + free(name); + free(scorestring); + + fclose(fp); + if (line) + free(line); + for (size_t i = 0; i < counter; i++) { + printf("User: %s -> Score: %s\n", HIGHSCORES_UserList[i].Username, HIGHSCORES_UserList[i].Score); + } + + HIGHSCORES_EntriesGot = counter; + printf("BHI Interface successfully quit!\n"); +} /* main */ diff --git a/highscores.h b/highscores.h new file mode 100644 index 0000000..abf70ff --- /dev/null +++ b/highscores.h @@ -0,0 +1,20 @@ +#ifndef __highscores_h__ +#define __highscores_h__ + +// Structs +typedef struct userStruct { + char Username[50], Score[30]; +} User; +// End Structs + +// Prototypes +void HIGHSCORES_Initialize(); +void printFontStyle(TTF_Font * ffont); +void HIGHSCORES_Draw(SDL_Renderer * renderer); +void HIGHSCORES_Deinitialize(); +void HIGHSCORES_GenerateTexture(SDL_Renderer * renderer); +void HIGHSCORES_DrawText(char * text, SDL_Rect * Message_rect); +void HIGHSCORES_ReloadList(); +// End Prototypes + +#endif diff --git a/main.c b/main.c index e286a30..48da5fc 100644 --- a/main.c +++ b/main.c @@ -9,63 +9,105 @@ #include "breakout.h" #include "vector.h" +#include "startmenu.h" +#include "gamestate.h" +#include "highscores.h" +#include "settings.h" -#ifndef __nullptr__ -#define Nullptr(type) (type *)0 -#endif // __nullptr__ +#include "main.h" -void DrawFrame(); -void INITIALIZE(); -void QUIT(); -void GAMELOOP(); -void mousePress(SDL_MouseButtonEvent b); -void keyPress(SDL_KeyboardEvent b); -void windowChanged(SDL_WindowEvent b); -void toggleFullscreen(); +// Default Render Size (Upscaled for bigger monitors) +const int width = 1920; +const int height = 1080; +float XScale = 1.0f, YScale = 1.0f; +// End render properties -const int width = 1600; // TODO: Fullscreen -const int height = 900; - -Uint8 * keystate; // TODO: export all this into scenery and enemy waves +int numKeys; +const Uint8 * keystate; // TODO: export all this into scenery and enemy waves SDL_Window * window; SDL_Renderer * renderer; SDL_Event event; bool running = true, fullscreen = false; - -Ball ball; +GameState gameState = MainMenu; +Scenery scenery; int main(int argc, char * args[]){ - // system("bhi.exe"); + // printf("Spielbereiche\n\t- 1: Hauptmen"ue "\n\t- 2: Spiel\n\t- 3: Level Select\n\t- 4: Settings\n\t- 5: Highscores\n"); + // GAME_ChangeState(readIntFromIO("W"ae "hle einen Spielbereich aus, den du testen m"oe "chtest:", "Fehlerhafte Eingabe!\n", "%d ist kein g"ue "ltiger Spielbereich!\n", 1, 5)); INITIALIZE(); while (running) { // Gameloop - while (SDL_PollEvent(&event)) { - switch (event.type) { - case SDL_QUIT: - running = false; - break; - case SDL_KEYDOWN: - if (event.key.keysym.scancode == SDL_SCANCODE_ESCAPE) running = false; - else keyPress(event.key); - break; - case SDL_MOUSEBUTTONDOWN: - mousePress(event.button); - break; - case SDL_WINDOWEVENT: - windowChanged(event.window); - break; - } + HandleSDLEvents(); + DrawBackground(renderer); + switch (gameState) { + case Game: + BREAKOUT_Update(&scenery, keystate); + BREAKOUT_Draw(&scenery, renderer); + break; + case MainMenu: + // Startmenu_Update(keystate); + Startmenu_Draw(renderer); + break; + case Highscores: + HIGHSCORES_Draw(renderer); + break; + case Settings: + Settings_Draw(renderer); + break; + default: + printf("Unknow state was updated: %d\n", gameState); + break; } - GAMELOOP(); - DrawFrame(); + SDL_RenderPresent(renderer); } QUIT(); return 0; } /* main */ -void GAMELOOP() { - keystate = SDL_GetKeyboardState(NULL); - BREAKOUT_Update(keystate); -} /* GAMELOOP */ +void GAME_Escape(){ + running = false; + printf("GAME_Escape was called!\n"); +} + +void GAME_ChangeState(GameState state){ + if (gameState == state) { + printf("State wasn't changed!\n"); + return; + } + gameState = state; + switch (gameState) { + case Highscores: + HIGHSCORES_ReloadList(); + HIGHSCORES_GenerateTexture(renderer); + printf("State was changed to Highscores!\n"); + break; + default: + printf("State was changed to %d!\n", gameState); + break; + } +} + +void HandleSDLEvents(){ + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_QUIT: + printf("NOTICE: User manually quit window!\n"); + running = false; + break; + case SDL_KEYDOWN: + // if (event.key.keysym.scancode == SDL_SCANCODE_ESCAPE) running = false; + // else + keyPress(event.key); + break; + case SDL_MOUSEBUTTONDOWN: + mousePress(event.button); + button_clicked(event.button, gameState); + break; + case SDL_WINDOWEVENT: + windowChanged(event.window); + break; + } + } +} /* HandleSDLEvents */ void mousePress(SDL_MouseButtonEvent b){ // Debug prop if (b.button == SDL_BUTTON_LEFT) { @@ -97,25 +139,29 @@ void windowChanged(SDL_WindowEvent b){ // Debug prop switch (b.event) { case SDL_WINDOWEVENT_SIZE_CHANGED: printf("Window was resized to (%d|%d)!\n", event.window.data1, event.window.data2); - BREAKOUT_ChangeSize(event.window.data1, event.window.data2); + // BREAKOUT_ChangeSize(event.window.data1, event.window.data2); + XScale = ((double)(event.window.data1) / (double)width); + YScale = ((double)(event.window.data2) / (double)height); + SDL_RenderSetScale(renderer, XScale, YScale); break; } } -void DrawFrame(){ +void DrawBackground(SDL_Renderer * renderer){ SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL_RenderClear(renderer); - BREAKOUT_Draw(renderer); - SDL_RenderPresent(renderer); -} +} /* DrawFrame */ void INITIALIZE() { + printf("Initializing started...\n"); srand(time(NULL)); - if (SDL_Init(SDL_INIT_EVERYTHING) != 0) printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError()); + if (SDL_Init(SDL_INIT_EVERYTHING) != 0) printf("SDL could not initialize! Error: %s\n", SDL_GetError()); else printf("SDL was successfully initialized!\n"); - if (IMG_Init(IMG_INIT_PNG) != IMG_INIT_PNG) printf("IMG could not initialize! IMG_Error: %s\n", IMG_GetError()); + keystate = SDL_GetKeyboardState(&numKeys); + if (IMG_Init(IMG_INIT_PNG) != IMG_INIT_PNG) printf("IMG could not initialize! Error: %s\n", IMG_GetError()); else printf("IMG was successfully initialized!\n"); - TTF_Init(); + if (TTF_Init() == -1) printf("TTF could not initialize! Error: %s\n", TTF_GetError()); + else printf("TTF was successfully initialized!\n"); window = SDL_CreateWindow("BreakING", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_OPENGL); SDL_SetWindowResizable(window, true); @@ -123,12 +169,19 @@ void INITIALIZE() { renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); printf("Renderer was created!\n"); BREAKOUT_INITIALIZE(renderer, width, height); + scenery = BREAKOUT_CreateDefault(); + Load_Textures(renderer); + HIGHSCORES_Initialize(); + Settings_Initialize(renderer); + printf("Initializing finished!\n"); } /* INITIALIZE */ void QUIT(){ printf("De-initializing started...\n"); + Settings_Deinitialize(); + HIGHSCORES_Deinitialize(); + BREAKOUT_DestroyObject(&scenery); BREAKOUT_DEINITIALIZE(); - free(keystate); TTF_Quit(); IMG_Quit(); printf("Quitting SDL_IMG finished!\n"); @@ -140,3 +193,28 @@ void QUIT(){ printf("Quitting SDL finished!\n"); printf("De-initializing finished!\n"); } /* QUIT */ + +int readIntFromIO(char * m1, char * m2, char * m3, int min, int max){ + int nitems, num; + + while (1) { + while (1) { + printf(m1); + nitems = scanf("%d", &num); + if (nitems == 0) { + printf(m2); + fflush(stdin); + continue; + } else { + break; + } + } + if ((num < min) || (num > max)) { + printf(m3, num); + } else { + break; + } + } + fflush(stdin); + return(num); +} /* readIntFromIO */ diff --git a/main.h b/main.h new file mode 100644 index 0000000..c2b62b9 --- /dev/null +++ b/main.h @@ -0,0 +1,42 @@ +#ifndef __main_h__ +#define __main_h__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "breakout.h" +#include "vector.h" +#include "startmenu.h" +#include "gamestate.h" +#include "highscores.h" + +#ifndef __nullptr__ +#define Nullptr(type) (type *)0 +#endif // __nullptr__ + +#define ae "\204" +#define oe "\224" +#define ue "\201" +#define ss "\341" + +// Prototypes +void GAME_ChangeState(GameState state); +void HandleSDLEvents(); +void GAME_Escape(); +void mousePress(SDL_MouseButtonEvent b); +void keyPress(SDL_KeyboardEvent b); +void toggleFullscreen(); +void windowChanged(SDL_WindowEvent b); +void DrawBackground(SDL_Renderer * renderer); +void INITIALIZE(); +void QUIT(); +int readIntFromIO(char * m1, char * m2, char * m3, int min, int max); +// End Prototypes + +#endif // __main_h__ diff --git a/paddle.c b/paddle.c new file mode 100644 index 0000000..e69de29 diff --git a/settings.c b/settings.c new file mode 100644 index 0000000..ea4baa7 --- /dev/null +++ b/settings.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include + +SDL_Texture* Setting_Texture; + +SDL_Rect Settings_rect; +SDL_Rect BV_Bar_rect; +SDL_Rect BV_Scalar_rect; +SDL_Rect BS_Bar_rect; +SDL_Rect BT_Bar_rect; +SDL_Rect BVController_rect; + +bool Settings_IsInit=false; + +void Settings_Initialize (SDL_Renderer* renderer) { + BV_Bar_rect = (SDL_Rect){.y = 300,.x = 400 , .w=400, .h=100}; + BV_Scalar_rect = (SDL_Rect){.y=300,.x=420,.w=20,.h=100}; + BS_Bar_rect = (SDL_Rect){.y = 500,.x = 400, .w=400, .h=100}; + BT_Bar_rect = (SDL_Rect){.y = 700,.x = 400, .w=400, .h=100}; + Setting_Texture = IMG_LoadTexture(renderer, "assets/images/settings_title.png"); + Settings_rect = (SDL_Rect){.x = 800, .y = 180, .w=313, .h=100}; + Settings_IsInit = true; +} + +void Settings_Draw (SDL_Renderer* renderer) { + SDL_SetRenderDrawColor(renderer,255,255,255,255); + SDL_RenderDrawRect(renderer,&BV_Bar_rect); + SDL_RenderDrawRect(renderer,&BS_Bar_rect); + SDL_RenderDrawRect(renderer,&BT_Bar_rect); + SDL_RenderDrawRect(renderer,&BV_Scalar_rect); + SDL_RenderCopy(renderer, Setting_Texture, NULL, &Settings_rect); + int x,y; + Uint32 Mousestate=SDL_GetMouseState(&x,&y); + if(y<=400&&y>=300&&x<=800&&x>=400&&(Mousestate & SDL_BUTTON(SDL_BUTTON_LEFT))){ + SDL_RenderFillRect(renderer,&BV_Scalar_rect); + SDL_RenderDrawRect(renderer,&BV_Scalar_rect); + if(x>790){ + BV_Scalar_rect.x=780; + } + else if(x<410){ + BV_Scalar_rect.x=400; + } + else{ + BV_Scalar_rect.x=x-10; + } + } + else{ + SDL_RenderDrawRect(renderer,&BV_Scalar_rect); + } + printf("%d,%d\n",x,y); + +} + +void Settings_Deinitialize(){ + if(Settings_IsInit){ + SDL_DestroyTexture(Setting_Texture); + Settings_IsInit=false; + } +} diff --git a/settings.h b/settings.h new file mode 100644 index 0000000..9234bf2 --- /dev/null +++ b/settings.h @@ -0,0 +1,18 @@ +#ifndef __Settings__ + +#define __Settings__ + +#include +#include +#include +#include +#include + + +void Settings_Initialize (SDL_Renderer* renderer); + +void Settings_Draw (SDL_Renderer* renderer); + +void Settings_Deinitialize(); + +#endif diff --git a/startmenu.c b/startmenu.c new file mode 100644 index 0000000..4fdc72a --- /dev/null +++ b/startmenu.c @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#include "gamestate.h" +#include "main.h" + + +SDL_Texture * TITLE_Texture; +SDL_Texture * PLAYBUTTON_Texture; +SDL_Texture * SKINSBUTTON_Texture; +SDL_Texture * LEVELBUTTON_Texture; +SDL_Texture * SETTINGSBUTTON_Texture; +SDL_Texture * HIGHSCORESBUTTON_Texture; +SDL_Texture * QUITBUTTON_Texture; + +SDL_Rect TITLE_Rect; +SDL_Rect PLAYBUTTON_Rect; +SDL_Rect SETTINGSBUTTON_Rect; +SDL_Rect LEVELBUTTON_Rect; +SDL_Rect SKINSBUTTON_Rect; +SDL_Rect HIGHSCORESBUTTON_Rect; +SDL_Rect QUITBUTTON_Rect; + +int clickInRect(SDL_MouseButtonEvent b, SDL_Rect * area_rect) { + return (((b.x) >= (area_rect->x)) && ((b.x) <= ((area_rect->x) + (area_rect->w))) && ((b.y) >= (area_rect->y)) && ((b.y) <= ((area_rect->y) + (area_rect->h)))); +} + +void Load_Textures(SDL_Renderer * renderer) { + TITLE_Texture = IMG_LoadTexture(renderer, "assets/images/breaking_button.png"); + TITLE_Rect = (SDL_Rect) {.x = 685, .y = 50, .w = 550, .h = 250 }; + + PLAYBUTTON_Texture = IMG_LoadTexture(renderer, "assets/images/play_button.png"); + PLAYBUTTON_Rect = (SDL_Rect) {.x = 497, .y = 400, .w = 313, .h = 178 }; + + SKINSBUTTON_Texture = IMG_LoadTexture(renderer, "assets/images/skins_button.png"); + SKINSBUTTON_Rect = (SDL_Rect) {.x = 1110, .y = 400, .w = 313, .h = 178 }; + + LEVELBUTTON_Texture = IMG_LoadTexture(renderer, "assets/images/level_button.png"); + LEVELBUTTON_Rect = (SDL_Rect) {.x = 497, .y = 700, .w = 313, .h = 178 }; + + SETTINGSBUTTON_Texture = IMG_LoadTexture(renderer, "assets/images/settings_button.png"); + SETTINGSBUTTON_Rect = (SDL_Rect) {.x = 1110, .y = 700, .w = 313, .h = 178 }; + + HIGHSCORESBUTTON_Texture = IMG_LoadTexture(renderer, "assets/images/highscores_button.png"); + HIGHSCORESBUTTON_Rect = (SDL_Rect) {.x = 1557, .y = 120, .w = 313, .h = 178 }; + + QUITBUTTON_Texture = IMG_LoadTexture(renderer, "assets/images/quit_button.png"); + QUITBUTTON_Rect = (SDL_Rect) {.x = 50, .y = 896, .w = 235, .h = 134 }; +} /* Load_Textures */ + +void Startmenu_Draw(SDL_Renderer * renderer) { + SDL_RenderCopy(renderer, TITLE_Texture, NULL, &TITLE_Rect); + SDL_RenderCopy(renderer, PLAYBUTTON_Texture, NULL, &PLAYBUTTON_Rect); + SDL_RenderCopy(renderer, SKINSBUTTON_Texture, NULL, &SKINSBUTTON_Rect); + SDL_RenderCopy(renderer, LEVELBUTTON_Texture, NULL, &LEVELBUTTON_Rect); + SDL_RenderCopy(renderer, SETTINGSBUTTON_Texture, NULL, &SETTINGSBUTTON_Rect); + SDL_RenderCopy(renderer, HIGHSCORESBUTTON_Texture, NULL, &HIGHSCORESBUTTON_Rect); + SDL_RenderCopy(renderer, QUITBUTTON_Texture, NULL, &QUITBUTTON_Rect); +} + +void button_clicked(SDL_MouseButtonEvent b, GameState gameState) { + if (gameState == MainMenu) { + if (clickInRect(b, &PLAYBUTTON_Rect) == 1) { + GAME_ChangeState(Game); + } else if (clickInRect(b, &SKINSBUTTON_Rect) == 1) { + GAME_ChangeState(SkinSelect); + } else if (clickInRect(b, &LEVELBUTTON_Rect) == 1) { + GAME_ChangeState(LevelSelect); + } else if (clickInRect(b, &SETTINGSBUTTON_Rect) == 1) { + GAME_ChangeState(Settings); + } else if (clickInRect(b, &HIGHSCORESBUTTON_Rect) == 1) { + GAME_ChangeState(Highscores); + } else if (clickInRect(b, &QUITBUTTON_Rect) == 1) { + GAME_Escape(); + } + } +} diff --git a/startmenu.h b/startmenu.h new file mode 100644 index 0000000..c4c2cab --- /dev/null +++ b/startmenu.h @@ -0,0 +1,20 @@ +#ifndef __Startmenu__ + +#define __Startmenu__ + +#include +#include +#include +#include + +#include "gamestate.h" + +void Load_Textures (SDL_Renderer* renderer); + +void Startmenu_Draw (SDL_Renderer* renderer); + +void button_clicked(SDL_MouseButtonEvent b, GameState gameState); + +int clickInRect(SDL_MouseButtonEvent b, SDL_Rect* area_rect); + +#endif