From d7e5845e4e7a2b5a2a1366ef07b936e1631d0b59 Mon Sep 17 00:00:00 2001 From: Michael Chen Date: Tue, 23 Jan 2018 21:22:59 +0100 Subject: [PATCH] Added ingame HUD and texture helper functions --- breakout.c | 116 +++++++++++++++++++++++++++++++++++------------------ breakout.h | 7 +++- 2 files changed, 83 insertions(+), 40 deletions(-) diff --git a/breakout.c b/breakout.c index 518b1de..63044eb 100644 --- a/breakout.c +++ b/breakout.c @@ -9,8 +9,12 @@ #include "breakout.h" #include "vector.h" +#include "gamestate.h" +#include "gameover.h" +#include "main.h" extern float XScale, YScale; +extern int width, height; #define BALL_TexturePath "assets/images/ball.png" #define PADDLE_TexturePath "assets/images/paddle.png" @@ -19,6 +23,8 @@ extern float XScale, YScale; #define BALL_MinSpeed 8.0f #define BALL_MaxSpeed 50.0f #define BALL_AccelerationTime 18000 +#define BREAKOUT_LiveHUDSize 35 +#define BREAKOUT_LiveHUDMargin 8 #ifndef __nullptr__ #define Nullptr(type) (type *)0 @@ -29,7 +35,6 @@ int BLOCK_TextureCount = 24; int BALL_TextureCount = 9; int GAME_CountdownTextureCount = 4; int PADDLE_TextureCount = 9; -int BREAKOUT_BoxWidth, BREAKOUT_BoxHeight; SDL_Texture * BALL_Texture; SDL_Texture * GAME_CountdownTexture; SDL_Texture * PADDLE_Texture; @@ -44,12 +49,10 @@ bool BALL_IsInit = false; bool PADDLE_IsInit = false; bool BLOCK_IsInit = false; -void BREAKOUT_INITIALIZE(SDL_Renderer * renderer, int width, int height){ +void BREAKOUT_INITIALIZE(SDL_Renderer * renderer){ if (!BREAKOUT_IsInit) { printf("Initializing Game...\n"); srand(time(NULL)); - BREAKOUT_BoxWidth = width; - BREAKOUT_BoxHeight = height; BALL_Initialize(renderer); PADDLE_Initialize(renderer); BLOCK_Initialize(renderer); @@ -94,18 +97,15 @@ Scenery BREAKOUT_CreateDefault(){ return scenery; } /* BREAKOUT_CreateDefault */ - -int BREAKOUT_RefreshScore(Scenery * scenery){ - (scenery->Score) = (int)round((double)(scenery->Frames) * 0.005f * ((scenery->ball).Speed) + (double)(50 * (scenery->DestroyedBlocks))); - printf("Score: %d\n", (scenery->Score)); - return (scenery->Score); +void BREAKOUT_IncreaseScoreBy(Scenery * scenery, int scoreInc){ + (scenery->Score) += scoreInc; } -// This Function is obsolete! Do not use it! -void BREAKOUT_ChangeSize(int width, int height){ - BREAKOUT_BoxWidth = width; - BREAKOUT_BoxHeight = height; -} +// int BREAKOUT_RefreshScore(Scenery * scenery){ +// (scenery->Score) = (int)round(((scenery->ball).Speed) * (double)(scenery->DestroyedBlocks)); +// printf("Score: %d\n", (scenery->Score)); +// return (scenery->Score); +// } void BREAKOUT_Update(Scenery * scenery, const Uint8 * keystate){ if (scenery->IsPaused) { @@ -113,11 +113,10 @@ void BREAKOUT_Update(Scenery * scenery, const Uint8 * keystate){ return; } if ((scenery->StartCountdown)-- > 0) { - // Render "Countdown" + // SDL_WarpMouse(960, 540); Doesn't exist return; } (scenery->Frames)++; - BREAKOUT_RefreshScore(scenery); if (scenery->IsGameOver) { BALL_ResetPosition(&(scenery->ball)); PADDLE_ResetPosition(&(scenery->paddle)); @@ -125,7 +124,7 @@ void BREAKOUT_Update(Scenery * scenery, const Uint8 * keystate){ scenery->IsGameOver = false; scenery->Frames = 0; if (--(scenery->Lives) <= 0) - printf("Game over, no lives left!\n"); + GAME_ChangeState(GameOver); else printf("Oh oh, only %d lives left!\n", scenery->Lives); return; @@ -146,10 +145,26 @@ void BREAKOUT_Draw(Scenery * scenery, SDL_Renderer * renderer){ if ((scenery->StartCountdown) > 0) { // ! Render Z-Layer ! SDL_Rect * rect = GAME_CountdownSourceRects + (((scenery->StartCountdown) - 1) / 60); SDL_Rect target = *rect; - target.x = ((BREAKOUT_BoxWidth - (rect->w)) / 2); - target.y = ((BREAKOUT_BoxHeight - (rect->h)) / 2); + target.x = ((width - (rect->w)) / 2); + target.y = ((height - (rect->h)) / 2); SDL_RenderCopy(renderer, GAME_CountdownTexture, rect, &target); } + SCORE_DrawHUD(renderer, scenery); + BREAKOUT_DrawLivesHUD(renderer, scenery); +} + +void BREAKOUT_DrawLivesHUD(SDL_Renderer * renderer, Scenery * scenery){ + SDL_Rect tmpRect; + + tmpRect.y = BREAKOUT_LiveHUDMargin; + tmpRect.w = BREAKOUT_LiveHUDSize; + tmpRect.h = BREAKOUT_LiveHUDSize; + tmpRect.x = width - BREAKOUT_LiveHUDMargin; + + for (int i = 0; i < (scenery->Lives); i++) { + tmpRect.x -= (BREAKOUT_LiveHUDSize + BREAKOUT_LiveHUDMargin); + BALL_DrawTexture(renderer, &tmpRect, (scenery->ball).TextureIndex); + } } void BREAKOUT_DEINITIALIZE(){ @@ -202,27 +217,33 @@ void BALL_Initialize(SDL_Renderer * renderer){ } /* BALL_Initialize */ Ball BALL_CreateDefault(){ - double rotation = (double)(rand() % 360); - return (Ball) { - .Location = (Vector) {.x = BREAKOUT_BoxWidth / 2 - 15, .y = BREAKOUT_BoxHeight - 132 }, - .Momentum = (Vector) {.x = 0.0f, .y = 15.0f }, - .TargetRect = (SDL_Rect) {.x = BREAKOUT_BoxWidth / 2 - 15, .y = BREAKOUT_BoxHeight - 130, .w = 30, .h = 30 }, + .Location = (Vector) {.x = (width / 2) - 15, .y = height - 132 }, + .Momentum = (Vector) {.x = 0.0f, .y = BALL_MinSpeed }, + .TargetRect = (SDL_Rect) {.x = width / 2 - 15, .y = height - 130, .w = 30, .h = 30 }, .Size = 15.0f, - .Rotation = rotation, - .RotationValue = 5, + .Rotation = 0, + .RotationValue = 9, .TextureIndex = 0, .Speed = 15.0f }; // Objekt für die Eigenschaften des Balls } void BALL_ResetPosition(Ball * obj){ - (obj->Location).x = BREAKOUT_BoxWidth / 2 - 15; - (obj->Location).y = BREAKOUT_BoxHeight - 130; + (obj->Location).x = width / 2 - 15; + (obj->Location).y = height - 130; RECT_SetTargetPos(&(obj->TargetRect), &(obj->Location)); (obj->Momentum) = VECTOR_GetScaledDirectionalUnitVector(0.0f, (obj->Speed)); } +void BALL_DrawTexture(SDL_Renderer * renderer, SDL_Rect * dstRect, int index){ + if (index > BALL_TextureCount || index < 0) { + printf("Ball with unkown texture index %d aus [0,...,%d]\n", index, (BALL_TextureCount - 1)); + return; + } + SDL_RenderCopy(renderer, BALL_Texture, BALL_SourceRects + index, dstRect); +} + void BALL_Draw(SDL_Renderer * renderer, Ball * obj){ // printf("Ball drawn at (%d|%d)!\n", (obj->TargetRect).x, (obj->TargetRect).x); SDL_RenderCopyEx(renderer, BALL_Texture, BALL_SourceRects + (obj->TextureIndex), &(obj->TargetRect), obj->Rotation, NULL, SDL_FLIP_NONE); @@ -308,7 +329,7 @@ SDL_Point BALL_GetCenter(Ball * obj){ void BALL_CollideWithBorders(Ball * obj){ 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))) + if ((obj->Location).x < 0.0f || (obj->Location).x > width - (2 * (obj->Size))) (obj->Momentum).x = -(obj->Momentum).x; } @@ -317,7 +338,7 @@ void BALL_MoveAwayFromBoundaries(Ball * obj){ ((obj->Location).y)++; while (((obj->Location).x) < 0) ((obj->Location).x)++; - while ((((obj->Location).x) + ((obj->Size) * 2)) > BREAKOUT_BoxWidth) + while ((((obj->Location).x) + ((obj->Size) * 2)) > width) ((obj->Location).x)--; } @@ -328,7 +349,7 @@ bool BALL_CollideWithPaddle(Ball * obj, Paddle * paddle){ BALL_CollideWithRect(obj, &(paddle->TargetRect)); else BALL_SteerMomentum(obj, paddle); // Sets it to unit vector! - // Following assumes that the paddle position was udated before the ball was updated + // Following assumes that the paddle position was udated before the ball was updated while (RECT_Collide(&(obj->TargetRect), &(paddle->TargetRect))) { // Move away from rect in small steps (obj->Location) = VECTOR_Add((obj->Location), (obj->Momentum)); BALL_MoveAwayFromBoundaries(obj); @@ -367,16 +388,19 @@ void BALL_Update(Ball * obj, Scenery * scenery){ oldLocation = obj->Location; if (BALL_CollideWithRect(obj, &(blocks[i].TargetRect))) { BLOCK_DealDamage(blocks + i, 1); - if (blocks[i].HP <= 0) + if (blocks[i].HP <= 0) { (scenery->DestroyedBlocks)++; + BREAKOUT_IncreaseScoreBy(scenery, (int)round((((scenery->ball).Speed) * ((scenery->ball).Speed) / 5.0f))); + } (obj->Location) = VECTOR_Add(oldLocation, (obj->Momentum)); BALL_MoveAwayFromBoundaries(obj); RECT_SetTargetPos(&(obj->TargetRect), &(obj->Location)); } } - if ((obj->Location).y > BREAKOUT_BoxHeight) // Collide with box boundaries + if ((obj->Location).y > height) { // Collide with box boundaries scenery->IsGameOver = true; - else BALL_CollideWithBorders(obj); + printf("Ball called game_over!\n"); + } else BALL_CollideWithBorders(obj); RECT_SetTargetPos(&(obj->TargetRect), &(obj->Location)); } /* BALL_Update */ @@ -419,7 +443,7 @@ Paddle PADDLE_CreateDefault(){ int defaultpaddlewidth = 300; return (Paddle) { - .TargetRect = (SDL_Rect) {.x = (BREAKOUT_BoxWidth - defaultpaddlewidth) / 2, .y = BREAKOUT_BoxHeight - 100, .w = defaultpaddlewidth, .h = 30 }, + .TargetRect = (SDL_Rect) {.x = (width - defaultpaddlewidth) / 2, .y = height - 100, .w = defaultpaddlewidth, .h = 30 }, .TextureIndex = 0, .Speed = 10, .SteeringAngle = 40.0f, @@ -428,8 +452,16 @@ Paddle PADDLE_CreateDefault(){ } void PADDLE_ResetPosition(Paddle * obj){ - (obj->TargetRect).x = (BREAKOUT_BoxWidth - ((obj->TargetRect).w)) / 2; - (obj->TargetRect).y = BREAKOUT_BoxHeight - 100; + (obj->TargetRect).x = (width - ((obj->TargetRect).w)) / 2; + (obj->TargetRect).y = height - 100; +} + +void PADDLE_DrawTexture(SDL_Renderer * renderer, SDL_Rect * dstRect, int index){ + if (index > PADDLE_TextureCount || index < 0) { + printf("Paddle with unkown texture index %d aus [0,...,%d]\n", index, (PADDLE_TextureCount - 1)); + return; + } + SDL_RenderCopy(renderer, PADDLE_Texture, PADDLE_SourceRects + index, dstRect); } void PADDLE_Draw(SDL_Renderer * renderer, Paddle * obj){ @@ -488,7 +520,7 @@ void PADDLE_Update(Paddle * obj, const Uint8 * keystate){ printf("Unknown Paddle Control Mode: %d!\n", obj->Mode); break; } /* switch */ - INT_Constrain(&((obj->TargetRect).x), 0, (BREAKOUT_BoxWidth - ((obj->TargetRect).w))); + INT_Constrain(&((obj->TargetRect).x), 0, (width - ((obj->TargetRect).w))); } /* PADDLE_Update */ void PADDLE_DestroyObject(Paddle * obj){ @@ -547,6 +579,14 @@ Block BLOCK_CreateDefault() { }; // Objekt für die Eigenschaften des Balls } +void BLOCK_DrawTexture(SDL_Renderer * renderer, SDL_Rect * dstRect, int index){ + if (index > BLOCK_TextureCount || index < 0) { + printf("Block with unkown texture index %d aus [0,...,%d]\n", index, (BLOCK_TextureCount - 1)); + return; + } + SDL_RenderCopy(renderer, BLOCK_Texture, BLOCK_SourceRects + index, dstRect); +} + 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); diff --git a/breakout.h b/breakout.h index b8bea2c..16133a9 100644 --- a/breakout.h +++ b/breakout.h @@ -45,17 +45,18 @@ typedef struct sceneryStruct { // End Structs // Prototypes -void BREAKOUT_INITIALIZE(SDL_Renderer * renderer, int width, int height); +void BREAKOUT_INITIALIZE(SDL_Renderer * renderer); Scenery BREAKOUT_CreateDefault(); int BREAKOUT_RefreshScore(Scenery * scenery); -void BREAKOUT_ChangeSize(int width, int height); void BREAKOUT_Update(Scenery * scenery, const Uint8 * keystate); void BREAKOUT_Draw(Scenery * scenery, SDL_Renderer * renderer); +void BREAKOUT_DrawLivesHUD(SDL_Renderer * renderer, Scenery * scenery); void BREAKOUT_DEINITIALIZE(); void BREAKOUT_DestroyObject(Scenery * scenery); void BALL_Initialize(SDL_Renderer * renderer); Ball BALL_CreateDefault(); void BALL_ResetPosition(Ball * obj); +void BALL_DrawTexture(SDL_Renderer * renderer, SDL_Rect * dstRect, int index); 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); @@ -72,6 +73,7 @@ void BALL_Deinitialize(); void PADDLE_Initialize(SDL_Renderer * renderer); Paddle PADDLE_CreateDefault(); void PADDLE_ResetPosition(Paddle * obj); +void PADDLE_DrawTexture(SDL_Renderer * renderer, SDL_Rect * dstRect, int index); void PADDLE_Draw(SDL_Renderer * renderer, Paddle * obj); bool KeyPressed(const Uint8 * keystate, Uint8 * keyArray); void INT_Constrain(int * variable, int min, int max); @@ -82,6 +84,7 @@ void PADDLE_DestroyObject(Paddle * obj); void PADDLE_Deinitialize(); void BLOCK_Initialize(SDL_Renderer * renderer); Block BLOCK_CreateDefault() ; +void BLOCK_DrawTexture(SDL_Renderer * renderer, SDL_Rect * dstRect, int index); void BLOCK_Draw(SDL_Renderer * renderer, Block * obj); void BLOCK_DealDamage(Block * obj, int dmg); void BLOCK_Update(Block * obj);