diff --git a/.gitignore b/.gitignore index 35f0e66..af4a962 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ sdl2-config *.o *.psd *.exe +*.json !bhi.exe .tags* *.txt diff --git a/bin/assets/images/ball.png b/bin/assets/images/ball.png index bcd3581..881b3c4 100644 Binary files a/bin/assets/images/ball.png and b/bin/assets/images/ball.png differ diff --git a/bin/assets/images/text.png b/bin/assets/images/text.png new file mode 100644 index 0000000..fe4044c Binary files /dev/null and b/bin/assets/images/text.png differ diff --git a/breakout.c b/breakout.c index c2f2fdb..176a683 100644 --- a/breakout.c +++ b/breakout.c @@ -12,20 +12,30 @@ extern float XScale, YScale; -#define BALL_TexturePath "assets/images/ball.png" -#define PADDLE_TexturePath "assets/images/paddle.png" -#define BLOCK_TexturePath "assets/images/spritesheet.png" +#define BALL_TexturePath "assets/images/ball.png" +#define PADDLE_TexturePath "assets/images/paddle.png" +#define BLOCK_TexturePath "assets/images/spritesheet.png" +#define BRAEKOUT_CountdownTexturePath "assets/images/text.png" +#define BALL_MinSpeed 8.0f +#define BALL_MaxSpeed 50.0f +#define BALL_AccelerationTime 18000 #ifndef __nullptr__ #define Nullptr(type) (type *)0 #endif // __nullptr__ +float PADDLE_SmoothFactor = 0.1f; 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; SDL_Texture * BLOCK_Texture; SDL_Rect * BALL_SourceRects; +SDL_Rect * GAME_CountdownSourceRects; SDL_Rect * PADDLE_SourceRects; SDL_Rect * BLOCK_SourceRects; Uint8 * PADDLE_MoveLeftKeys, * PADDLE_MoveRightKeys; @@ -43,6 +53,15 @@ void BREAKOUT_INITIALIZE(SDL_Renderer * renderer, int width, int height){ BALL_Initialize(renderer); PADDLE_Initialize(renderer); BLOCK_Initialize(renderer); + GAME_CountdownTexture = IMG_LoadTexture(renderer, BRAEKOUT_CountdownTexturePath); + if (!GAME_CountdownTexture) printf("Coutndown texture failed to load!\n"); + GAME_CountdownTextureCount = 4; + GAME_CountdownSourceRects = (SDL_Rect *)malloc(GAME_CountdownTextureCount * sizeof(SDL_Rect)); + if (!GAME_CountdownSourceRects) printf("FATAL! Memory allocation failed!\n"); + GAME_CountdownSourceRects[0] = (SDL_Rect) {.x = 1, .y = 668, .w = 1000, .h = 732 }; + GAME_CountdownSourceRects[1] = (SDL_Rect) {.x = 1, .y = 1, .w = 242, .h = 665 }; + GAME_CountdownSourceRects[2] = (SDL_Rect) {.x = 245, .y = 1, .w = 443, .h = 665 }; + GAME_CountdownSourceRects[3] = (SDL_Rect) {.x = 690, .y = 1, .w = 443, .h = 665 }; printf("Game initialized!\n"); BREAKOUT_IsInit = true; } else printf("Game is already initialized!\n"); @@ -57,6 +76,7 @@ Scenery BREAKOUT_CreateDefault(){ scenery.ball = BALL_CreateDefault(); scenery.paddle = PADDLE_CreateDefault(); scenery.blocks = malloc(scenery.BlockCount * sizeof(Block)); + scenery.Frames = 0; if (!(scenery.blocks)) printf("FATAL! Memory allocation failed!\n"); scenery.IsPaused = false; scenery.Lives = 3; @@ -87,11 +107,13 @@ void BREAKOUT_Update(Scenery * scenery, const Uint8 * keystate){ // Render "Countdown" return; } + (scenery->Frames)++; if (scenery->IsGameOver) { BALL_ResetPosition(&(scenery->ball)); PADDLE_ResetPosition(&(scenery->paddle)); scenery->StartCountdown = 240; scenery->IsGameOver = false; + scenery->Frames = 0; if (--(scenery->Lives) <= 0) printf("Game over, no lives left!\n"); else @@ -111,16 +133,27 @@ void BREAKOUT_Draw(Scenery * scenery, SDL_Renderer * renderer){ } BALL_Draw(renderer, &(scenery->ball)); PADDLE_Draw(renderer, &(scenery->paddle)); + 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); + printf("Texture From: %d, %d, %d, %d\n", rect->x, rect->y, rect->w, rect->h); + printf("Texture To: %d, %d, %d, %d\n", target.x, target.y, target.w, target.h); + SDL_RenderCopy(renderer, GAME_CountdownTexture, rect, &target); + } } void BREAKOUT_DEINITIALIZE(){ if (BREAKOUT_IsInit) { printf("De-initializing Game...\n"); + SDL_DestroyTexture(GAME_CountdownTexture); free(PADDLE_MoveLeftKeys); free(PADDLE_MoveRightKeys); free(BALL_SourceRects); free(PADDLE_SourceRects); free(BLOCK_SourceRects); + free(GAME_CountdownSourceRects); BALL_Deinitialize(); PADDLE_Deinitialize(); BLOCK_Deinitialize(); @@ -143,24 +176,33 @@ void BALL_Initialize(SDL_Renderer * renderer){ printf("Initializing Ball...\n"); 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)); + BALL_TextureCount = 9; + BALL_SourceRects = (SDL_Rect *)malloc(BALL_TextureCount * 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_SourceRects[0] = (SDL_Rect) {.x = 1029, .y = 1029, .w = 512, .h = 512 }; + BALL_SourceRects[1] = (SDL_Rect) {.x = 1, .y = 1, .w = 512, .h = 512 }; + BALL_SourceRects[2] = (SDL_Rect) {.x = 1, .y = 515, .w = 512, .h = 512 }; + BALL_SourceRects[3] = (SDL_Rect) {.x = 1, .y = 1029, .w = 512, .h = 512 }; + BALL_SourceRects[4] = (SDL_Rect) {.x = 515, .y = 1, .w = 512, .h = 512 }; + BALL_SourceRects[5] = (SDL_Rect) {.x = 1029, .y = 1, .w = 512, .h = 512 }; + BALL_SourceRects[6] = (SDL_Rect) {.x = 515, .y = 515, .w = 512, .h = 512 }; + BALL_SourceRects[7] = (SDL_Rect) {.x = 515, .y = 1029, .w = 512, .h = 512 }; + BALL_SourceRects[8] = (SDL_Rect) {.x = 1029, .y = 515, .w = 512, .h = 512 }; printf("Ball initialized!\n"); BALL_IsInit = true; } else printf("Ball is already initialized!\n"); -} +} /* BALL_Initialize */ Ball BALL_CreateDefault(){ double rotation = (double)(rand() % 360); return (Ball) { - .Location = (Vector) {.x = BREAKOUT_BoxWidth / 2 - 15, .y = BREAKOUT_BoxHeight - 130 }, + .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 }, .Size = 15.0f, .Rotation = rotation, - .RotationValue = 2, + .RotationValue = 5, .TextureIndex = 0, .Speed = 15.0f }; // Objekt für die Eigenschaften des Balls @@ -170,6 +212,7 @@ void BALL_ResetPosition(Ball * obj){ (obj->Location).x = BREAKOUT_BoxWidth / 2 - 15; (obj->Location).y = BREAKOUT_BoxHeight - 130; RECT_SetTargetPos(&(obj->TargetRect), &(obj->Location)); + (obj->Momentum) = VECTOR_GetScaledDirectionalUnitVector(0.0f, (obj->Speed)); } void BALL_Draw(SDL_Renderer * renderer, Ball * obj){ @@ -289,7 +332,16 @@ bool BALL_CollideWithPaddle(Ball * obj, Paddle * paddle){ return false; } /* BALL_CollideWithPaddle */ +void BALL_AdaptSpeedGradient(Ball * obj, int FrameCount){ + if (FrameCount > BALL_AccelerationTime) + obj->Speed = BALL_MaxSpeed; + else + obj->Speed = BALL_MinSpeed + (((double)FrameCount / (double)BALL_AccelerationTime) * (BALL_MaxSpeed - BALL_MinSpeed)); +} + void BALL_Update(Ball * obj, Scenery * scenery){ + BALL_AdaptSpeedGradient(obj, (scenery->Frames)); + (obj->Momentum) = VECTOR_ChangeScaleTo((obj->Momentum), (obj->Speed)); Block * blocks = (scenery->blocks); Paddle * paddle = &(scenery->paddle); int BlockCount = scenery->BlockCount; @@ -361,7 +413,7 @@ Paddle PADDLE_CreateDefault(){ .TextureIndex = 0, .Speed = 10, .SteeringAngle = 40.0f, - .Mode = KeyboardControl + .Mode = MouseControl }; // Objekt für die Eigenschaften des Balls } @@ -373,8 +425,6 @@ void PADDLE_ResetPosition(Paddle * obj){ 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)); } bool KeyPressed(const Uint8 * keystate, Uint8 * keyArray){ @@ -398,36 +448,36 @@ void DOUBLE_Constrain(double * variable, double min, double max){ *variable = min; } +void PADDLE_MoveSmooth(Paddle * obj){ + int mouseX, paddleXMid, halfPaddle = ((obj->TargetRect).w / 2); + + SDL_GetMouseState(&mouseX, NULL); + mouseX = (int)roundf((float)mouseX / XScale); + paddleXMid = halfPaddle + (obj->TargetRect.x); // Current State + (obj->TargetRect).x = paddleXMid - (int)roundf((float)(paddleXMid - mouseX) * PADDLE_SmoothFactor) - halfPaddle; +} + void PADDLE_Update(Paddle * obj, const Uint8 * keystate){ - bool leftKeyPressed = false, rightKeyPressed = false; - int paddleXMid = (obj->TargetRect).x + ((obj->TargetRect).w / 2); - int mouseX; + bool leftKeyPressed, rightKeyPressed; switch (obj->Mode) { case MouseControl: - SDL_GetMouseState(&mouseX, NULL); - mouseX = (int)roundf((float)mouseX / XScale); - if (abs(mouseX - paddleXMid) > (obj->Speed)) { - if (mouseX > paddleXMid) - rightKeyPressed = true; - else - leftKeyPressed = true; - } + PADDLE_MoveSmooth(obj); break; case KeyboardControl: leftKeyPressed = KeyPressed(keystate, PADDLE_MoveLeftKeys); rightKeyPressed = KeyPressed(keystate, PADDLE_MoveRightKeys); + + if (leftKeyPressed && (!rightKeyPressed)) { + ((obj->TargetRect).x) -= (obj->Speed); + } else if ((!leftKeyPressed) && rightKeyPressed) { + ((obj->TargetRect).x) += (obj->Speed); + } break; default: printf("Unknown Paddle Control Mode: %d!\n", obj->Mode); break; - } - - if (leftKeyPressed && (!rightKeyPressed)) { - ((obj->TargetRect).x) -= (obj->Speed); - } else if ((!leftKeyPressed) && rightKeyPressed) { - ((obj->TargetRect).x) += (obj->Speed); - } + } /* switch */ INT_Constrain(&((obj->TargetRect).x), 0, (BREAKOUT_BoxWidth - ((obj->TargetRect).w))); } /* PADDLE_Update */ diff --git a/breakout.h b/breakout.h index 90cd196..786393b 100644 --- a/breakout.h +++ b/breakout.h @@ -41,6 +41,7 @@ typedef struct sceneryStruct { Block * blocks; int BlockCount, Lives, StartCountdown; bool IsPaused, IsGameOver; + int Frames; } Scenery; // Objekt für die Objekte und Eigenschaften einer Szenerie // End Structs