diff --git a/.gitignore b/.gitignore index 35f0e66..6800e30 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,8 @@ sdl2-config *.o *.psd *.exe +*.json +*.cfg !bhi.exe .tags* *.txt diff --git a/Makefile b/Makefile index 10e8671..f55f77a 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ -libs = -lmingw32 -lSDL2main -lSDL2 -lopengl32 -lSDL2_image -lSDL2_ttf +libs = -lmingw32 -lSDL2main -lSDL2 -lopengl32 -lSDL2_image -lSDL2_ttf -lSDL2_mixer includes = -I".\include" compiler = gcc -warningLevel = -Wall -Wno-unused-variable -Wno-unused-but-set-variable +warningLevel = -Wall -Wno-parentheses sources = *.c linker = -L".\lib" dir = bin diff --git a/background.c b/background.c new file mode 100644 index 0000000..e56a996 --- /dev/null +++ b/background.c @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "breakout.h" +#include "vector.h" +#include "background.h" + +#define BG_Path_1 "assets/images/bg/bg1.png" + +int BACKGROUND_BoxWidth, BACKGROUND_BoxHeight; +int BACKGROUND_TextureCount; +SDL_Texture ** BACKGROUND_Textures; +bool BACKGROUND_IsInit = false; +SDL_Rect BACKGROUND_TotalRect; + +void BACKGROUND_Initialize(SDL_Renderer * renderer, int width, int height){ + if (!BACKGROUND_IsInit) { + printf("Initializing Background...\n"); + BACKGROUND_BoxWidth = width; + BACKGROUND_BoxHeight = height; + BACKGROUND_TextureCount = 1; + BACKGROUND_TotalRect = (SDL_Rect) {.x = 0, .y = 0, .w = 1920, .h = 1080 }; + BACKGROUND_Textures = malloc(BACKGROUND_TextureCount * sizeof(SDL_Texture *)); + BACKGROUND_Textures[0] = IMG_LoadTexture(renderer, BG_Path_1); + printf("Background initialized!\n"); + BACKGROUND_IsInit = true; + } else + printf("Background already initialized!\n"); +} + +void BACKGROUND_Draw(SDL_Renderer * renderer, int index){ + if (index < 0 || index >= BACKGROUND_TextureCount) { + printf("Bad Background Texture index: %d by max: %d\n", index, BACKGROUND_TextureCount); + return; + } + SDL_RenderCopy(renderer, BACKGROUND_Textures[index], &BACKGROUND_TotalRect, &BACKGROUND_TotalRect); +} + +void BACKGROUND_Deinitialize(){ + if (BACKGROUND_IsInit) { + printf("De-initializing Background...\n"); + for (int i = 0; i < BACKGROUND_TextureCount; i++) { + SDL_DestroyTexture(BACKGROUND_Textures[0]); + } + free(BACKGROUND_Textures); + printf("Background de-initialized!\n"); + BACKGROUND_IsInit = false; + } else + printf("Background already de-initialized!\n"); +} diff --git a/background.h b/background.h new file mode 100644 index 0000000..32e739c --- /dev/null +++ b/background.h @@ -0,0 +1,22 @@ +#ifndef __background_h__ +#define __background_h__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "breakout.h" +#include "vector.h" + +// Prototypes +void BACKGROUND_Initialize(SDL_Renderer * renderer, int width, int height); +void BACKGROUND_Draw(SDL_Renderer * renderer, int index); +void BACKGROUND_Deinitialize(); +// End Prototypes + +#endif diff --git a/bin/SDL2_mixer.dll b/bin/SDL2_mixer.dll new file mode 100644 index 0000000..54ebbb1 Binary files /dev/null and b/bin/SDL2_mixer.dll differ diff --git a/bin/assets/images/Unbenannt.png b/bin/assets/images/Unbenannt.png new file mode 100644 index 0000000..a5aa3e8 Binary files /dev/null and b/bin/assets/images/Unbenannt.png differ 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/bar_texture.png b/bin/assets/images/bar_texture.png new file mode 100644 index 0000000..bde1483 Binary files /dev/null and b/bin/assets/images/bar_texture.png differ diff --git a/bin/assets/images/bg/bg1.png b/bin/assets/images/bg/bg1.png new file mode 100644 index 0000000..32c489c Binary files /dev/null and b/bin/assets/images/bg/bg1.png differ diff --git a/bin/assets/images/gameover.png b/bin/assets/images/gameover.png new file mode 100644 index 0000000..6cf7930 Binary files /dev/null and b/bin/assets/images/gameover.png differ diff --git a/bin/assets/images/l_arrow_button.png b/bin/assets/images/l_arrow_button.png new file mode 100644 index 0000000..274d37f Binary files /dev/null and b/bin/assets/images/l_arrow_button.png differ diff --git a/bin/assets/images/numbers.png b/bin/assets/images/numbers.png new file mode 100644 index 0000000..339f96d Binary files /dev/null and b/bin/assets/images/numbers.png differ diff --git a/bin/assets/images/paused.png b/bin/assets/images/paused.png new file mode 100644 index 0000000..cf1ad4a Binary files /dev/null and b/bin/assets/images/paused.png differ diff --git a/bin/assets/images/r_arrow_button.png b/bin/assets/images/r_arrow_button.png new file mode 100644 index 0000000..75fc981 Binary files /dev/null and b/bin/assets/images/r_arrow_button.png differ diff --git a/bin/assets/images/return_button.png b/bin/assets/images/return_button.png new file mode 100644 index 0000000..ecb8e77 Binary files /dev/null and b/bin/assets/images/return_button.png differ diff --git a/bin/assets/images/scalar_button_pressed.png b/bin/assets/images/scalar_button_pressed.png new file mode 100644 index 0000000..4851397 Binary files /dev/null and b/bin/assets/images/scalar_button_pressed.png differ diff --git a/bin/assets/images/scalar_button_unpressed.png b/bin/assets/images/scalar_button_unpressed.png new file mode 100644 index 0000000..5d47601 Binary files /dev/null and b/bin/assets/images/scalar_button_unpressed.png differ diff --git a/bin/assets/images/skins_button.png b/bin/assets/images/skins_button.png index 02cb30f..5ec1873 100644 Binary files a/bin/assets/images/skins_button.png and b/bin/assets/images/skins_button.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/bin/assets/images/upload.png b/bin/assets/images/upload.png new file mode 100644 index 0000000..5b64d5c Binary files /dev/null and b/bin/assets/images/upload.png differ diff --git a/bin/assets/images/yourscore.png b/bin/assets/images/yourscore.png new file mode 100644 index 0000000..cc21024 Binary files /dev/null and b/bin/assets/images/yourscore.png differ diff --git a/bin/assets/sounds/death.wav b/bin/assets/sounds/death.wav new file mode 100644 index 0000000..2d16917 Binary files /dev/null and b/bin/assets/sounds/death.wav differ diff --git a/bin/assets/sounds/hit1.wav b/bin/assets/sounds/hit1.wav new file mode 100644 index 0000000..605e2e9 Binary files /dev/null and b/bin/assets/sounds/hit1.wav differ diff --git a/bin/assets/sounds/hit2.wav b/bin/assets/sounds/hit2.wav new file mode 100644 index 0000000..2ec93cf Binary files /dev/null and b/bin/assets/sounds/hit2.wav differ diff --git a/bin/assets/sounds/hit3.wav b/bin/assets/sounds/hit3.wav new file mode 100644 index 0000000..501308e Binary files /dev/null and b/bin/assets/sounds/hit3.wav differ diff --git a/bin/assets/sounds/hit4.wav b/bin/assets/sounds/hit4.wav new file mode 100644 index 0000000..408de69 Binary files /dev/null and b/bin/assets/sounds/hit4.wav differ diff --git a/bin/assets/sounds/hit5.wav b/bin/assets/sounds/hit5.wav new file mode 100644 index 0000000..69eb66c Binary files /dev/null and b/bin/assets/sounds/hit5.wav differ diff --git a/bin/assets/sounds/ingame_music.wav b/bin/assets/sounds/ingame_music.wav new file mode 100644 index 0000000..916f273 Binary files /dev/null and b/bin/assets/sounds/ingame_music.wav differ diff --git a/bin/assets/sounds/menu_music.wav b/bin/assets/sounds/menu_music.wav new file mode 100644 index 0000000..a86a897 Binary files /dev/null and b/bin/assets/sounds/menu_music.wav differ diff --git a/bin/bhi.exe b/bin/bhi.exe index b49a627..c53fca8 100644 Binary files a/bin/bhi.exe and b/bin/bhi.exe differ diff --git a/bin/libFLAC-8.dll b/bin/libFLAC-8.dll new file mode 100644 index 0000000..1c55ad4 Binary files /dev/null and b/bin/libFLAC-8.dll differ diff --git a/bin/libmodplug-1.dll b/bin/libmodplug-1.dll new file mode 100644 index 0000000..a2cba0d Binary files /dev/null and b/bin/libmodplug-1.dll differ diff --git a/bin/libmpg123-0.dll b/bin/libmpg123-0.dll new file mode 100644 index 0000000..ca7de30 Binary files /dev/null and b/bin/libmpg123-0.dll differ diff --git a/bin/libogg-0.dll b/bin/libogg-0.dll new file mode 100644 index 0000000..3abe6eb Binary files /dev/null and b/bin/libogg-0.dll differ diff --git a/bin/libvorbis-0.dll b/bin/libvorbis-0.dll new file mode 100644 index 0000000..4e44ef0 Binary files /dev/null and b/bin/libvorbis-0.dll differ diff --git a/bin/libvorbisfile-3.dll b/bin/libvorbisfile-3.dll new file mode 100644 index 0000000..e757eb6 Binary files /dev/null and b/bin/libvorbisfile-3.dll differ diff --git a/breakout.c b/breakout.c index bb43112..61d9acb 100644 --- a/breakout.c +++ b/breakout.c @@ -1,29 +1,62 @@ #include #include -#include #include #include +#include #include #include -#include +#include #include "breakout.h" #include "vector.h" +#include "gamestate.h" +#include "gameover.h" +#include "main.h" -#define BALL_TexturePath "assets/images/ball.png" -#define PADDLE_TexturePath "assets/images/paddle.png" -#define BLOCK_TexturePath "assets/images/spritesheet.png" +extern float XScale, YScale; +extern int width, height; + +#define BALL_TexturePath "assets/images/ball.png" +#define PADDLE_TexturePath "assets/images/paddle.png" +#define BLOCK_TexturePath "assets/images/spritesheet.png" +#define BREAKOUT_CountdownTexturePath "assets/images/text.png" +#define BREAKOUT_PausedTexturePath "assets/images/paused.png" +#define BREAKOUT_IngameSoundPath "assets/sounds/ingame_music.wav" +#define BREAKOUT_DeathSoundPath "assets/sounds/death.wav" +#define BREAKOUT_HitSoundPath1 "assets/sounds/hit1.wav" +#define BREAKOUT_HitSoundPath2 "assets/sounds/hit2.wav" +#define BREAKOUT_HitSoundPath3 "assets/sounds/hit3.wav" +#define BREAKOUT_HitSoundPath4 "assets/sounds/hit4.wav" +#define BREAKOUT_HitSoundPath5 "assets/sounds/hit5.wav" +#define BALL_MinSpeed 8.0f +#define BALL_MaxSpeed 25.0f +#define BALL_AccelerationTime 10000 +#define PADDLE_MaxSize 300 +#define PADDLE_MinSize 50 +#define PADDLE_AccelerationTime 18000 +#define BREAKOUT_LiveHUDSize 35 +#define BREAKOUT_LiveHUDMargin 8 +#define BREAKOUT_PushIntervale 1800 +#define BREAKOUT_FadeTime 1000 #ifndef __nullptr__ #define Nullptr(type) (type *)0 #endif // __nullptr__ +float PADDLE_SmoothFactor = 0.1f; +float BLOCK_SmoothFactor = 0.05f; +float BREAKOUT_LifePenalty = 0.75f; int BLOCK_TextureCount = 24; -int BREAKOUT_BoxWidth, BREAKOUT_BoxHeight; +int BALL_TextureCount = 9; +int BREAKOUT_CountdownTextureCount = 4; +int PADDLE_TextureCount = 9; SDL_Texture * BALL_Texture; +SDL_Texture * BREAKOUT_CountdownTexture; SDL_Texture * PADDLE_Texture; SDL_Texture * BLOCK_Texture; +SDL_Texture * BREAKOUT_PausedTexture; SDL_Rect * BALL_SourceRects; +SDL_Rect * BREAKOUT_CountdownSourceRects; SDL_Rect * PADDLE_SourceRects; SDL_Rect * BLOCK_SourceRects; Uint8 * PADDLE_MoveLeftKeys, * PADDLE_MoveRightKeys; @@ -31,57 +64,175 @@ bool BREAKOUT_IsInit = false; bool BALL_IsInit = false; bool PADDLE_IsInit = false; bool BLOCK_IsInit = false; +Mix_Chunk * BREAKOUT_DeathSound; +Mix_Chunk ** BREAKOUT_HitSound; +Mix_Music * BREAKOUT_IngameMusic; -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); + BREAKOUT_CountdownTexture = IMG_LoadTexture(renderer, BREAKOUT_CountdownTexturePath); + if (!BREAKOUT_CountdownTexture) printf("Countdown texture failed to load!\n"); + BREAKOUT_PausedTexture = IMG_LoadTexture(renderer, BREAKOUT_PausedTexturePath); + if (!BREAKOUT_PausedTexture) printf("Paused texture failed to load!\n"); + BREAKOUT_CountdownTextureCount = 4; + BREAKOUT_CountdownSourceRects = (SDL_Rect *)malloc(BREAKOUT_CountdownTextureCount * sizeof(SDL_Rect)); + if (!BREAKOUT_CountdownSourceRects) printf("FATAL! Memory allocation failed!\n"); + BREAKOUT_CountdownSourceRects[0] = (SDL_Rect) {.x = 1, .y = 668, .w = 1000, .h = 732 }; + BREAKOUT_CountdownSourceRects[1] = (SDL_Rect) {.x = 1, .y = 1, .w = 242, .h = 665 }; + BREAKOUT_CountdownSourceRects[2] = (SDL_Rect) {.x = 245, .y = 1, .w = 443, .h = 665 }; + BREAKOUT_CountdownSourceRects[3] = (SDL_Rect) {.x = 690, .y = 1, .w = 443, .h = 665 }; + BREAKOUT_HitSound = malloc(5 * sizeof(Mix_Chunk *)); + BREAKOUT_HitSound[0] = Mix_LoadWAV(BREAKOUT_HitSoundPath1); + BREAKOUT_HitSound[1] = Mix_LoadWAV(BREAKOUT_HitSoundPath2); + BREAKOUT_HitSound[2] = Mix_LoadWAV(BREAKOUT_HitSoundPath3); + BREAKOUT_HitSound[3] = Mix_LoadWAV(BREAKOUT_HitSoundPath4); + BREAKOUT_HitSound[4] = Mix_LoadWAV(BREAKOUT_HitSoundPath5); + BREAKOUT_DeathSound = Mix_LoadWAV(BREAKOUT_DeathSoundPath); + BREAKOUT_IngameMusic = Mix_LoadMUS(BREAKOUT_IngameSoundPath); printf("Game initialized!\n"); BREAKOUT_IsInit = true; } else printf("Game is already initialized!\n"); } /* BREAKOUT_INITIALIZE */ +void BREAKOUT_StartMusic(){ + printf("Attempting to start game music...\n"); + if (!Mix_PlayingMusic()) + Mix_FadeInMusic(BREAKOUT_IngameMusic, -1, BREAKOUT_FadeTime); + else printf("Game music is already playing!\n"); +} + +void BREAKOUT_PauseMusic(){ + printf("Attempting to pause game music...\n"); + if (Mix_PlayingMusic()) + Mix_HaltMusic(); + // Mix_FadeOutMusic(BREAKOUT_FadeTime); + else printf("There is no game music to be paused!\n"); +} + +// Toggle Game pause, not the music! +void BREAKOUT_TogglePause(Scenery * scenery){ + (scenery->IsPaused) = !(scenery->IsPaused); + printf("Game was %s!\n", ( (scenery->IsPaused) ? "paused" : "unpaused")); +} + +void BREAKOUT_KeyPressed(Scenery * scenery, SDL_KeyboardEvent * b){ + if ((b->keysym).scancode == SDL_SCANCODE_ESCAPE) { + printf("Escape was pressed ingame! Toggle Pause...\n"); + BREAKOUT_TogglePause(scenery); + } +} + Scenery BREAKOUT_CreateDefault(){ Scenery scenery; - scenery.BlockCount = 60; + scenery.StartCountdown = 240; + scenery.TopLeftBlockColor = 0; + scenery.IsGameOver = false; + scenery.BlockCount = 135; scenery.ball = BALL_CreateDefault(); scenery.paddle = PADDLE_CreateDefault(); scenery.blocks = malloc(scenery.BlockCount * sizeof(Block)); + scenery.Frames = 0; + scenery.YBlocks = 9; + scenery.XBlocks = 15; + scenery.Score = 0; + if (!(scenery.blocks)) printf("FATAL! Memory allocation failed!\n"); + scenery.IsPaused = false; + scenery.Lives = 3; + scenery.DestroyedBlocks = 0; int index; - for (int y = 0; y < 6; y++) { - index = 10 * y; - for (int x = 0; x < 10; x++) { + for (int y = 0; y < scenery.YBlocks; y++) { + index = (scenery.XBlocks) * y; + for (int x = 0; x < scenery.XBlocks; 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"); + scenery.blocks[x + index].TargetRect = (SDL_Rect) {.x = ((128 * x) + 2), .y = ((64 * y) + 1), .w = 124, .h = 62 }; + scenery.blocks[x + index].TextureIndex = y + x; + scenery.blocks[x + index].DestYValue = ((64 * y) + 1); } } 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_IncreaseScoreBy(Scenery * scenery, int scoreInc){ + (scenery->Score) += scoreInc; } +void TEXTURE_RenderCenteredSpriteSheet(SDL_Renderer * renderer, SDL_Texture * texture, SDL_Rect * srcRect, float Scale){ + SDL_Rect target; + + target.w = (int)roundf(((float)(srcRect->w)) * Scale); + target.h = (int)roundf(((float)(srcRect->h)) * Scale); + target.x = ((width - (target.w)) / 2); + target.y = ((height - (target.h)) / 2); + SDL_RenderCopy(renderer, texture, srcRect, &target); +} + +void TEXTURE_RenderCentered(SDL_Renderer * renderer, SDL_Texture * texture, float Scale){ + int w, h; + SDL_Rect target; + + SDL_QueryTexture(texture, NULL, NULL, &w, &h); + target.w = (int)roundf(((float)w) * Scale); + target.h = (int)roundf(((float)h) * Scale); + target.x = ((width - (target.w)) / 2); + target.y = ((height - (target.h)) / 2); + SDL_RenderCopy(renderer, texture, NULL, &target); +} + +void BREAKOUT_PushNewRow(Scenery * scenery){ + printf("Pushing new line...\n"); + (scenery->TopLeftBlockColor)--; + // Rotate through textures + if ((scenery->TopLeftBlockColor) < 0) (scenery->TopLeftBlockColor) = (BLOCK_TextureCount - 1); + else if ((scenery->TopLeftBlockColor) >= 24) (scenery->TopLeftBlockColor) = 0; + int oldBlockCount = (scenery->BlockCount); + (scenery->BlockCount) += (scenery->XBlocks); + (scenery->YBlocks)++; + scenery->blocks = realloc((scenery->blocks), (scenery->BlockCount) * sizeof(Block)); + for (size_t i = 0; i < oldBlockCount; i++) { + (scenery->blocks)[i].DestYValue += 64; + } + for (size_t x = 0; x < (scenery->XBlocks); x++) { + (scenery->blocks)[x + oldBlockCount] = BLOCK_CreateDefault(); + (scenery->blocks)[x + oldBlockCount].TargetRect = (SDL_Rect) {.x = ((128 * x) + 2), .y = -63, .w = 124, .h = 62 }; + (scenery->blocks)[x + oldBlockCount].TextureIndex = (((scenery->TopLeftBlockColor) + x) % BLOCK_TextureCount); + (scenery->blocks)[x + oldBlockCount].DestYValue = 1; + } + printf("New line was pushed!\n"); +} /* BREAKOUT_PushNewRow */ + 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)); + if (scenery->IsPaused) return; + if ((scenery->StartCountdown)-- > 0) return; + (scenery->Frames)++; + if (scenery->IsGameOver) { + BALL_ResetPosition(&(scenery->ball)); + PADDLE_ResetPosition(&(scenery->paddle)); + scenery->StartCountdown = 240; + scenery->IsGameOver = false; + if (--(scenery->Lives) <= 0) + GAME_ChangeState(GameOver); + else { + // Reduce score when there is a life left + // scenery->Score = (int)roundf((float)(scenery->Score) * BREAKOUT_LifePenalty); + printf("Oh oh, only %d lives left!\n", scenery->Lives); + } + return; + } + if ((scenery->Frames) % BREAKOUT_PushIntervale == 0) { + BREAKOUT_PushNewRow(scenery); + } + PADDLE_Update(&(scenery->paddle), scenery, keystate); // Update paddle before ball because paddle is not static! for (int i = 0; i < (scenery->BlockCount); i++) { BLOCK_Update((scenery->blocks) + i); } -} + BALL_Update(&(scenery->ball), scenery); +} /* BREAKOUT_Update */ void BREAKOUT_Draw(Scenery * scenery, SDL_Renderer * renderer){ for (int i = 0; i < (scenery->BlockCount); i++) { @@ -89,23 +240,53 @@ void BREAKOUT_Draw(Scenery * scenery, SDL_Renderer * renderer){ } BALL_Draw(renderer, &(scenery->ball)); PADDLE_Draw(renderer, &(scenery->paddle)); + SCORE_DrawHUD(renderer, scenery); + BREAKOUT_DrawLivesHUD(renderer, scenery); + if (scenery->IsPaused) { + TEXTURE_RenderCentered(renderer, BREAKOUT_PausedTexture, 0.5f); + } else if ((scenery->StartCountdown) > 0) { // ! Render Z-Layer ! + TEXTURE_RenderCenteredSpriteSheet(renderer, BREAKOUT_CountdownTexture, (BREAKOUT_CountdownSourceRects + (((scenery->StartCountdown) - 1) / 60)), 1.0f); + } +} + +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(){ if (BREAKOUT_IsInit) { printf("De-initializing Game...\n"); + for (int i = 0; i < 5; i++) { + Mix_FreeChunk(BREAKOUT_HitSound[i]); + } + free(BREAKOUT_HitSound); + Mix_FreeChunk(BREAKOUT_DeathSound); + Mix_FreeMusic(BREAKOUT_IngameMusic); + SDL_DestroyTexture(BREAKOUT_CountdownTexture); + SDL_DestroyTexture(BREAKOUT_PausedTexture); free(PADDLE_MoveLeftKeys); free(PADDLE_MoveRightKeys); free(BALL_SourceRects); free(PADDLE_SourceRects); free(BLOCK_SourceRects); + free(BREAKOUT_CountdownSourceRects); BALL_Deinitialize(); PADDLE_Deinitialize(); BLOCK_Deinitialize(); printf("Game de-initialized!\n"); BREAKOUT_IsInit = false; } else printf("Game is already de-initialized!\n"); -} +} /* BREAKOUT_DEINITIALIZE */ void BREAKOUT_DestroyObject(Scenery * scenery){ for (size_t i = 0; i < (scenery->BlockCount); i++) { @@ -121,83 +302,104 @@ 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 + 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, + .Location = (Vector) {.x = (width / 2) - 15, .y = height - 131 }, + .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 = 0, + .RotationValue = 9, .TextureIndex = 0, .Speed = 15.0f }; // Objekt für die Eigenschaften des Balls } +void BALL_ResetPosition(Ball * obj){ + (obj->Location).x = width / 2 - (obj->Size); + (obj->Location).y = height - 101 - (2 * (obj->Size)); + 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); } bool BALL_CollideWithRect(Ball * obj, SDL_Rect * rect){ - SDL_Point ballCenter = BALL_GetCenter(obj); - - 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; + if (!RECT_Collide(&(obj->TargetRect), rect)) return false; // Already returned with false if square ball hitbox didnt collide with rect - Vector center = (Vector) {.x = ballCenter.x, .y = ballCenter.y }; + Vector unitMomentum = VECTOR_ChangeScaleTo((obj->Momentum), 1.0f); + Vector center = BALL_GetCenter(obj); 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; + left = (center.x) < (rect->x); + right = (center.x) > (rect->x) + (rect->w); + top = (center.y) < (rect->y); + bottom = (center.y) > (rect->y) + (rect->h); yMid = !(top || bottom); xMid = !(left || right); - if (yMid) + // Move away from hitbox from where you came from when stuck in the middle of the block at high speeds + while (yMid && xMid) { + (obj->Location) = VECTOR_Subtract((obj->Location), unitMomentum); + center = BALL_GetCenter(obj); + left = (center.x) < (rect->x); + right = (center.x) > (rect->x) + (rect->w); + top = (center.y) < (rect->y); + bottom = (center.y) > (rect->y) + (rect->h); + yMid = !(top || bottom); + xMid = !(left || right); + } + if (yMid) // Hit left or right (obj->Momentum).x = -(obj->Momentum).x; - if (xMid) + if (xMid) // Hit bottom or top (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)); - // */ - // } + if (xMid || yMid) return true; + // double oldAngle = fmod((double)(VECTOR_GetRotation(obj->Momentum)), 360.0f); + + if (left) { + corner.x = (rect->x); + } else if (right) { + corner.x = ((rect->x) + (rect->w)); + } // Other case will not appear since returned above + if (top) { + corner.y = (rect->y); + } else if (bottom) { + corner.y = ((rect->y) + (rect->h)); + } + Vector cornerToMid = VECTOR_GetVectorFromTo(corner, center); + if (VECTOR_GetMagnitude(cornerToMid) > (obj->Size)) return false; + double lot = VECTOR_GetRotation(cornerToMid); + double inRotation = fmod(VECTOR_GetRotation(obj->Momentum) + 180.0f, 360.0f); + double outAngle = fmod(lot + (0.5 * (lot - inRotation)), 360.0f); + printf("In: %.2f | Lot: %.2f | Out: %.2f\n", inRotation, lot, outAngle); + (obj->Momentum) = VECTOR_GetScaledDirectionalUnitVector(outAngle, (obj->Speed)); return true; } /* BALL_CollideWithRect */ @@ -224,7 +426,7 @@ void BALL_SteerMomentum(Ball * obj, Paddle * paddle){ offset /= paddleHalfLen; offset *= (paddle->SteeringAngle); DOUBLE_Constrain(&offset, -(paddle->SteeringAngle), (paddle->SteeringAngle)); - (obj->Momentum) = getDirectionalUnitVector(offset); + (obj->Momentum) = VECTOR_GetDirectionalUnitVector(offset); } void RECT_SetTargetPos(SDL_Rect * rect, Vector * Location){ @@ -232,46 +434,95 @@ void RECT_SetTargetPos(SDL_Rect * rect, Vector * Location){ rect->y = (int)round(Location->y); } -SDL_Point BALL_GetCenter(Ball * obj){ - return (SDL_Point) {.x = ((obj->TargetRect).x) + (obj->Size), .y = ((obj->TargetRect).y) + (obj->Size) }; +Vector BALL_GetCenter(Ball * obj){ + return (Vector) {.x = ((obj->Location).x) + (obj->Size), .y = ((obj->Location).y) + (obj->Size) }; } -void BALL_Update(Ball * obj, Paddle * paddle, Block * blocks, int BlockCount){ +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 > width - (2 * (obj->Size))) + (obj->Momentum).x = -(obj->Momentum).x; +} + +void BALL_MoveAwayFromBoundaries(Ball * obj){ + while (((obj->Location).y) < 0) + ((obj->Location).y)++; + while (((obj->Location).x) < 0) + ((obj->Location).x)++; + while ((((obj->Location).x) + ((obj->Size) * 2)) > width) + ((obj->Location).x)--; +} + +bool BALL_CollideWithPaddle(Ball * obj, Paddle * paddle){ + if (RECT_Collide(&(obj->TargetRect), &(paddle->TargetRect))) { + Vector ballCenter = BALL_GetCenter(obj); + if (ballCenter.y > (paddle->TargetRect).y) // if the ball hits the paddle from the sides (or the bottom (?)) + 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 + 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); + RECT_SetTargetPos(&(obj->TargetRect), &(obj->Location)); + } + (obj->Momentum) = VECTOR_ChangeScaleTo((obj->Momentum), (obj->Speed)); + BALL_PlayCollisionSound(); + return true; + } + 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_PlayCollisionSound(){ + int sound; + + Mix_PlayChannel(-1, BREAKOUT_HitSound[(sound = (rand() % 5))], 0); + printf("Collision sound %d played...\n", sound); +} + +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; 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); + (obj->Location) = VECTOR_Add((obj->Location), oldMomentum); + RECT_SetTargetPos(&(obj->TargetRect), &(obj->Location)); - 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)); + if (!BALL_CollideWithPaddle(obj, paddle)) // Collide with Paddle + for (int i = 0; i < BlockCount; i++) { // Check Collide with each block + if (blocks[i].HP <= 0) continue; + oldMomentum = obj->Momentum; + oldLocation = obj->Location; + if (BALL_CollideWithRect(obj, &(blocks[i].TargetRect))) { + BALL_PlayCollisionSound(); + BLOCK_DealDamage(blocks + i, 1); + 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)); + } } - (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) // 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; + if ((obj->Location).y > height) { // Collide with box boundaries + Mix_PlayChannel(-1, BREAKOUT_DeathSound, 0); + scenery->IsGameOver = true; + printf("Ball called game_over!\n"); + } else BALL_CollideWithBorders(obj); RECT_SetTargetPos(&(obj->TargetRect), &(obj->Location)); } /* BALL_Update */ @@ -311,22 +562,31 @@ void PADDLE_Initialize(SDL_Renderer * renderer){ } /* PADDLE_Initialize */ 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 - PADDLE_MaxSize) / 2, .y = height - 100, .w = PADDLE_MaxSize, .h = 30 }, .TextureIndex = 0, .Speed = 10, .SteeringAngle = 40.0f, - .Mode = KeyboardControl + .Mode = MouseControl }; // Objekt für die Eigenschaften des Balls } +void PADDLE_ResetPosition(Paddle * obj){ + (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){ // 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){ @@ -350,36 +610,54 @@ void DOUBLE_Constrain(double * variable, double min, double max){ *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; +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_MoveAuto(Scenery * scenery){ + int paddleXMid, halfPaddle = (((scenery->paddle).TargetRect).w / 2); + + paddleXMid = halfPaddle + ((scenery->paddle).TargetRect.x); // Current State + ((scenery->paddle).TargetRect).x = paddleXMid - (int)roundf((float)(paddleXMid - (((scenery->ball).Location).x + (rand() % 30) + ((scenery->ball).Size))) * 0.2f) - halfPaddle; +} + +void PADDLE_AdaptSpeedGradient(Paddle * obj, int FrameCount){ + if (FrameCount > PADDLE_AccelerationTime) + return; + (obj->TargetRect).w = PADDLE_MaxSize - (((double)FrameCount / (double)PADDLE_AccelerationTime) * (PADDLE_MaxSize - PADDLE_MinSize)); +} + +void PADDLE_Update(Paddle * obj, Scenery * scenery, const Uint8 * keystate){ + PADDLE_AdaptSpeedGradient(obj, (scenery->Frames)); + bool leftKeyPressed, rightKeyPressed; switch (obj->Mode) { case MouseControl: - SDL_GetMouseState(&mouseX, NULL); - 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; + case Automatic: + PADDLE_MoveAuto(scenery); 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); - } - INT_Constrain(&((obj->TargetRect).x), 0, (BREAKOUT_BoxWidth - ((obj->TargetRect).w))); + } /* switch */ + INT_Constrain(&((obj->TargetRect).x), 0, (width - ((obj->TargetRect).w))); } /* PADDLE_Update */ void PADDLE_DestroyObject(Paddle * obj){ @@ -430,14 +708,23 @@ void BLOCK_Initialize(SDL_Renderer * renderer){ } else printf("Block is already initialized!\n"); } /* PADDLE_Initialize */ -Block BLOCK_CreateDefault() { +Block BLOCK_CreateDefault(){ return (Block) { .TargetRect = (SDL_Rect) {.x = 0, .y = 0, .w = 100, .h = 50 }, .TextureIndex = (rand() % BLOCK_TextureCount), - .HP = 1 + .HP = 1, + .DestYValue = 0 }; // 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); @@ -449,8 +736,12 @@ void BLOCK_DealDamage(Block * obj, int dmg){ if (((obj->HP) -= dmg) <= 0) printf("Block was destroyed!\n"); } +void BLOCK_MoveSmooth(Block * obj){ + ((obj->TargetRect).y) -= (int)roundf((float)(((obj->TargetRect).y) - (obj->DestYValue)) * BLOCK_SmoothFactor); +} + void BLOCK_Update(Block * obj){ -// Do nothing currently + BLOCK_MoveSmooth(obj); } void BLOCK_DestroyObject(Block * obj){ } diff --git a/breakout.h b/breakout.h index 8a638d9..bcbf566 100644 --- a/breakout.h +++ b/breakout.h @@ -6,11 +6,13 @@ #include #include #include +#include +#include #include "vector.h" // Enums -typedef enum controlModeEnum {KeyboardControl = 0, MouseControl = 1} ControlMode; +typedef enum controlModeEnum {KeyboardControl = 0, MouseControl = 1, Automatic = 2} ControlMode; // End Enums // Structs @@ -32,49 +34,72 @@ typedef struct paddleStruct { typedef struct blockStruct { SDL_Rect TargetRect; - int TextureIndex, HP; + int TextureIndex, HP, DestYValue; } Block; // Objekt für die Eigenschaften des Paddles typedef struct sceneryStruct { Ball ball; Paddle paddle; Block * blocks; - int BlockCount; // Move to scenery + int BlockCount, Lives, StartCountdown, Frames, Score, DestroyedBlocks, TopLeftBlockColor, XBlocks, YBlocks; + bool IsPaused, IsGameOver; } Scenery; // Objekt für die Objekte und Eigenschaften einer Szenerie // End Structs // Prototypes -void BREAKOUT_INITIALIZE(SDL_Renderer * renderer, int width, int height); +void BREAKOUT_INITIALIZE(SDL_Renderer * renderer); +void BREAKOUT_StartMusic(); +void BREAKOUT_PauseMusic(); +void BREAKOUT_TogglePause(Scenery * scenery); +void BREAKOUT_KeyPressed(Scenery * scenery, SDL_KeyboardEvent * b); Scenery BREAKOUT_CreateDefault(); -void BREAKOUT_ChangeSize(int width, int height); +void BREAKOUT_IncreaseScoreBy(Scenery * scenery, int scoreInc); +void TEXTURE_RenderCenteredSpriteSheet(SDL_Renderer * renderer, SDL_Texture * texture, SDL_Rect * srcRect, float Scale); +void TEXTURE_RenderCentered(SDL_Renderer * renderer, SDL_Texture * texture, float Scale); +void BREAKOUT_PushNewRow(Scenery * scenery); 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); 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); +Vector BALL_GetCenter(Ball * obj); +void BALL_CollideWithBorders(Ball * obj); +void BALL_MoveAwayFromBoundaries(Ball * obj); +bool BALL_CollideWithPaddle(Ball * obj, Paddle * paddle); +void BALL_AdaptSpeedGradient(Ball * obj, int FrameCount); +void BALL_PlayCollisionSound(); +void BALL_Update(Ball * obj, Scenery * scenery); void BALL_DestroyObject(Ball * obj); 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); void DOUBLE_Constrain(double * variable, double min, double max); -void PADDLE_Update(Paddle * obj, const Uint8 * keystate); +void PADDLE_MoveSmooth(Paddle * obj); +void PADDLE_MoveAuto(Scenery * scenery); +void PADDLE_AdaptSpeedGradient(Paddle * obj, int FrameCount); +void PADDLE_Update(Paddle * obj, Scenery * scenery, const Uint8 * keystate); void PADDLE_DestroyObject(Paddle * obj); void PADDLE_Deinitialize(); void BLOCK_Initialize(SDL_Renderer * renderer); -Block BLOCK_CreateDefault() ; +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_MoveSmooth(Block * obj); void BLOCK_Update(Block * obj); void BLOCK_DestroyObject(Block * obj); void BLOCK_Deinitialize(); diff --git a/font.c b/font.c new file mode 100644 index 0000000..1cd22b1 --- /dev/null +++ b/font.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "font.h" + +SDL_Color FONT_FontColor; +TTF_Font * FONT_FontFamily = NULL; + +void FONT_Initialize(){ + printf("Initializing Font...\n"); + FONT_FontColor = (SDL_Color) {255, 255, 255 }; + FONT_FontFamily = TTF_OpenFont(FONT_FontFile, 48); + if (!FONT_FontFamily) printf("Font could not initialize! Error: %s\n", TTF_GetError()); + else printf("Font was successfully initialized!\n"); + FONT_PrintFontStyle(FONT_FontFamily); + printf("Font initialized!\n"); +} + +void FONT_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 FONT_Deinitialize(){ + printf("De-initializing Font...\n"); + TTF_CloseFont(FONT_FontFamily); + FONT_FontFamily = NULL; // to be safe... + printf("Font de-initialized!\n"); +} + +void FONT_RenderText(SDL_Renderer * renderer, char * text, SDL_Rect * dstRect){ + SDL_Rect srcRect; + + srcRect.x = 0; + srcRect.y = 0; + SDL_Texture * texture = FONT_GenerateTexture(renderer, text, &srcRect); + SDL_RenderCopy(renderer, texture, &srcRect, dstRect); + SDL_DestroyTexture(texture); +} + +SDL_Texture * FONT_GenerateTexture(SDL_Renderer * renderer, char * text, SDL_Rect * Message_rect){ + SDL_Surface * tmpSurface = FONT_GenerateSurface(text, Message_rect); + SDL_Texture * resultTexture = SDL_CreateTextureFromSurface(renderer, tmpSurface); + + SDL_FreeSurface(tmpSurface); + return resultTexture; +} /* FONT_GenerateSurface */ + +SDL_Surface * FONT_GenerateSurface(char * text, SDL_Rect * Message_rect){ + TTF_SizeText(FONT_FontFamily, text, &(Message_rect->w), &(Message_rect->h)); + return TTF_RenderText_Solid(FONT_FontFamily, text, FONT_FontColor); +} diff --git a/font.h b/font.h new file mode 100644 index 0000000..eaf2688 --- /dev/null +++ b/font.h @@ -0,0 +1,20 @@ +#ifndef __font_h__ +#define __font_h__ + +#define FONT_FontFile "assets/fonts/monofur.ttf" + +// Externs +extern SDL_Color FONT_FontColor; +extern TTF_Font * FONT_FontFamily; +// End Externs + +// Prototypes +void FONT_Initialize(); +void FONT_PrintFontStyle(TTF_Font * ffont); +void FONT_Deinitialize(); +void FONT_RenderText(SDL_Renderer * renderer, char * text, SDL_Rect * dstRect); +SDL_Texture * FONT_GenerateTexture(SDL_Renderer * renderer, char * text, SDL_Rect * Message_rect); +SDL_Surface * FONT_GenerateSurface(char * text, SDL_Rect * Message_rect); +// End Prototypes + +#endif // __font_h__ diff --git a/gameover.c b/gameover.c new file mode 100644 index 0000000..58a9b0a --- /dev/null +++ b/gameover.c @@ -0,0 +1,201 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gameover.h" +#include "gamestate.h" +#include "breakout.h" +#include "vector.h" +#include "highscores.h" +#include "background.h" +#include "main.h" + +#define GAMEOVER_TexturePath "assets/images/gameover.png" +#define GAMEOVER_NumbersTexturePath "assets/images/numbers.png" +#define GAMEOVER_ScoreTexturePath "assets/images/yourscore.png" +#define GAMEOVER_UploadTexturePath "assets/images/upload.png" +#define GAMEOVER_HUDScale 16.0f +#define GAMEOVER_Scale 4.0f + +extern char * Username; +extern char * Password; +extern bool LoggedIn; + +extern int width, height; + +int GAMEOVER_HUDMargin = 5; +SDL_Texture * GAMEOVER_Texture; +SDL_Texture * GAMEOVER_Numbers; +SDL_Texture * GAMEOVER_ScoreTexture; +SDL_Texture * GAMEOVER_UploadTexture; +SDL_Rect * GAMEOVER_NumberRects; +SDL_Rect * GAMEOVER_UploadRects; +SDL_Rect GAMEOVER_TargetRect; +SDL_Rect GAMEOVER_ScoreTargetRect; +SDL_Rect GAMEOVER_HUDScoreTargetRect; +SDL_Rect * GAMEOVER_UploadTargetRects; +int * GAMEOVER_Digits; +bool GAMEOVER_IsInit = false; +UploadState GAMEOVER_UploadState = Initial; + +void GAMEOVER_Initialize(SDL_Renderer * renderer){ + if (!GAMEOVER_IsInit) { + printf("Initializing Gameover...\n"); + GAMEOVER_UploadState = Initial; + GAMEOVER_Texture = IMG_LoadTexture(renderer, GAMEOVER_TexturePath); + if (!GAMEOVER_Texture) printf("Gameover Texture couldn't be loaded!\n"); + GAMEOVER_Numbers = IMG_LoadTexture(renderer, GAMEOVER_NumbersTexturePath); + if (!GAMEOVER_Numbers) printf("Gameover Numbers couldn't be loaded!\n"); + GAMEOVER_ScoreTexture = IMG_LoadTexture(renderer, GAMEOVER_ScoreTexturePath); + if (!GAMEOVER_ScoreTexture) printf("Gameover Score Texture couldn't be loaded!\n"); + GAMEOVER_UploadTexture = IMG_LoadTexture(renderer, GAMEOVER_UploadTexturePath); + if (!GAMEOVER_UploadTexture) printf("Gameover Score Texture couldn't be loaded!\n"); + int w, h; + SDL_QueryTexture(GAMEOVER_Texture, NULL, NULL, &w, &h); + w /= 2; + h /= 2; + GAMEOVER_TargetRect.x = ((1920 - w) / 2); + GAMEOVER_TargetRect.y = 50; + GAMEOVER_TargetRect.w = w; + GAMEOVER_TargetRect.h = h; + GAMEOVER_NumberRects = calloc(10, sizeof(SDL_Rect)); + if (!GAMEOVER_NumberRects) printf("FATAL: Memory Allocation Failed!\n"); + GAMEOVER_NumberRects[0] = (SDL_Rect) {.x = 446, .y = 668, .w = 442, .h = 665 }; + GAMEOVER_NumberRects[1] = (SDL_Rect) {.x = 1299, .y = 1335, .w = 242, .h = 665 }; + GAMEOVER_NumberRects[2] = (SDL_Rect) {.x = 1, .y = 1, .w = 443, .h = 665 }; + GAMEOVER_NumberRects[3] = (SDL_Rect) {.x = 1, .y = 668, .w = 443, .h = 665 }; + GAMEOVER_NumberRects[4] = (SDL_Rect) {.x = 1, .y = 1335, .w = 443, .h = 665 }; + GAMEOVER_NumberRects[5] = (SDL_Rect) {.x = 446, .y = 1, .w = 443, .h = 665 }; + GAMEOVER_NumberRects[6] = (SDL_Rect) {.x = 891, .y = 1, .w = 443, .h = 665 }; + GAMEOVER_NumberRects[7] = (SDL_Rect) {.x = 890, .y = 1335, .w = 407, .h = 665 }; + GAMEOVER_NumberRects[8] = (SDL_Rect) {.x = 446, .y = 1335, .w = 442, .h = 665 }; + GAMEOVER_NumberRects[9] = (SDL_Rect) {.x = 890, .y = 668, .w = 442, .h = 665 }; + GAMEOVER_ScoreTargetRect.x = 0; + GAMEOVER_ScoreTargetRect.y = 450; + GAMEOVER_ScoreTargetRect.h = 183; + GAMEOVER_ScoreTargetRect.w = 1000; + GAMEOVER_UploadRects = malloc(4 * sizeof(SDL_Rect)); + if (!GAMEOVER_UploadRects) printf("FATAL: Memory Allocation Failed!\n"); + GAMEOVER_UploadRects[0] = (SDL_Rect) {.x = 1, .y = 1, .w = 4634, .h = 732 }; + GAMEOVER_UploadRects[1] = (SDL_Rect) {.x = 1, .y = 735, .w = 3981, .h = 734 }; + GAMEOVER_UploadRects[2] = (SDL_Rect) {.x = 1, .y = 1471, .w = 3024, .h = 666 }; + GAMEOVER_UploadRects[3] = (SDL_Rect) {.x = 3027, .y = 1471, .w = 2391, .h = 666 }; + GAMEOVER_UploadTargetRects = malloc(4 * sizeof(SDL_Rect)); + if (!GAMEOVER_UploadTargetRects) printf("FATAL: Memory Allocation Failed!\n"); + for (int i = 0; i < 4; i++) { + GAMEOVER_UploadTargetRects[i] = (SDL_Rect) {.x = 0, .y = 650, .w = ((GAMEOVER_UploadRects[i].w) / 5), .h = ((GAMEOVER_UploadRects[i].h) / 5) }; + } + GAMEOVER_HUDScoreTargetRect = (SDL_Rect) {.x = GAMEOVER_HUDMargin, .y = GAMEOVER_HUDMargin, .w = 250, .h = 46 }; + GAMEOVER_Digits = malloc(25 * sizeof(int)); + printf("Gameover initialized!\n"); + GAMEOVER_IsInit = true; + } else + printf("Gameover already initialized!\n"); +} /* GAMEOVER_Initialize */ + +void GAMEOVER_MouseClicked(SDL_MouseButtonEvent b, Scenery * scenery){ + if (b.button == SDL_BUTTON_LEFT) { + if (LoggedIn) + if (GAMEOVER_UploadState == Initial || GAMEOVER_UploadState == Failed) { + if (clickInRect(b, (GAMEOVER_UploadTargetRects + GAMEOVER_UploadState))) { + GAMEOVER_UploadState = Uploading; + if (HIGHSCORES_UploadScore(Username, (scenery->Score))) { + GAMEOVER_UploadState = Finished; + } else { + GAMEOVER_UploadState = Failed; + } + } + } + } +} + +void GAMEOVER_Draw(SDL_Renderer * renderer, Scenery * scenery){ + int i, count; + + SDL_RenderCopy(renderer, GAMEOVER_Texture, NULL, &GAMEOVER_TargetRect); + GAMEOVER_GetDigits((scenery->Score), &count); + int totalWidth = GAMEOVER_ScoreTargetRect.w; + for (i = (count - 1); i >= 0; i--) { + totalWidth += (int)roundf((float)GAMEOVER_NumberRects[i].w / GAMEOVER_Scale); + } + GAMEOVER_ScoreTargetRect.x = ((1920 - totalWidth) / 2); + SDL_RenderCopy(renderer, GAMEOVER_ScoreTexture, NULL, &GAMEOVER_ScoreTargetRect); + int xOffset = GAMEOVER_ScoreTargetRect.x + GAMEOVER_ScoreTargetRect.w; + SDL_Rect target; + target.y = 450; + for (i = (count - 1); i >= 0; i--) { + target.x = xOffset; + target.h = (int)roundf((float)(GAMEOVER_NumberRects[GAMEOVER_Digits[i]].h) / GAMEOVER_Scale); + target.w = (int)roundf((float)(GAMEOVER_NumberRects[GAMEOVER_Digits[i]].w) / GAMEOVER_Scale); + SDL_RenderCopy(renderer, GAMEOVER_Numbers, (GAMEOVER_NumberRects + GAMEOVER_Digits[i]), &target); + xOffset += target.w - 1; + } + if (LoggedIn) + GAMEOVER_DrawHorizontalCenter(renderer, GAMEOVER_UploadTexture, (GAMEOVER_UploadRects + GAMEOVER_UploadState), (GAMEOVER_UploadTargetRects + GAMEOVER_UploadState)); +} /* GAMEOVER_Draw */ + +void GAMEOVER_DrawHorizontalCenter(SDL_Renderer * renderer, SDL_Texture * texture, SDL_Rect * srcRect, SDL_Rect * dstRect){ + SDL_Rect target = *dstRect; + + target.x = ((width - target.w) / 2); + SDL_RenderCopy(renderer, texture, srcRect, &target); +} + +void GAMEOVER_GetDigits(int input, int * digitCount){ + int score = input; + int count = 0; + + while (score != 0) { + GAMEOVER_Digits[(count++)] = (score % 10); + score /= 10; + } + if (count == 0) { + count = 1; + GAMEOVER_Digits[0] = 0; + } + *digitCount = count; +} + +void SCORE_DrawHUD(SDL_Renderer * renderer, Scenery * scenery){ + int i, count; + + GAMEOVER_GetDigits((scenery->Score), &count); + int totalWidth = GAMEOVER_HUDScoreTargetRect.w; + for (i = (count - 1); i >= 0; i--) { + totalWidth += (int)roundf((float)GAMEOVER_NumberRects[i].w / GAMEOVER_HUDScale); + } + GAMEOVER_HUDScoreTargetRect.x = GAMEOVER_HUDMargin; + SDL_RenderCopy(renderer, GAMEOVER_ScoreTexture, NULL, &GAMEOVER_HUDScoreTargetRect); + int xOffset = GAMEOVER_HUDScoreTargetRect.x + GAMEOVER_HUDScoreTargetRect.w; + SDL_Rect target; + target.y = GAMEOVER_HUDMargin; + for (i = (count - 1); i >= 0; i--) { + target.x = xOffset; + target.h = (int)roundf((float)(GAMEOVER_NumberRects[GAMEOVER_Digits[i]].h) / GAMEOVER_HUDScale); + target.w = (int)roundf((float)(GAMEOVER_NumberRects[GAMEOVER_Digits[i]].w) / GAMEOVER_HUDScale); + SDL_RenderCopy(renderer, GAMEOVER_Numbers, (GAMEOVER_NumberRects + GAMEOVER_Digits[i]), &target); + xOffset += target.w - 1; + } +} /* SCORE_DrawHUD */ + +void GAMEOVER_Deinitialize(){ + if (GAMEOVER_IsInit) { + printf("De-initializing Gameover...\n"); + free(GAMEOVER_Digits); + free(GAMEOVER_NumberRects); + free(GAMEOVER_UploadRects); + free(GAMEOVER_UploadTargetRects); + SDL_DestroyTexture(GAMEOVER_Texture); + SDL_DestroyTexture(GAMEOVER_ScoreTexture); + SDL_DestroyTexture(GAMEOVER_Numbers); + SDL_DestroyTexture(GAMEOVER_UploadTexture); + printf("Gameover de-initialized!\n"); + GAMEOVER_IsInit = false; + } else + printf("Gameover already de-initialized!\n"); +} diff --git a/gameover.h b/gameover.h new file mode 100644 index 0000000..ac50e2f --- /dev/null +++ b/gameover.h @@ -0,0 +1,31 @@ +#ifndef __gameover_h__ +#define __gameover_h__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gameover.h" +#include "gamestate.h" +#include "main.h" + +// Enums +typedef enum uploadStateEnum { Initial = 0, Uploading = 1, Finished = 2, Failed = 3 } UploadState; +// Enums + +// Prototypes +void GAMEOVER_Initialize(SDL_Renderer * renderer); +void GAMEOVER_MouseClicked(SDL_MouseButtonEvent b, Scenery * scenery); +void GAMEOVER_Draw(SDL_Renderer * renderer, Scenery * scenery); +void GAMEOVER_DrawHorizontalCenter(SDL_Renderer * renderer, SDL_Texture * texture, SDL_Rect * srcRect, SDL_Rect * dstRect); +void GAMEOVER_GetDigits(int input, int * digitCount); +void SCORE_DrawHUD(SDL_Renderer * renderer, Scenery * scenery); +void GAMEOVER_Deinitialize(); +// End Prototypes + +#endif // __gameover_h__ diff --git a/gamestate.h b/gamestate.h index fca7225..c4291e0 100644 --- a/gamestate.h +++ b/gamestate.h @@ -1,6 +1,6 @@ #ifndef __gamestate_h__ #define __gamestate_h__ -typedef enum gameStateEnum { MainMenu = 1, Game = 2, LevelSelect = 3, SkinSelect = 4, Settings = 5, Highscores = 6 } GameState; +typedef enum gameStateEnum { MainMenu = 1, Game = 2, LevelSelect = 3, SkinSelect = 4, Settings = 5, Highscores = 6 , GameOver = 7 } GameState; #endif diff --git a/highscores.c b/highscores.c index ee5d98e..efd101d 100644 --- a/highscores.c +++ b/highscores.c @@ -8,7 +8,8 @@ #include "highscores.h" -#define HIGHSCORES_FontFile "assets/fonts/monofur.ttf" +#define HIGHSCORES_FontFile "assets/fonts/monofur.ttf" +#define HIGHSCORES_OutputFilePath "output.txt" int HIGHSCORES_EntriesGot = 0; User * HIGHSCORES_UserList; @@ -57,7 +58,6 @@ void HIGHSCORES_Draw(SDL_Renderer * renderer){ 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); @@ -67,7 +67,7 @@ void HIGHSCORES_Deinitialize(){ void HIGHSCORES_GenerateTexture(SDL_Renderer * renderer){ char * buffer = calloc(100, sizeof(char)); int count = 0; - char format[20] = "| %-58s | %-10s |"; + char format[20] = "| %-54s | %-14s |"; SDL_Rect Message_rect; SDL_Surface * HIGHSCORES_TableSurface = SDL_CreateRGBSurface(0, 1920, 1080, 32, 0, 0, 0, 0); @@ -103,10 +103,95 @@ void HIGHSCORES_DrawText(char * text, SDL_Rect * Message_rect){ tempSurface = TTF_RenderText_Solid(HIGHSCORES_FontFamily, text, HIGHSCORES_FontColor); } +bool HIGHSCORES_UploadScore(char * username, int score){ + char buffer[200]; + char * line = NULL; + size_t len = 0; + ssize_t read; + + sprintf(buffer, "bhi upload %s %s %d", HIGHSCORES_OutputFilePath, username, score); + printf("BHI called with \"%s\"\n", buffer); + // printf("Call BHI interface:\n"); + system(buffer); + // printf("BHI interface quit!\nBHI output handling...\n"); + FILE * fp = fopen(HIGHSCORES_OutputFilePath, "r"); + if (fp == NULL) { + fclose(fp); + return false; + } + if ((read = getline(&line, &len, fp)) != -1) + if (line[0] == '0') { + fclose(fp); + return false; + } + fclose(fp); + return true; +} /* HIGHSCORES_UploadScore */ + +bool HIGHSCORES_Login(char * username, char * password){ + char buffer[200]; + char * line = NULL; + size_t len = 0; + ssize_t read; + + sprintf(buffer, "bhi login %s %s %s", HIGHSCORES_OutputFilePath, username, password); + // printf("BHI called with \"%s\"\n", buffer); + printf("Logging in...\n"); + system(buffer); + // printf("BHI interface quit!\nBHI output handling...\n"); + FILE * fp = fopen(HIGHSCORES_OutputFilePath, "r"); + if (fp == NULL) { + fclose(fp); + printf("Login failed: Output file \"%s\" not found!\n", HIGHSCORES_OutputFilePath); + return false; + } + if ((read = getline(&line, &len, fp)) != -1) { + if (line[0] == '0') { + // if ((read = getline(&line, &len, fp)) != -1) { + // printf("Error: %s\n", line); + // } + fclose(fp); + return false; + } + } + fclose(fp); + return true; +} /* HIGHSCORES_Login */ + +bool HIGHSCORES_Register(char * username, char * password){ + char buffer[200]; + char * line = NULL; + size_t len = 0; + ssize_t read; + + sprintf(buffer, "bhi register %s %s %s", HIGHSCORES_OutputFilePath, username, password); + // printf("BHI called with \"%s\"\n", buffer); + printf("Registering...\n"); + system(buffer); + // printf("BHI interface quit!\nBHI output handling...\n"); + FILE * fp = fopen(HIGHSCORES_OutputFilePath, "r"); + if (fp == NULL) { + fclose(fp); + printf("Registration failed: Output file \"%s\" not found!\n", HIGHSCORES_OutputFilePath); + return false; + } + if ((read = getline(&line, &len, fp)) != -1) { + if (line[0] == '0') { + if ((read = getline(&line, &len, fp)) != -1) { + printf("Error: %s\n", line); + } + fclose(fp); + return false; + } + } + fclose(fp); + return true; +} /* HIGHSCORES_Login */ + void HIGHSCORES_ReloadList(){ printf("Call BHI interface:\n"); system("bhi top output.txt"); - printf("BHI interface quit!\nBHI output handling...\n"); + // printf("BHI interface quit!\nBHI output handling...\n"); HIGHSCORES_EntriesGot = 0; FILE * fp; @@ -118,10 +203,12 @@ void HIGHSCORES_ReloadList(){ bool switchread = false; HIGHSCORES_UserList = malloc(10 * sizeof(User)); fp = fopen("output.txt", "r"); - if (fp == NULL) + if (fp == NULL) { + printf("Reload failed: Output file \"%s\" not found!\n", HIGHSCORES_OutputFilePath); return; + } if ((read = getline(&line, &len, fp)) != -1) - if (line[0] == 0) + if (line[0] == '0') return; int counter = 0; while ((read = getline(&line, &len, fp)) != -1) { diff --git a/highscores.h b/highscores.h index abf70ff..eea45dd 100644 --- a/highscores.h +++ b/highscores.h @@ -14,6 +14,9 @@ void HIGHSCORES_Draw(SDL_Renderer * renderer); void HIGHSCORES_Deinitialize(); void HIGHSCORES_GenerateTexture(SDL_Renderer * renderer); void HIGHSCORES_DrawText(char * text, SDL_Rect * Message_rect); +bool HIGHSCORES_UploadScore(char * username, int score); +bool HIGHSCORES_Login(char * username, char * password); +bool HIGHSCORES_Register(char * username, char * password); void HIGHSCORES_ReloadList(); // End Prototypes diff --git a/include/SDL2/SDL_mixer.h b/include/SDL2/SDL_mixer.h new file mode 100644 index 0000000..cbb8ae6 --- /dev/null +++ b/include/SDL2/SDL_mixer.h @@ -0,0 +1,649 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2017 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_MIXER_H_ +#define SDL_MIXER_H_ + +#include "SDL_stdinc.h" +#include "SDL_rwops.h" +#include "SDL_audio.h" +#include "SDL_endian.h" +#include "SDL_version.h" +#include "begin_code.h" + +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +extern "C" { +#endif + +/* Printable format: "%d.%d.%d", MAJOR, MINOR, PATCHLEVEL +*/ +#define SDL_MIXER_MAJOR_VERSION 2 +#define SDL_MIXER_MINOR_VERSION 0 +#define SDL_MIXER_PATCHLEVEL 2 + +/* This macro can be used to fill a version structure with the compile-time + * version of the SDL_mixer library. + */ +#define SDL_MIXER_VERSION(X) \ +{ \ + (X)->major = SDL_MIXER_MAJOR_VERSION; \ + (X)->minor = SDL_MIXER_MINOR_VERSION; \ + (X)->patch = SDL_MIXER_PATCHLEVEL; \ +} + +/* Backwards compatibility */ +#define MIX_MAJOR_VERSION SDL_MIXER_MAJOR_VERSION +#define MIX_MINOR_VERSION SDL_MIXER_MINOR_VERSION +#define MIX_PATCHLEVEL SDL_MIXER_PATCHLEVEL +#define MIX_VERSION(X) SDL_MIXER_VERSION(X) + +/** + * This is the version number macro for the current SDL_mixer version. + */ +#define SDL_MIXER_COMPILEDVERSION \ + SDL_VERSIONNUM(SDL_MIXER_MAJOR_VERSION, SDL_MIXER_MINOR_VERSION, SDL_MIXER_PATCHLEVEL) + +/** + * This macro will evaluate to true if compiled with SDL_mixer at least X.Y.Z. + */ +#define SDL_MIXER_VERSION_ATLEAST(X, Y, Z) \ + (SDL_MIXER_COMPILEDVERSION >= SDL_VERSIONNUM(X, Y, Z)) + +/* This function gets the version of the dynamically linked SDL_mixer library. + it should NOT be used to fill a version structure, instead you should + use the SDL_MIXER_VERSION() macro. + */ +extern DECLSPEC const SDL_version * SDLCALL Mix_Linked_Version(void); + +typedef enum +{ + MIX_INIT_FLAC = 0x00000001, + MIX_INIT_MOD = 0x00000002, + MIX_INIT_MP3 = 0x00000008, + MIX_INIT_OGG = 0x00000010, + MIX_INIT_MID = 0x00000020 +} MIX_InitFlags; + +/* Loads dynamic libraries and prepares them for use. Flags should be + one or more flags from MIX_InitFlags OR'd together. + It returns the flags successfully initialized, or 0 on failure. + */ +extern DECLSPEC int SDLCALL Mix_Init(int flags); + +/* Unloads libraries loaded with Mix_Init */ +extern DECLSPEC void SDLCALL Mix_Quit(void); + + +/* The default mixer has 8 simultaneous mixing channels */ +#ifndef MIX_CHANNELS +#define MIX_CHANNELS 8 +#endif + +/* Good default values for a PC soundcard */ +#define MIX_DEFAULT_FREQUENCY 22050 +#if SDL_BYTEORDER == SDL_LIL_ENDIAN +#define MIX_DEFAULT_FORMAT AUDIO_S16LSB +#else +#define MIX_DEFAULT_FORMAT AUDIO_S16MSB +#endif +#define MIX_DEFAULT_CHANNELS 2 +#define MIX_MAX_VOLUME SDL_MIX_MAXVOLUME /* Volume of a chunk */ + +/* The internal format for an audio chunk */ +typedef struct Mix_Chunk { + int allocated; + Uint8 *abuf; + Uint32 alen; + Uint8 volume; /* Per-sample volume, 0-128 */ +} Mix_Chunk; + +/* The different fading types supported */ +typedef enum { + MIX_NO_FADING, + MIX_FADING_OUT, + MIX_FADING_IN +} Mix_Fading; + +/* These are types of music files (not libraries used to load them) */ +typedef enum { + MUS_NONE, + MUS_CMD, + MUS_WAV, + MUS_MOD, + MUS_MID, + MUS_OGG, + MUS_MP3, + MUS_MP3_MAD_UNUSED, + MUS_FLAC, + MUS_MODPLUG_UNUSED +} Mix_MusicType; + +/* The internal format for a music chunk interpreted via mikmod */ +typedef struct _Mix_Music Mix_Music; + +/* Open the mixer with a certain audio format */ +extern DECLSPEC int SDLCALL Mix_OpenAudio(int frequency, Uint16 format, int channels, int chunksize); + +/* Open the mixer with specific device and certain audio format */ +extern DECLSPEC int SDLCALL Mix_OpenAudioDevice(int frequency, Uint16 format, int channels, int chunksize, const char* device, int allowed_changes); + +/* Dynamically change the number of channels managed by the mixer. + If decreasing the number of channels, the upper channels are + stopped. + This function returns the new number of allocated channels. + */ +extern DECLSPEC int SDLCALL Mix_AllocateChannels(int numchans); + +/* Find out what the actual audio device parameters are. + This function returns 1 if the audio has been opened, 0 otherwise. + */ +extern DECLSPEC int SDLCALL Mix_QuerySpec(int *frequency,Uint16 *format,int *channels); + +/* Load a wave file or a music (.mod .s3m .it .xm) file */ +extern DECLSPEC Mix_Chunk * SDLCALL Mix_LoadWAV_RW(SDL_RWops *src, int freesrc); +#define Mix_LoadWAV(file) Mix_LoadWAV_RW(SDL_RWFromFile(file, "rb"), 1) +extern DECLSPEC Mix_Music * SDLCALL Mix_LoadMUS(const char *file); + +/* Load a music file from an SDL_RWop object (Ogg and MikMod specific currently) + Matt Campbell (matt@campbellhome.dhs.org) April 2000 */ +extern DECLSPEC Mix_Music * SDLCALL Mix_LoadMUS_RW(SDL_RWops *src, int freesrc); + +/* Load a music file from an SDL_RWop object assuming a specific format */ +extern DECLSPEC Mix_Music * SDLCALL Mix_LoadMUSType_RW(SDL_RWops *src, Mix_MusicType type, int freesrc); + +/* Load a wave file of the mixer format from a memory buffer */ +extern DECLSPEC Mix_Chunk * SDLCALL Mix_QuickLoad_WAV(Uint8 *mem); + +/* Load raw audio data of the mixer format from a memory buffer */ +extern DECLSPEC Mix_Chunk * SDLCALL Mix_QuickLoad_RAW(Uint8 *mem, Uint32 len); + +/* Free an audio chunk previously loaded */ +extern DECLSPEC void SDLCALL Mix_FreeChunk(Mix_Chunk *chunk); +extern DECLSPEC void SDLCALL Mix_FreeMusic(Mix_Music *music); + +/* Get a list of chunk/music decoders that this build of SDL_mixer provides. + This list can change between builds AND runs of the program, if external + libraries that add functionality become available. + You must successfully call Mix_OpenAudio() before calling these functions. + This API is only available in SDL_mixer 1.2.9 and later. + + // usage... + int i; + const int total = Mix_GetNumChunkDecoders(); + for (i = 0; i < total; i++) + printf("Supported chunk decoder: [%s]\n", Mix_GetChunkDecoder(i)); + + Appearing in this list doesn't promise your specific audio file will + decode...but it's handy to know if you have, say, a functioning Timidity + install. + + These return values are static, read-only data; do not modify or free it. + The pointers remain valid until you call Mix_CloseAudio(). +*/ +extern DECLSPEC int SDLCALL Mix_GetNumChunkDecoders(void); +extern DECLSPEC const char * SDLCALL Mix_GetChunkDecoder(int index); +extern DECLSPEC SDL_bool SDLCALL Mix_HasChunkDecoder(const char *name); +extern DECLSPEC int SDLCALL Mix_GetNumMusicDecoders(void); +extern DECLSPEC const char * SDLCALL Mix_GetMusicDecoder(int index); +extern DECLSPEC SDL_bool SDLCALL Mix_HasMusicDecoder(const char *name); + +/* Find out the music format of a mixer music, or the currently playing + music, if 'music' is NULL. +*/ +extern DECLSPEC Mix_MusicType SDLCALL Mix_GetMusicType(const Mix_Music *music); + +/* Set a function that is called after all mixing is performed. + This can be used to provide real-time visual display of the audio stream + or add a custom mixer filter for the stream data. +*/ +extern DECLSPEC void SDLCALL Mix_SetPostMix(void (SDLCALL *mix_func)(void *udata, Uint8 *stream, int len), void *arg); + +/* Add your own music player or additional mixer function. + If 'mix_func' is NULL, the default music player is re-enabled. + */ +extern DECLSPEC void SDLCALL Mix_HookMusic(void (SDLCALL *mix_func)(void *udata, Uint8 *stream, int len), void *arg); + +/* Add your own callback for when the music has finished playing or when it is + * stopped from a call to Mix_HaltMusic. + */ +extern DECLSPEC void SDLCALL Mix_HookMusicFinished(void (SDLCALL *music_finished)(void)); + +/* Get a pointer to the user data for the current music hook */ +extern DECLSPEC void * SDLCALL Mix_GetMusicHookData(void); + +/* + * Add your own callback when a channel has finished playing. NULL + * to disable callback. The callback may be called from the mixer's audio + * callback or it could be called as a result of Mix_HaltChannel(), etc. + * do not call SDL_LockAudio() from this callback; you will either be + * inside the audio callback, or SDL_mixer will explicitly lock the audio + * before calling your callback. + */ +extern DECLSPEC void SDLCALL Mix_ChannelFinished(void (SDLCALL *channel_finished)(int channel)); + + +/* Special Effects API by ryan c. gordon. (icculus@icculus.org) */ + +#define MIX_CHANNEL_POST -2 + +/* This is the format of a special effect callback: + * + * myeffect(int chan, void *stream, int len, void *udata); + * + * (chan) is the channel number that your effect is affecting. (stream) is + * the buffer of data to work upon. (len) is the size of (stream), and + * (udata) is a user-defined bit of data, which you pass as the last arg of + * Mix_RegisterEffect(), and is passed back unmolested to your callback. + * Your effect changes the contents of (stream) based on whatever parameters + * are significant, or just leaves it be, if you prefer. You can do whatever + * you like to the buffer, though, and it will continue in its changed state + * down the mixing pipeline, through any other effect functions, then finally + * to be mixed with the rest of the channels and music for the final output + * stream. + * + * DO NOT EVER call SDL_LockAudio() from your callback function! + */ +typedef void (SDLCALL *Mix_EffectFunc_t)(int chan, void *stream, int len, void *udata); + +/* + * This is a callback that signifies that a channel has finished all its + * loops and has completed playback. This gets called if the buffer + * plays out normally, or if you call Mix_HaltChannel(), implicitly stop + * a channel via Mix_AllocateChannels(), or unregister a callback while + * it's still playing. + * + * DO NOT EVER call SDL_LockAudio() from your callback function! + */ +typedef void (SDLCALL *Mix_EffectDone_t)(int chan, void *udata); + + +/* Register a special effect function. At mixing time, the channel data is + * copied into a buffer and passed through each registered effect function. + * After it passes through all the functions, it is mixed into the final + * output stream. The copy to buffer is performed once, then each effect + * function performs on the output of the previous effect. Understand that + * this extra copy to a buffer is not performed if there are no effects + * registered for a given chunk, which saves CPU cycles, and any given + * effect will be extra cycles, too, so it is crucial that your code run + * fast. Also note that the data that your function is given is in the + * format of the sound device, and not the format you gave to Mix_OpenAudio(), + * although they may in reality be the same. This is an unfortunate but + * necessary speed concern. Use Mix_QuerySpec() to determine if you can + * handle the data before you register your effect, and take appropriate + * actions. + * You may also specify a callback (Mix_EffectDone_t) that is called when + * the channel finishes playing. This gives you a more fine-grained control + * than Mix_ChannelFinished(), in case you need to free effect-specific + * resources, etc. If you don't need this, you can specify NULL. + * You may set the callbacks before or after calling Mix_PlayChannel(). + * Things like Mix_SetPanning() are just internal special effect functions, + * so if you are using that, you've already incurred the overhead of a copy + * to a separate buffer, and that these effects will be in the queue with + * any functions you've registered. The list of registered effects for a + * channel is reset when a chunk finishes playing, so you need to explicitly + * set them with each call to Mix_PlayChannel*(). + * You may also register a special effect function that is to be run after + * final mixing occurs. The rules for these callbacks are identical to those + * in Mix_RegisterEffect, but they are run after all the channels and the + * music have been mixed into a single stream, whereas channel-specific + * effects run on a given channel before any other mixing occurs. These + * global effect callbacks are call "posteffects". Posteffects only have + * their Mix_EffectDone_t function called when they are unregistered (since + * the main output stream is never "done" in the same sense as a channel). + * You must unregister them manually when you've had enough. Your callback + * will be told that the channel being mixed is (MIX_CHANNEL_POST) if the + * processing is considered a posteffect. + * + * After all these effects have finished processing, the callback registered + * through Mix_SetPostMix() runs, and then the stream goes to the audio + * device. + * + * DO NOT EVER call SDL_LockAudio() from your callback function! + * + * returns zero if error (no such channel), nonzero if added. + * Error messages can be retrieved from Mix_GetError(). + */ +extern DECLSPEC int SDLCALL Mix_RegisterEffect(int chan, Mix_EffectFunc_t f, Mix_EffectDone_t d, void *arg); + + +/* You may not need to call this explicitly, unless you need to stop an + * effect from processing in the middle of a chunk's playback. + * Posteffects are never implicitly unregistered as they are for channels, + * but they may be explicitly unregistered through this function by + * specifying MIX_CHANNEL_POST for a channel. + * returns zero if error (no such channel or effect), nonzero if removed. + * Error messages can be retrieved from Mix_GetError(). + */ +extern DECLSPEC int SDLCALL Mix_UnregisterEffect(int channel, Mix_EffectFunc_t f); + + +/* You may not need to call this explicitly, unless you need to stop all + * effects from processing in the middle of a chunk's playback. Note that + * this will also shut off some internal effect processing, since + * Mix_SetPanning() and others may use this API under the hood. This is + * called internally when a channel completes playback. + * Posteffects are never implicitly unregistered as they are for channels, + * but they may be explicitly unregistered through this function by + * specifying MIX_CHANNEL_POST for a channel. + * returns zero if error (no such channel), nonzero if all effects removed. + * Error messages can be retrieved from Mix_GetError(). + */ +extern DECLSPEC int SDLCALL Mix_UnregisterAllEffects(int channel); + + +#define MIX_EFFECTSMAXSPEED "MIX_EFFECTSMAXSPEED" + +/* + * These are the internally-defined mixing effects. They use the same API that + * effects defined in the application use, but are provided here as a + * convenience. Some effects can reduce their quality or use more memory in + * the name of speed; to enable this, make sure the environment variable + * MIX_EFFECTSMAXSPEED (see above) is defined before you call + * Mix_OpenAudio(). + */ + + +/* Set the panning of a channel. The left and right channels are specified + * as integers between 0 and 255, quietest to loudest, respectively. + * + * Technically, this is just individual volume control for a sample with + * two (stereo) channels, so it can be used for more than just panning. + * If you want real panning, call it like this: + * + * Mix_SetPanning(channel, left, 255 - left); + * + * ...which isn't so hard. + * + * Setting (channel) to MIX_CHANNEL_POST registers this as a posteffect, and + * the panning will be done to the final mixed stream before passing it on + * to the audio device. + * + * This uses the Mix_RegisterEffect() API internally, and returns without + * registering the effect function if the audio device is not configured + * for stereo output. Setting both (left) and (right) to 255 causes this + * effect to be unregistered, since that is the data's normal state. + * + * returns zero if error (no such channel or Mix_RegisterEffect() fails), + * nonzero if panning effect enabled. Note that an audio device in mono + * mode is a no-op, but this call will return successful in that case. + * Error messages can be retrieved from Mix_GetError(). + */ +extern DECLSPEC int SDLCALL Mix_SetPanning(int channel, Uint8 left, Uint8 right); + + +/* Set the position of a channel. (angle) is an integer from 0 to 360, that + * specifies the location of the sound in relation to the listener. (angle) + * will be reduced as neccesary (540 becomes 180 degrees, -100 becomes 260). + * Angle 0 is due north, and rotates clockwise as the value increases. + * For efficiency, the precision of this effect may be limited (angles 1 + * through 7 might all produce the same effect, 8 through 15 are equal, etc). + * (distance) is an integer between 0 and 255 that specifies the space + * between the sound and the listener. The larger the number, the further + * away the sound is. Using 255 does not guarantee that the channel will be + * culled from the mixing process or be completely silent. For efficiency, + * the precision of this effect may be limited (distance 0 through 5 might + * all produce the same effect, 6 through 10 are equal, etc). Setting (angle) + * and (distance) to 0 unregisters this effect, since the data would be + * unchanged. + * + * If you need more precise positional audio, consider using OpenAL for + * spatialized effects instead of SDL_mixer. This is only meant to be a + * basic effect for simple "3D" games. + * + * If the audio device is configured for mono output, then you won't get + * any effectiveness from the angle; however, distance attenuation on the + * channel will still occur. While this effect will function with stereo + * voices, it makes more sense to use voices with only one channel of sound, + * so when they are mixed through this effect, the positioning will sound + * correct. You can convert them to mono through SDL before giving them to + * the mixer in the first place if you like. + * + * Setting (channel) to MIX_CHANNEL_POST registers this as a posteffect, and + * the positioning will be done to the final mixed stream before passing it + * on to the audio device. + * + * This is a convenience wrapper over Mix_SetDistance() and Mix_SetPanning(). + * + * returns zero if error (no such channel or Mix_RegisterEffect() fails), + * nonzero if position effect is enabled. + * Error messages can be retrieved from Mix_GetError(). + */ +extern DECLSPEC int SDLCALL Mix_SetPosition(int channel, Sint16 angle, Uint8 distance); + + +/* Set the "distance" of a channel. (distance) is an integer from 0 to 255 + * that specifies the location of the sound in relation to the listener. + * Distance 0 is overlapping the listener, and 255 is as far away as possible + * A distance of 255 does not guarantee silence; in such a case, you might + * want to try changing the chunk's volume, or just cull the sample from the + * mixing process with Mix_HaltChannel(). + * For efficiency, the precision of this effect may be limited (distances 1 + * through 7 might all produce the same effect, 8 through 15 are equal, etc). + * (distance) is an integer between 0 and 255 that specifies the space + * between the sound and the listener. The larger the number, the further + * away the sound is. + * Setting (distance) to 0 unregisters this effect, since the data would be + * unchanged. + * If you need more precise positional audio, consider using OpenAL for + * spatialized effects instead of SDL_mixer. This is only meant to be a + * basic effect for simple "3D" games. + * + * Setting (channel) to MIX_CHANNEL_POST registers this as a posteffect, and + * the distance attenuation will be done to the final mixed stream before + * passing it on to the audio device. + * + * This uses the Mix_RegisterEffect() API internally. + * + * returns zero if error (no such channel or Mix_RegisterEffect() fails), + * nonzero if position effect is enabled. + * Error messages can be retrieved from Mix_GetError(). + */ +extern DECLSPEC int SDLCALL Mix_SetDistance(int channel, Uint8 distance); + + +/* + * !!! FIXME : Haven't implemented, since the effect goes past the + * end of the sound buffer. Will have to think about this. + * --ryan. + */ +#if 0 +/* Causes an echo effect to be mixed into a sound. (echo) is the amount + * of echo to mix. 0 is no echo, 255 is infinite (and probably not + * what you want). + * + * Setting (channel) to MIX_CHANNEL_POST registers this as a posteffect, and + * the reverbing will be done to the final mixed stream before passing it on + * to the audio device. + * + * This uses the Mix_RegisterEffect() API internally. If you specify an echo + * of zero, the effect is unregistered, as the data is already in that state. + * + * returns zero if error (no such channel or Mix_RegisterEffect() fails), + * nonzero if reversing effect is enabled. + * Error messages can be retrieved from Mix_GetError(). + */ +extern no_parse_DECLSPEC int SDLCALL Mix_SetReverb(int channel, Uint8 echo); +#endif + +/* Causes a channel to reverse its stereo. This is handy if the user has his + * speakers hooked up backwards, or you would like to have a minor bit of + * psychedelia in your sound code. :) Calling this function with (flip) + * set to non-zero reverses the chunks's usual channels. If (flip) is zero, + * the effect is unregistered. + * + * This uses the Mix_RegisterEffect() API internally, and thus is probably + * more CPU intensive than having the user just plug in his speakers + * correctly. Mix_SetReverseStereo() returns without registering the effect + * function if the audio device is not configured for stereo output. + * + * If you specify MIX_CHANNEL_POST for (channel), then this the effect is used + * on the final mixed stream before sending it on to the audio device (a + * posteffect). + * + * returns zero if error (no such channel or Mix_RegisterEffect() fails), + * nonzero if reversing effect is enabled. Note that an audio device in mono + * mode is a no-op, but this call will return successful in that case. + * Error messages can be retrieved from Mix_GetError(). + */ +extern DECLSPEC int SDLCALL Mix_SetReverseStereo(int channel, int flip); + +/* end of effects API. --ryan. */ + + +/* Reserve the first channels (0 -> n-1) for the application, i.e. don't allocate + them dynamically to the next sample if requested with a -1 value below. + Returns the number of reserved channels. + */ +extern DECLSPEC int SDLCALL Mix_ReserveChannels(int num); + +/* Channel grouping functions */ + +/* Attach a tag to a channel. A tag can be assigned to several mixer + channels, to form groups of channels. + If 'tag' is -1, the tag is removed (actually -1 is the tag used to + represent the group of all the channels). + Returns true if everything was OK. + */ +extern DECLSPEC int SDLCALL Mix_GroupChannel(int which, int tag); +/* Assign several consecutive channels to a group */ +extern DECLSPEC int SDLCALL Mix_GroupChannels(int from, int to, int tag); +/* Finds the first available channel in a group of channels, + returning -1 if none are available. + */ +extern DECLSPEC int SDLCALL Mix_GroupAvailable(int tag); +/* Returns the number of channels in a group. This is also a subtle + way to get the total number of channels when 'tag' is -1 + */ +extern DECLSPEC int SDLCALL Mix_GroupCount(int tag); +/* Finds the "oldest" sample playing in a group of channels */ +extern DECLSPEC int SDLCALL Mix_GroupOldest(int tag); +/* Finds the "most recent" (i.e. last) sample playing in a group of channels */ +extern DECLSPEC int SDLCALL Mix_GroupNewer(int tag); + +/* Play an audio chunk on a specific channel. + If the specified channel is -1, play on the first free channel. + If 'loops' is greater than zero, loop the sound that many times. + If 'loops' is -1, loop inifinitely (~65000 times). + Returns which channel was used to play the sound. +*/ +#define Mix_PlayChannel(channel,chunk,loops) Mix_PlayChannelTimed(channel,chunk,loops,-1) +/* The same as above, but the sound is played at most 'ticks' milliseconds */ +extern DECLSPEC int SDLCALL Mix_PlayChannelTimed(int channel, Mix_Chunk *chunk, int loops, int ticks); +extern DECLSPEC int SDLCALL Mix_PlayMusic(Mix_Music *music, int loops); + +/* Fade in music or a channel over "ms" milliseconds, same semantics as the "Play" functions */ +extern DECLSPEC int SDLCALL Mix_FadeInMusic(Mix_Music *music, int loops, int ms); +extern DECLSPEC int SDLCALL Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position); +#define Mix_FadeInChannel(channel,chunk,loops,ms) Mix_FadeInChannelTimed(channel,chunk,loops,ms,-1) +extern DECLSPEC int SDLCALL Mix_FadeInChannelTimed(int channel, Mix_Chunk *chunk, int loops, int ms, int ticks); + +/* Set the volume in the range of 0-128 of a specific channel or chunk. + If the specified channel is -1, set volume for all channels. + Returns the original volume. + If the specified volume is -1, just return the current volume. +*/ +extern DECLSPEC int SDLCALL Mix_Volume(int channel, int volume); +extern DECLSPEC int SDLCALL Mix_VolumeChunk(Mix_Chunk *chunk, int volume); +extern DECLSPEC int SDLCALL Mix_VolumeMusic(int volume); + +/* Halt playing of a particular channel */ +extern DECLSPEC int SDLCALL Mix_HaltChannel(int channel); +extern DECLSPEC int SDLCALL Mix_HaltGroup(int tag); +extern DECLSPEC int SDLCALL Mix_HaltMusic(void); + +/* Change the expiration delay for a particular channel. + The sample will stop playing after the 'ticks' milliseconds have elapsed, + or remove the expiration if 'ticks' is -1 +*/ +extern DECLSPEC int SDLCALL Mix_ExpireChannel(int channel, int ticks); + +/* Halt a channel, fading it out progressively till it's silent + The ms parameter indicates the number of milliseconds the fading + will take. + */ +extern DECLSPEC int SDLCALL Mix_FadeOutChannel(int which, int ms); +extern DECLSPEC int SDLCALL Mix_FadeOutGroup(int tag, int ms); +extern DECLSPEC int SDLCALL Mix_FadeOutMusic(int ms); + +/* Query the fading status of a channel */ +extern DECLSPEC Mix_Fading SDLCALL Mix_FadingMusic(void); +extern DECLSPEC Mix_Fading SDLCALL Mix_FadingChannel(int which); + +/* Pause/Resume a particular channel */ +extern DECLSPEC void SDLCALL Mix_Pause(int channel); +extern DECLSPEC void SDLCALL Mix_Resume(int channel); +extern DECLSPEC int SDLCALL Mix_Paused(int channel); + +/* Pause/Resume the music stream */ +extern DECLSPEC void SDLCALL Mix_PauseMusic(void); +extern DECLSPEC void SDLCALL Mix_ResumeMusic(void); +extern DECLSPEC void SDLCALL Mix_RewindMusic(void); +extern DECLSPEC int SDLCALL Mix_PausedMusic(void); + +/* Set the current position in the music stream. + This returns 0 if successful, or -1 if it failed or isn't implemented. + This function is only implemented for MOD music formats (set pattern + order number) and for OGG, FLAC, MP3_MAD, MP3_MPG and MODPLUG music + (set position in seconds), at the moment. +*/ +extern DECLSPEC int SDLCALL Mix_SetMusicPosition(double position); + +/* Check the status of a specific channel. + If the specified channel is -1, check all channels. +*/ +extern DECLSPEC int SDLCALL Mix_Playing(int channel); +extern DECLSPEC int SDLCALL Mix_PlayingMusic(void); + +/* Stop music and set external music playback command */ +extern DECLSPEC int SDLCALL Mix_SetMusicCMD(const char *command); + +/* Synchro value is set by MikMod from modules while playing */ +extern DECLSPEC int SDLCALL Mix_SetSynchroValue(int value); +extern DECLSPEC int SDLCALL Mix_GetSynchroValue(void); + +/* Set/Get/Iterate SoundFonts paths to use by supported MIDI backends */ +extern DECLSPEC int SDLCALL Mix_SetSoundFonts(const char *paths); +extern DECLSPEC const char* SDLCALL Mix_GetSoundFonts(void); +extern DECLSPEC int SDLCALL Mix_EachSoundFont(int (SDLCALL *function)(const char*, void*), void *data); + +/* Get the Mix_Chunk currently associated with a mixer channel + Returns NULL if it's an invalid channel, or there's no chunk associated. +*/ +extern DECLSPEC Mix_Chunk * SDLCALL Mix_GetChunk(int channel); + +/* Close the mixer, halting all playing audio */ +extern DECLSPEC void SDLCALL Mix_CloseAudio(void); + +/* We'll use SDL for reporting errors */ +#define Mix_SetError SDL_SetError +#define Mix_GetError SDL_GetError +#define Mix_ClearError SDL_ClearError + +/* Ends C function definitions when using C++ */ +#ifdef __cplusplus +} +#endif +#include "close_code.h" + +#endif /* SDL_MIXER_H_ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/lib/libSDL2_mixer.a b/lib/libSDL2_mixer.a new file mode 100644 index 0000000..9cc3ed1 Binary files /dev/null and b/lib/libSDL2_mixer.a differ diff --git a/lib/libSDL2_mixer.dll.a b/lib/libSDL2_mixer.dll.a new file mode 100644 index 0000000..6b63de0 Binary files /dev/null and b/lib/libSDL2_mixer.dll.a differ diff --git a/lib/libSDL2_mixer.la b/lib/libSDL2_mixer.la new file mode 100644 index 0000000..9e8c14f --- /dev/null +++ b/lib/libSDL2_mixer.la @@ -0,0 +1,41 @@ +# libSDL2_mixer.la - a libtool library file +# Generated by ltmain.sh (GNU libtool) 2.2.6 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='../bin/SDL2_mixer.dll' + +# Names of this library. +library_names='libSDL2_mixer.dll.a' + +# The name of the static archive. +old_library='libSDL2_mixer.a' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags='' + +# Libraries that this one depends upon. +dependency_libs=' -L/usr/local/i686-w64-mingw32/lib -lmingw32 /usr/local/i686-w64-mingw32/lib/libSDL2.la -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -limm32 -lole32 -loleaut32 -lshell32 -lversion -luuid -lwinmm' + +# Names of additional weak libraries provided by this library +weak_library_names='' + +# Version information for libSDL2_mixer. +current=2 +age=2 +revision=0 + +# Is this an already installed library? +installed=yes + +# Should we warn about portability when linking against -modules? +shouldnotlink=no + +# Files to dlopen/dlpreopen +dlopen='' +dlpreopen='' + +# Directory that this library needs to be installed in: +libdir='/Users/slouken/release/SDL_mixer/SDL2_mixer-2.0.2/i686-w64-mingw32/lib' diff --git a/lib/pkgconfig/SDL2_mixer.pc b/lib/pkgconfig/SDL2_mixer.pc new file mode 100644 index 0000000..76ba57f --- /dev/null +++ b/lib/pkgconfig/SDL2_mixer.pc @@ -0,0 +1,12 @@ +prefix=/usr/local/i686-w64-mingw32 +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: SDL2_mixer +Description: mixer library for Simple DirectMedia Layer +Version: 2.0.2 +Requires: sdl2 >= 2.0.7 +Libs: -L${libdir} -lSDL2_mixer +Cflags: -I${includedir}/SDL2 + diff --git a/main.c b/main.c index 48da5fc..95fbabc 100644 --- a/main.c +++ b/main.c @@ -2,17 +2,25 @@ #include #include #include +#include #include #include #include #include +#include #include "breakout.h" #include "vector.h" #include "startmenu.h" #include "gamestate.h" #include "highscores.h" +#include "gameover.h" #include "settings.h" +#include "background.h" + +#define MAIN_MenuMusicPath "assets/sounds/menu_music.wav" +#define MAIN_AccountSaveFilePath "account.cfg" +#define MAIN_FadeTime 1000 #include "main.h" @@ -27,20 +35,28 @@ 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; +bool running = true, fullscreen = false, LoggedIn = false; GameState gameState = MainMenu; Scenery scenery; +Mix_Music * MenuLoop; +char * Username; +char * Password; int main(int argc, char * args[]){ - // 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)); + AttemptLogin(); INITIALIZE(); + Uint32 fps_lasttime = SDL_GetTicks(); // the last recorded time. + Uint32 fps_current; // the current FPS. + Uint32 fps_frames = 0; // frames passed since the last recorded fps. + + GAME_ChangeState(MainMenu); while (running) { // Gameloop HandleSDLEvents(); DrawBackground(renderer); switch (gameState) { case Game: BREAKOUT_Update(&scenery, keystate); + BACKGROUND_Draw(renderer, 0); BREAKOUT_Draw(&scenery, renderer); break; case MainMenu: @@ -51,30 +67,191 @@ int main(int argc, char * args[]){ HIGHSCORES_Draw(renderer); break; case Settings: - Settings_Draw(renderer); + Settings_Draw(renderer, &scenery); + break; + case GameOver: + GAMEOVER_Draw(renderer, &scenery); break; default: printf("Unknow state was updated: %d\n", gameState); break; - } + } /* switch */ SDL_RenderPresent(renderer); + fps_frames++; + if (fps_lasttime < SDL_GetTicks() - 1000) { + fps_lasttime = SDL_GetTicks(); + fps_current = fps_frames; + fps_frames = 0; + printf("Frames/s: %u\n", fps_current); + } } QUIT(); return 0; } /* main */ +bool PushNewCredentialsToSaveFile(const char * filename){ + FILE * file; + + if (file = fopen(filename, "w")) { + fprintf(file, "%s\n%s", Username, Password); + fclose(file); + return true; + } + return false; +} + +bool GrabAccountFromSaveFile(const char * filename){ + FILE * file; + + if (file = fopen(filename, "r")) { + bool success = true; + success = (fscanf(file, "%s\n%s", Username, Password) > 0); + if (success) printf("Account save file found \"%s\"!\nAttempting automatic login for user \"%s\"...\n", MAIN_AccountSaveFilePath, Username); + else printf("Account save file \"%s\" is invalid!\n", MAIN_AccountSaveFilePath); + fclose(file); + return success; + } + return false; +} /* GrabAccountFromSaveFile */ + +void GAME_ReadCredentials(){ + printf("Input your username: "); + gets(Username); + printf("Input your password: "); + gets(Password); +} + +bool GAME_Login(){ + printf("Login:\n"); + bool loginSuccess = HIGHSCORES_Login(Username, Password); + if (loginSuccess) { + printf("Successfully logged in as %s!\n", Username); + LoggedIn = true; + } else + printf("Login failed!\n"); + return loginSuccess; +} + +bool GAME_Register(){ + printf("Register:\n"); + bool loginSuccess = HIGHSCORES_Register(Username, Password); + if (loginSuccess) { + printf("Successfully registered new account: %s!\n", Username); + LoggedIn = true; + } else + printf("Registration failed!\n"); + return loginSuccess; +} + +void AttemptLogin(){ + Username = calloc(50, sizeof(char)); + Password = calloc(50, sizeof(char)); + int state; + bool loginSuccess = false; + + if (GrabAccountFromSaveFile(MAIN_AccountSaveFilePath)) { + if (GAME_Login()) { + printf("Automatic login succeded!\n"); + return; + } else { + printf("Automatic login failed! Try manually!\n"); + system("pause"); + } + } + while (!loginSuccess) { + system("cls"); + printf("If you want to upload your score to the scoreboard you need to login! Enter\n\t- 1 for logging in with an existing account\n\t- 2 for creating a new account\n\t- 3 for playing unranked\n"); + state = readIntFromIO("Input>", "Invalid input! Awaited a number from 1 to 3.\n", "%d is not a valid mode!\n", 1, 3); + switch (state) { + case 1: + GAME_ReadCredentials(); + loginSuccess = GAME_Login(); + break; + case 2: + GAME_ReadCredentials(); + loginSuccess = GAME_Register(); + break; + case 3: + printf("Skipping login!"); + LoggedIn = false; + loginSuccess = true; + break; + default: + printf("This should not happen! State is %d...\n", state); + LoggedIn = false; + loginSuccess = false; + break; + } /* switch */ + if (!loginSuccess) system("pause"); + } + if (PushNewCredentialsToSaveFile(MAIN_AccountSaveFilePath)) printf("New login credentials were automatically saved!\n"); + else printf("Login credentials could not be autosaved!\n"); +} /* AttemptLogin */ + +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 */ + void GAME_Escape(){ running = false; printf("GAME_Escape was called!\n"); } +void MENU_StartMusic(){ + printf("Attempting to start menu music...\n"); + if (!Mix_PlayingMusic()) + Mix_FadeInMusic(MenuLoop, -1, MAIN_FadeTime); + else printf("Menu music is already playing!\n"); +} + +void MENU_PauseMusic(){ + printf("Attempting to pause menu music...\n"); + if (Mix_PlayingMusic()) + Mix_HaltMusic(); + // Mix_FadeOutMusic(MAIN_FadeTime); + else printf("There is no menu music to be paused!\n"); +} + void GAME_ChangeState(GameState state){ + if (state == Game) { + printf("Game music starting!\n"); + MENU_PauseMusic(); + BREAKOUT_StartMusic(); + } else { + printf("Menu music starting!\n"); + BREAKOUT_PauseMusic(); + MENU_StartMusic(); + } if (gameState == state) { printf("State wasn't changed!\n"); return; } gameState = state; switch (gameState) { + case Game: + BALL_ResetPosition(&(scenery.ball)); + break; case Highscores: HIGHSCORES_ReloadList(); HIGHSCORES_GenerateTexture(renderer); @@ -84,7 +261,7 @@ void GAME_ChangeState(GameState state){ printf("State was changed to %d!\n", gameState); break; } -} +} /* GAME_ChangeState */ void HandleSDLEvents(){ while (SDL_PollEvent(&event)) { @@ -110,6 +287,14 @@ void HandleSDLEvents(){ } /* HandleSDLEvents */ void mousePress(SDL_MouseButtonEvent b){ // Debug prop + switch (gameState) { + case GameOver: + GAMEOVER_MouseClicked(b, &scenery); + break; + default: + printf("Gamestate currently ignores Mouse press event: %d!\n", gameState); + break; + } if (b.button == SDL_BUTTON_LEFT) { printf("Left mouse pressed at %d, %d\n", b.x, b.y); } else if (b.button == SDL_BUTTON_RIGHT) { @@ -123,6 +308,14 @@ void keyPress(SDL_KeyboardEvent b){ // Debug prop printf("Key pressed: ID is %d\n", b.keysym.scancode); if (b.keysym.scancode == SDL_SCANCODE_F11 || b.keysym.scancode == SDL_SCANCODE_5) { toggleFullscreen(); + } else { + switch (gameState) { + case Game: + BREAKOUT_KeyPressed(&scenery, &b); + break; + default: + break; + } } } @@ -152,7 +345,7 @@ void DrawBackground(SDL_Renderer * renderer){ SDL_RenderClear(renderer); } /* DrawFrame */ -void INITIALIZE() { +void INITIALIZE(){ printf("Initializing started...\n"); srand(time(NULL)); if (SDL_Init(SDL_INIT_EVERYTHING) != 0) printf("SDL could not initialize! Error: %s\n", SDL_GetError()); @@ -162,26 +355,38 @@ void INITIALIZE() { else printf("IMG was successfully initialized!\n"); if (TTF_Init() == -1) printf("TTF could not initialize! Error: %s\n", TTF_GetError()); else printf("TTF was successfully initialized!\n"); + if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0) printf("Mixer could not initialize! Error %s\n", Mix_GetError()); + else printf("Mixer was successfully initialized!\n"); window = SDL_CreateWindow("BreakING", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_OPENGL); SDL_SetWindowResizable(window, true); + SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP); printf("Window was created!\n"); renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); printf("Renderer was created!\n"); - BREAKOUT_INITIALIZE(renderer, width, height); + BREAKOUT_INITIALIZE(renderer); scenery = BREAKOUT_CreateDefault(); Load_Textures(renderer); HIGHSCORES_Initialize(); - Settings_Initialize(renderer); + BACKGROUND_Initialize(renderer, width, height); + Settings_Initialize(renderer, &scenery); + GAMEOVER_Initialize(renderer); + MenuLoop = Mix_LoadMUS(MAIN_MenuMusicPath); printf("Initializing finished!\n"); } /* INITIALIZE */ void QUIT(){ printf("De-initializing started...\n"); + free(Username); + free(Password); + Mix_FreeMusic(MenuLoop); + GAMEOVER_Deinitialize(); + BACKGROUND_Deinitialize(); Settings_Deinitialize(); HIGHSCORES_Deinitialize(); BREAKOUT_DestroyObject(&scenery); BREAKOUT_DEINITIALIZE(); + Mix_CloseAudio(); TTF_Quit(); IMG_Quit(); printf("Quitting SDL_IMG finished!\n"); @@ -193,28 +398,3 @@ 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 index c2b62b9..b5c7892 100644 --- a/main.h +++ b/main.h @@ -15,6 +15,9 @@ #include "startmenu.h" #include "gamestate.h" #include "highscores.h" +#include "gameover.h" +#include "settings.h" +#include "background.h" #ifndef __nullptr__ #define Nullptr(type) (type *)0 @@ -26,9 +29,18 @@ #define ss "\341" // Prototypes +bool PushNewCredentialsToSaveFile(const char * filename); +bool GrabAccountFromSaveFile(const char * filename); +void GAME_ReadCredentials(); +bool GAME_Login(); +bool GAME_Register(); +void AttemptLogin(); +int readIntFromIO(char * m1, char * m2, char * m3, int min, int max); +void GAME_Escape(); +void MENU_StartMusic(); +void MENU_PauseMusic(); void GAME_ChangeState(GameState state); void HandleSDLEvents(); -void GAME_Escape(); void mousePress(SDL_MouseButtonEvent b); void keyPress(SDL_KeyboardEvent b); void toggleFullscreen(); @@ -36,7 +48,6 @@ 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/old/settings.c b/old/settings.c new file mode 100644 index 0000000..70842ba --- /dev/null +++ b/old/settings.c @@ -0,0 +1,110 @@ +#include +#include +#include +#include +#include + +#include "settings.h" + +#define Slider_height 100 +#define Scalar_width 20 +#define Bar_width 400 +#define round(x) ((int) ((x) + .5)) +#define distance(x1,y1,x2,y2) ((int)(sqrt(pow(x2-x1,2)+pow(y2-y1,2)))) + +SDL_Texture* Settings_Texture; +SDL_Texture* Settings_Return_Button_Texture; + +SDL_Rect Settings_rect; +SDL_Rect Settings_Return_Button_rect; +Slider BV; +Slider BS; +Slider BT; +Uint32 Mousestate; +bool Settings_IsInit=false; + +void Settings_Initialize (SDL_Renderer* renderer,Scenery* scenery) { + Initialize_Slider(400,300,Scalar_width,Bar_width,Slider_height,1,2,&BV,1.5); + Initialize_Slider(400,500,Scalar_width,Bar_width,Slider_height,30,100,&BS,scenery->ball.TargetRect.w); + Initialize_Slider(400,700,Scalar_width,Bar_width,Slider_height,0,8,&BT,scenery->ball.TextureIndex); + Settings_Texture = IMG_LoadTexture(renderer, "assets/images/settings_title.png"); + Settings_rect = (SDL_Rect){.x = 800, .y = 180, .w=313, .h=100}; + Settings_Return_Button_Texture = IMG_LoadTexture(renderer, "assets/images/return_button.png"); + Settings_Return_Button_rect = (SDL_Rect){.x = 200, .y = 200, .w=75, .h=75}; + Settings_IsInit = true; +} + +void Settings_Draw (SDL_Renderer* renderer,Scenery* scenery) { + double x; + scenery->ball.TargetRect.x=900; + scenery->ball.TargetRect.y=700; + SDL_RenderCopy(renderer, Settings_Texture, NULL, &Settings_rect); + SDL_RenderCopy(renderer, Settings_Return_Button_Texture, NULL, &Settings_Return_Button_rect); + Draw_Slider(renderer,&BV); + Draw_Slider(renderer,&BS); + Draw_Slider(renderer,&BT); + Draw_Ballstate(renderer,scenery); + mapping(&x,&BT); + scenery->ball.TextureIndex=round(x); + mapping(&x,&BS); + scenery->ball.TargetRect.w=x; + scenery->ball.TargetRect.h=x; + Settings_Return(); +} + +void Settings_Deinitialize(){ + if(Settings_IsInit){ + SDL_DestroyTexture(Settings_Texture); + SDL_DestroyTexture(Settings_Ball_Texture); + Settings_IsInit=false; + } +} + +void Draw_Slider(SDL_Renderer* renderer,Slider* beta){ + SDL_SetRenderDrawColor(renderer,255,255,255,255); + SDL_RenderDrawRect(renderer,&beta->Bar_rect); + int x,y; + Mousestate=SDL_GetMouseState(&x,&y); + if(y<=((beta->Bar_rect.y)+(beta->Bar_rect.h))&&y>=(beta->Bar_rect.y)&&x<=(beta->Bar_rect.w+beta->Bar_rect.x)&&x>=(beta->Bar_rect.x)&&(Mousestate & SDL_BUTTON(SDL_BUTTON_LEFT))){ + SDL_RenderFillRect(renderer,&beta->Scalar_rect); + SDL_RenderDrawRect(renderer,&beta->Scalar_rect); + if(x>(beta->Bar_rect.x+beta->Bar_rect.w-(beta->Scalar_rect.w)/2)){ + beta->Scalar_rect.x=(beta->Bar_rect.x+beta->Bar_rect.w-(beta->Scalar_rect.w)); + beta->Slider_value=(beta->Bar_rect.x+beta->Bar_rect.w-(beta->Scalar_rect.w)/2); + } + else if(xBar_rect.x+(beta->Scalar_rect.w)/2){ + beta->Scalar_rect.x=beta->Bar_rect.x; + beta->Slider_value=beta->Bar_rect.x+(beta->Scalar_rect.w)/2; + } + else{ + beta->Scalar_rect.x=x-(beta->Scalar_rect.w/2); + beta->Slider_value=x; + } + } + else{ + SDL_RenderDrawRect(renderer,&beta->Scalar_rect); + } +} + +void Draw_Ballstate(SDL_Renderer* renderer,Scenery* scenery){ + BALL_Draw(renderer, &(scenery->ball)); +} + +void mapping(double *x,Slider* beta){ + *x=((beta->max-beta->min)/(beta->Bar_rect.w-(beta->Scalar_rect.w)))*(beta->Slider_value-beta->Bar_rect.x-beta->Scalar_rect.w/2)+beta->min; +} + +void Initialize_Slider(int x,int y,int sw,int bw,int h,double min,double max,Slider* beta,double defaultvalue){ + beta->Scalar_rect = (SDL_Rect){.x=(defaultvalue-min)/(max-min)*(bw-sw/2)+x,.y=y,.w=sw,.h=h}; + beta->Bar_rect = (SDL_Rect){.x=x,.y=y,.w=bw,.h=h}; + beta->max=max; + beta->min=min; + beta->Slider_value=(defaultvalue-min)/(max-min)*(bw-sw/2)+x; +} + +void Settings_Return(Scenery* scenery){ + int x,y; + Mousestate=SDL_GetMouseState(&x,&y); + if((distance(x,y,237,237)<=37)&&(Mousestate & SDL_BUTTON(SDL_BUTTON_LEFT))) + GAME_ChangeState(MainMenu); +} diff --git a/old/settings.h b/old/settings.h new file mode 100644 index 0000000..c1a518b --- /dev/null +++ b/old/settings.h @@ -0,0 +1,38 @@ +#ifndef __Settings__ + +#define __Settings__ + +#include +#include +#include +#include +#include +#include +#include "breakout.h" +#include "gamestate.h" +#include "main.h" + +typedef struct sliderstruct { + SDL_Rect Bar_rect; + SDL_Rect Scalar_rect; + double Slider_value,min,max; +} Slider; + + +void Settings_Draw (SDL_Renderer* renderer,Scenery* scenery); + +void Draw_Slider(SDL_Renderer* renderer,Slider* beta); + +void Draw_Ballstate(SDL_Renderer* renderer,Scenery* scenery); + +void Settings_Initialize (SDL_Renderer* renderer,Scenery* scenery); + +void Initialize_Slider(int x,int y,int sw,int bw,int h,double min,double max,Slider* beta,double defaultvalue); + +void Settings_Deinitialize(); + +void mapping(double *x,Slider* beta); + +void Settings_Return(); + +#endif diff --git a/paddle.c b/paddle.c deleted file mode 100644 index e69de29..0000000 diff --git a/settings.c b/settings.c index ea4baa7..f94da7a 100644 --- a/settings.c +++ b/settings.c @@ -3,60 +3,177 @@ #include #include #include +#include + +#include "settings.h" + +extern float XScale, YScale; + +#define Slider_height 100 +#define Scalar_width 20 +#define Bar_width 400 +#define round(x) ((int)((x) + .5)) +#define distance(x1,y1,x2,y2) ((int)(sqrt(pow(x2-x1,2)+pow(y2-y1,2)))) + +SDL_Texture * Settings_Texture; +SDL_Texture * Settings_Ball_Texture; +SDL_Texture * Settings_Skins_Texture; +SDL_Texture * Return_Button_Texture; +SDL_Texture * Bar_Texture; +SDL_Texture * Scalar_Button_Texture0; +SDL_Texture * Scalar_Button_Texture1; +SDL_Texture * L_Arrow_Texture; +SDL_Texture * R_Arrow_Texture; -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; +SDL_Rect Settings_Ball_rect; +SDL_Rect Settings_Skins_rect; +SDL_Rect Return_Button_rect; -bool Settings_IsInit=false; +Slider BV; +Slider BS; +Slider BT; +Stepslider SBT; + +Uint32 Mousestate; + +bool Settings_IsInit = false; +bool IsLock=false; + +void Settings_Initialize (SDL_Renderer* renderer,Scenery* scenery) { + // Initialize_Slider(400,300,Scalar_width,Bar_width,Slider_height,1,2,&BV,1.5); + Initialize_Slider(400,500,Scalar_width,Bar_width,Slider_height,30,100,&BS,scenery->ball.TargetRect.w); + Initialize_Slider(400,700,Scalar_width,Bar_width,Slider_height,0,8,&BT,scenery->ball.TextureIndex); + Initialize_Stepslider(400,300,Scalar_width,Bar_width,Slider_height,0,8,&SBT,scenery->ball.TextureIndex); + Settings_Texture = IMG_LoadTexture(renderer, "assets/images/settings_title.png"); + Settings_rect = (SDL_Rect){.x = 647, .y = 50, .w=626, .h=200}; + + Settings_Ball_rect = (SDL_Rect){.x = 1200, .y = 700, .w=90, .h=90}; + + Settings_Skins_Texture = IMG_LoadTexture(renderer, "assets/images/skins_button.png"); + Settings_Skins_rect = (SDL_Rect){.x = 50, .y = 710, .w=315, .h=70}; + + Return_Button_Texture = IMG_LoadTexture(renderer, "assets/images/return_button.png"); + Return_Button_rect = (SDL_Rect){.x = 200, .y = 200, .w=75, .h=75}; + + Bar_Texture = IMG_LoadTexture(renderer, "assets/images/bar_texture.png"); + Scalar_Button_Texture0 = IMG_LoadTexture(renderer, "assets/images/scalar_button_unpressed.png"); + Scalar_Button_Texture1 = IMG_LoadTexture(renderer, "assets/images/scalar_button_pressed.png"); + + R_Arrow_Texture = IMG_LoadTexture(renderer, "assets/images/r_arrow_button.png" ); + L_Arrow_Texture = IMG_LoadTexture(renderer, "assets/images/l_arrow_button.png" ); -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; +void Settings_Draw(SDL_Renderer * renderer, Scenery * scenery) { + double x; + if(!(Mousestate & SDL_BUTTON(SDL_BUTTON_LEFT))){ + IsLock=BV.IsLock=BS.IsLock=BT.IsLock=false; + }else{ + IsLock=true; } - 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); + // Draw_Slider(renderer, &BV); + Draw_Slider(renderer, &BS); + Draw_Slider(renderer, &BT); + Draw_Stepslider(renderer, &SBT); + SDL_RenderCopy(renderer, Settings_Texture, NULL, &Settings_rect); + SDL_RenderCopy(renderer, Return_Button_Texture, NULL, &Return_Button_rect); + SDL_RenderCopy(renderer, Settings_Skins_Texture, NULL, &Settings_Skins_rect); + BALL_DrawTexture(renderer, &Settings_Ball_rect, scenery->ball.TextureIndex); + Settings_Return(); + mapping(&x, &BS); + scenery->ball.TargetRect.w = x; + scenery->ball.TargetRect.h = x; + scenery->ball.Size = ((double)x / 2.0f); + mapping(&x, &BT); + x = round(x); + scenery->ball.TextureIndex = x; } void Settings_Deinitialize(){ - if(Settings_IsInit){ - SDL_DestroyTexture(Setting_Texture); - Settings_IsInit=false; + if (Settings_IsInit) { + SDL_DestroyTexture(Settings_Texture); + SDL_DestroyTexture(Settings_Ball_Texture); + SDL_DestroyTexture(Bar_Texture); + SDL_DestroyTexture(Return_Button_Texture); + SDL_DestroyTexture(Settings_Skins_Texture); + SDL_DestroyTexture(Scalar_Button_Texture0); + SDL_DestroyTexture(Scalar_Button_Texture1); + Settings_IsInit = false; + } +} + +void Draw_Slider(SDL_Renderer * renderer, Slider * beta){ + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + SDL_RenderCopy(renderer, Bar_Texture, NULL, &beta->Bar_rect); + int x, y; + Mousestate = SDL_GetMouseState(&x, &y); + x = round((float)x / XScale); + y = round((float)y / YScale); + if ((y <= ((beta->Bar_rect.y) + (beta->Bar_rect.h)) && y >= (beta->Bar_rect.y) && x <= (beta->Bar_rect.w + beta->Bar_rect.x) && x >= (beta->Bar_rect.x) && (Mousestate & SDL_BUTTON(SDL_BUTTON_LEFT)))||beta->IsLock) { + if(!IsLock){ + beta->IsLock=true; + IsLock=true; + } + if(beta->IsLock){ + SDL_RenderCopy(renderer, Scalar_Button_Texture1, NULL, &beta->Scalar_rect); + if (x > (beta->Bar_rect.x + beta->Bar_rect.w - (beta->Scalar_rect.w) / 2)) { + beta->Scalar_rect.x = (beta->Bar_rect.x + beta->Bar_rect.w - (beta->Scalar_rect.w)); + beta->Slider_value = (beta->Bar_rect.x + beta->Bar_rect.w - (beta->Scalar_rect.w) / 2); + } else if (x < beta->Bar_rect.x + (beta->Scalar_rect.w) / 2) { + beta->Scalar_rect.x = beta->Bar_rect.x; + beta->Slider_value = beta->Bar_rect.x + (beta->Scalar_rect.w) / 2; + } else { + beta->Scalar_rect.x = x - (beta->Scalar_rect.w / 2); + beta->Slider_value = x; + } + } else { + SDL_RenderCopy(renderer, Scalar_Button_Texture0, NULL, &beta->Scalar_rect); + } + } else { + SDL_RenderCopy(renderer, Scalar_Button_Texture0, NULL, &beta->Scalar_rect); + } +} /* Draw_Slider */ + +void Draw_Stepslider(SDL_Renderer* renderer,Stepslider* beta){ + SDL_RenderCopy(renderer, Bar_Texture, NULL, &beta->Bar_rect); + SDL_RenderCopy(renderer, Scalar_Button_Texture0, NULL, &beta->Scalar_rect); + SDL_RenderCopy(renderer, L_Arrow_Texture, NULL, &beta->L_Arrow_rect); + SDL_RenderCopy(renderer, R_Arrow_Texture, NULL, &beta->R_Arrow_rect); +} + +void mapping(double * x, Slider * beta){ + *x = ((beta->max - beta->min) / (beta->Bar_rect.w - (beta->Scalar_rect.w))) * (beta->Slider_value - beta->Bar_rect.x - beta->Scalar_rect.w / 2) + beta->min; +} + +void Initialize_Slider(int x, int y, int sw, int bw, int h, double min, double max, Slider * beta,double defaultvalue){ + beta->Scalar_rect = (SDL_Rect) {.x = (defaultvalue-min)/(max-min)*(bw-sw/2)+x, .y = y, .w = sw, .h = h }; + beta->Bar_rect = (SDL_Rect) {.x = x, .y = y, .w = bw, .h = h }; + beta->max = max; + beta->min = min; + beta->Slider_value = (defaultvalue-min)/(max-min)*(bw-sw/2)+x; +} + +void Initialize_Stepslider(int x,int y,int sw,int bw,int h,double min,double max,Stepslider* beta,double defaultvalue){ + beta->Scalar_rect = (SDL_Rect) {.x = (defaultvalue-min)/(max-min)*(bw-sw/2)+x, .y = y, .w = sw, .h = h }; + beta->Bar_rect = (SDL_Rect) {.x = x, .y = y, .w = bw, .h = h }; + beta->L_Arrow_rect = (SDL_Rect) {.x = x-30-h, .y = y, .w = h, .h = h }; + beta->R_Arrow_rect = (SDL_Rect) {.x = x+bw+30, .y = y, .w = h, .h = h }; + beta->max = max; + beta->min = min; + beta->Slider_value = (defaultvalue-min)/(max-min)*(bw-sw/2)+x; +} + +void Settings_Return(){ + if(!IsLock){ + int x,y; + Mousestate=SDL_GetMouseState(&x,&y); + x = round((float)x / XScale); + y = round((float)y / YScale); + if((distance(x,y,237,237)<=37)&&(Mousestate & SDL_BUTTON(SDL_BUTTON_LEFT))) + GAME_ChangeState(MainMenu); } } diff --git a/settings.h b/settings.h index 9234bf2..c8bef88 100644 --- a/settings.h +++ b/settings.h @@ -7,12 +7,43 @@ #include #include #include +#include "breakout.h" +#include "gamestate.h" +#include "main.h" + +typedef struct sliderstruct { + SDL_Rect Bar_rect; + SDL_Rect Scalar_rect; + bool IsLock; + double Slider_value,min,max; +} Slider; + +typedef struct stepsliderstruct { + SDL_Rect Bar_rect; + SDL_Rect Scalar_rect; + SDL_Rect L_Arrow_rect; + SDL_Rect R_Arrow_rect; + bool IsLock; + double Slider_value,min,max; +} Stepslider; -void Settings_Initialize (SDL_Renderer* renderer); +void Settings_Draw (SDL_Renderer* renderer,Scenery* scenery); -void Settings_Draw (SDL_Renderer* renderer); +void Draw_Slider(SDL_Renderer* renderer,Slider* beta); + +void Draw_Stepslider(SDL_Renderer* renderer,Stepslider* beta); + +void Settings_Initialize (SDL_Renderer* renderer,Scenery* scenery); + +void Initialize_Slider(int x,int y,int sw,int bw,int h,double min,double max,Slider* beta,double defaultvalue); + +void Initialize_Stepslider(int x,int y,int sw,int bw,int h,double min,double max,Stepslider* beta,double defaultvalue); void Settings_Deinitialize(); +void mapping(double *x,Slider* beta); + +void Settings_Return(); + #endif diff --git a/startmenu.c b/startmenu.c index 4fdc72a..cc6dbc2 100644 --- a/startmenu.c +++ b/startmenu.c @@ -5,11 +5,11 @@ #include "gamestate.h" #include "main.h" +extern float XScale, YScale; +extern SDL_Rect Return_Button_rect; 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; @@ -17,13 +17,15 @@ 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)))); + int clickx, clicky; + + clickx = (int)roundf((float)b.x / XScale); + clicky = (int)roundf((float)b.y / YScale); + return ((clickx >= (area_rect->x)) && (clickx <= ((area_rect->x) + (area_rect->w))) && (clicky >= (area_rect->y)) && (clicky <= ((area_rect->y) + (area_rect->h)))); } void Load_Textures(SDL_Renderer * renderer) { @@ -31,16 +33,10 @@ void Load_Textures(SDL_Renderer * renderer) { 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 }; + PLAYBUTTON_Rect = (SDL_Rect) {.x = 772, .y = 420, .w = 376, .h = 214 }; SETTINGSBUTTON_Texture = IMG_LoadTexture(renderer, "assets/images/settings_button.png"); - SETTINGSBUTTON_Rect = (SDL_Rect) {.x = 1110, .y = 700, .w = 313, .h = 178 }; + SETTINGSBUTTON_Rect = (SDL_Rect) {.x = 772, .y = 720, .w = 376, .h = 214 }; HIGHSCORESBUTTON_Texture = IMG_LoadTexture(renderer, "assets/images/highscores_button.png"); HIGHSCORESBUTTON_Rect = (SDL_Rect) {.x = 1557, .y = 120, .w = 313, .h = 178 }; @@ -52,8 +48,6 @@ void Load_Textures(SDL_Renderer * renderer) { 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); @@ -63,10 +57,6 @@ 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) { diff --git a/vector.c b/vector.c index b4ec420..5afc5c3 100644 --- a/vector.c +++ b/vector.c @@ -6,7 +6,7 @@ const double degreeToRadians = M_PI / 180.0f; // End Properties -Vector vectorScale(Vector v, double factor){ +Vector VECTOR_ScaleBy(Vector v, double factor){ return (Vector) { .x = v.x * factor, @@ -14,30 +14,30 @@ Vector vectorScale(Vector v, double factor){ }; } -double vectorMagnitude(Vector v){ +double VECTOR_GetMagnitude(Vector v){ return sqrt((v.x * v.x) + (v.y * v.y)); } -double vectorRotation(Vector v){ +double VECTOR_GetRotation(Vector v){ double da = atan2(v.x, -v.y) / degreeToRadians; if (da < 0.0f) return (da + 360.0f); else return da; } -Vector vectorScaleTo(Vector v, double magnitude){ - return vectorScale(v, magnitude / vectorMagnitude(v)); +Vector VECTOR_ChangeScaleTo(Vector v, double magnitude){ + return VECTOR_ScaleBy(v, magnitude / VECTOR_GetMagnitude(v)); } -double dotProduct(Vector v1, Vector v2){ +double VECTOR_DotProduct(Vector v1, Vector v2){ return (v1.x * v2.x ) + (v1.y * v2.y); } -double vectorDist(Vector v1, Vector v2){ - return sqrt(dotProduct(v1, v2)); +double VECTOR_Distance(Vector v1, Vector v2){ + return sqrt(VECTOR_DotProduct(v1, v2)); } -Vector vectorAdd(Vector v1, Vector v2){ +Vector VECTOR_Add(Vector v1, Vector v2){ return (Vector) { .x = v1.x + v2.x, @@ -45,7 +45,7 @@ Vector vectorAdd(Vector v1, Vector v2){ }; } -Vector vectorSub(Vector v1, Vector v2){ +Vector VECTOR_Subtract(Vector v1, Vector v2){ return (Vector) { .x = v1.x - v2.x, @@ -61,7 +61,7 @@ double degreeCos(double x){ return cos(x * degreeToRadians); } -Vector getDirectionalUnitVector(double rotation){ +Vector VECTOR_GetDirectionalUnitVector(double rotation){ return (Vector) { .x = degreeSin(rotation), @@ -69,16 +69,20 @@ Vector getDirectionalUnitVector(double rotation){ }; } -Vector getScaledDirectionalUnitVector(double rotation, double Magnitude){ +Vector VECTOR_GetScaledDirectionalUnitVector(double rotation, double Magnitude){ Vector v = (Vector) { .x = degreeSin(rotation), .y = -degreeCos(rotation) }; - return vectorScale(v, Magnitude); + return VECTOR_ScaleBy(v, Magnitude); } -Vector getScaledVectorFromTo(Vector from, Vector to, double Magnitude){ - return vectorScale(vectorSub(to, from), Magnitude); +Vector VECTOR_GetScaledVectorFromTo(Vector from, Vector to, double Magnitude){ + return VECTOR_ChangeScaleTo(VECTOR_Subtract(to, from), Magnitude); +} + +Vector VECTOR_GetVectorFromTo(Vector from, Vector to){ + return VECTOR_Subtract(to, from); } diff --git a/vector.h b/vector.h index 2bbaf4d..f4b3896 100644 --- a/vector.h +++ b/vector.h @@ -8,19 +8,20 @@ typedef struct vectorStruct { // End Structs // Prototypes -Vector vectorScale(Vector v, double factor); -double vectorMagnitude(Vector v); -double vectorRotation(Vector v); -Vector vectorScaleTo(Vector v, double magnitude); -double dotProduct(Vector v1, Vector v2); -double vectorDist(Vector v1, Vector v2); -Vector vectorAdd(Vector v1, Vector v2); -Vector vectorSub(Vector v1, Vector v2); +Vector VECTOR_ScaleBy(Vector v, double factor); +double VECTOR_GetMagnitude(Vector v); +double VECTOR_GetRotation(Vector v); +Vector VECTOR_ChangeScaleTo(Vector v, double magnitude); +double VECTOR_DotProduct(Vector v1, Vector v2); +double VECTOR_Distance(Vector v1, Vector v2); +Vector VECTOR_Add(Vector v1, Vector v2); +Vector VECTOR_Subtract(Vector v1, Vector v2); double degreeSin(double x); double degreeCos(double x); -Vector getDirectionalUnitVector(double rotation); -Vector getScaledDirectionalUnitVector(double rotation, double Magnitude); -Vector getScaledVectorFromTo(Vector from, Vector to, double Magnitude); +Vector VECTOR_GetDirectionalUnitVector(double rotation); +Vector VECTOR_GetScaledDirectionalUnitVector(double rotation, double Magnitude); +Vector VECTOR_GetScaledVectorFromTo(Vector from, Vector to, double Magnitude); +Vector VECTOR_GetVectorFromTo(Vector from, Vector to); // End Prototypes #endif // __vector_h__