diff --git a/src/constants.h b/src/constants.h index 0864439..39ec957 100644 --- a/src/constants.h +++ b/src/constants.h @@ -22,11 +22,11 @@ constexpr int APPLE_COORDS[4] = {513, 0, 250, 251}; constexpr int BROCCOLI_COORDS[4] = {767, 2, 268, 153}; constexpr int BANANA_COORDS[4] = {525, 254, 189, 355}; -constexpr float CORN_EYE_OFFSET[2] = {-10, 0}; +constexpr float CORN_EYE_OFFSET[2] = {-0.01F, 0}; constexpr float GRAPES_EYE_OFFSET[2] = {0, 0}; constexpr float APPLE_EYE_OFFSET[2] = {0, 0}; constexpr float BROCCOLI_EYE_OFFSET[2] = {0, 0}; -constexpr float BANANA_EYE_OFFSET[2] = {40, 0}; +constexpr float BANANA_EYE_OFFSET[2] = {0.2F, 0}; constexpr float EYE_WIDTH_RATIO = 0.3F; @@ -44,8 +44,14 @@ constexpr float MIN_BLINK_TIME = 1.0F; constexpr float MAX_BLINK_TIME = 20.0F; constexpr float BLINK_DURATION = 0.7F; -constexpr float CUT_TIMER_RATE = 1.0F; +constexpr float CUT_RATE = 0.7F; -constexpr float CUT_TIMER_RATE_INC_AMT = 0.03F; +constexpr float CUT_TIMER_RATE_INC_AMT = 0.1F; + +constexpr float SPLIT_DX = 60.0F; +constexpr float SPLIT_DY = 100.0F; +constexpr float SPLIT_DA = 80.0F; + +constexpr float POST_CUT_TIME = 1.7F; #endif diff --git a/src/game.cc b/src/game.cc index dd03827..df07ab1 100644 --- a/src/game.cc +++ b/src/game.cc @@ -11,8 +11,9 @@ Game::Game() : re(std::random_device{}()), dist(0, FOOD_COUNT - 1), score(0), areaSizeRatio(1.0F), currentFood(dist(re)), blinkTimer(10.0F), - cutTimer(0.0F), cutTimerRateInc(1.0F) { + cutTimer(0.0F), cutTimerRateInc(1.0F), postCutTimer(0.0F) { flags.set(0); + flags.set(3); spriteSheet = LoadTexture("resources/produceStuff.png"); } @@ -35,8 +36,8 @@ void Game::update_impl() { for (unsigned long long i = score; i > 0; i /= 10) { temp.push_back((i % 10) + '0'); } - for (auto c : temp) { - scoreString.push_back(c); + for (int i = temp.size(); i-- > 0;) { + scoreString.push_back(temp[i]); } } } @@ -52,136 +53,180 @@ void Game::update_impl() { } } - cutTimer += dt * CUT_TIMER_RATE * cutTimerRateInc; - if (cutTimer > 1.0F) { - cutTimer -= 1.0F; + if (flags.test(3)) { + flags.reset(3); + switch (currentFood) { + case (unsigned int)FoodType::FT_APPLE: + ratio = (float)APPLE_COORDS[2] / (float)APPLE_COORDS[3]; + break; + case (unsigned int)FoodType::FT_BANANA: + ratio = (float)BANANA_COORDS[2] / (float)BANANA_COORDS[3]; + break; + case (unsigned int)FoodType::FT_BROCCOLI: + ratio = (float)BROCCOLI_COORDS[2] / (float)BROCCOLI_COORDS[3]; + break; + case (unsigned int)FoodType::FT_CORN: + ratio = (float)CORN_COORDS[2] / (float)CORN_COORDS[3]; + break; + case (unsigned int)FoodType::FT_GRAPES: + ratio = (float)GRAPES_COORDS[2] / (float)GRAPES_COORDS[3]; + break; + default: + ratio = 1.0F; + break; + } + + if (ratio < 1.0F) { + height = MAX_FOOD_WH; + width = height * ratio; + } else { + width = MAX_FOOD_WH; + height = width / ratio; + } + + if (width > GetScreenWidth() && height <= GetScreenHeight()) { + if (ratio < 1.0F) { + height = GetScreenWidth() / ratio; + width = height * ratio; + } else { + width = GetScreenWidth(); + height = width / ratio; + } + } else if (width <= GetScreenWidth() && height > GetScreenHeight()) { + if (ratio < 1.0F) { + height = GetScreenHeight(); + width = height * ratio; + } else { + width = GetScreenHeight() * ratio; + height = width / ratio; + } + } + offsetX = (GetScreenWidth() - width) / 2.0F; + offsetY = (GetScreenHeight() - height) / 2.0F; + } + + if (!flags.test(4)) { + cutTimer += dt * CUT_RATE * cutTimerRateInc; + if (cutTimer > 1.0F) { + cutTimer -= 1.0F; + } + } + + cutPos = cutTimer * height + offsetY - height / 3.0F; + + if (!flags.test(4) && IsMouseButtonPressed(0)) { + flags.set(4); + if (cutPos >= offsetY && cutPos <= offsetY + height / 3.0F) { + // in correct range + flags.set(2); + ++score; + flags.set(0); + } else if (cutPos > offsetY + height / 3.0F) { + // past range + flags.set(5); + postCutTimer = POST_CUT_TIME; + } else { + // before range + postCutTimer = POST_CUT_TIME; + } + + if (flags.test(4) && (flags.test(2) || flags.test(5)) && !flags.test(6)) { + flags.set(6); + relativeCutRatio = (cutPos - offsetY) / height; + splitX = offsetX; + splitY = offsetY; + splitAngle = 0.0F; + splitDX = std::uniform_real_distribution(-SPLIT_DX, SPLIT_DX)(re); + splitDY = std::uniform_real_distribution(-SPLIT_DY, SPLIT_DY)(re); + splitDAngle = + std::uniform_real_distribution(-SPLIT_DA, SPLIT_DA)(re); + postCutTimer = POST_CUT_TIME; + cutTimerRateInc += CUT_TIMER_RATE_INC_AMT; + } + } + + if (flags.test(6)) { + splitX += splitDX * dt; + splitY += splitDY * dt; + splitAngle += splitDAngle * dt; + } + if (postCutTimer > 0.0F) { + postCutTimer -= dt; + if (postCutTimer <= 0.0F) { + reset(!flags.test(2)); + } } } void Game::draw_impl() { - BeginDrawing(); ClearBackground(RAYWHITE); - float ratio; - float width; - float height; - float offsetX; - float offsetY; + int coords[4]; + Helpers::get_fruit_coords(coords, (FoodType)currentFood); - switch (currentFood) { - case (unsigned int)FoodType::FT_APPLE: - ratio = (float)APPLE_COORDS[2] / (float)APPLE_COORDS[3]; - break; - case (unsigned int)FoodType::FT_BANANA: - ratio = (float)BANANA_COORDS[2] / (float)BANANA_COORDS[3]; - break; - case (unsigned int)FoodType::FT_BROCCOLI: - ratio = (float)BROCCOLI_COORDS[2] / (float)BROCCOLI_COORDS[3]; - break; - case (unsigned int)FoodType::FT_CORN: - ratio = (float)CORN_COORDS[2] / (float)CORN_COORDS[3]; - break; - case (unsigned int)FoodType::FT_GRAPES: - ratio = (float)GRAPES_COORDS[2] / (float)GRAPES_COORDS[3]; - break; - default: - ratio = 1.0F; - break; - } - - if (ratio < 1.0F) { - height = MAX_FOOD_WH; - width = height * ratio; + if (flags.test(6)) { + // bottom portion + DrawTexturePro( + spriteSheet, + {(float)coords[0], (float)coords[1] + coords[3] * relativeCutRatio, + (float)coords[2], (float)coords[3] * (1.0F - relativeCutRatio)}, + {offsetX, offsetY + height * relativeCutRatio, width, + height * (1.0F - relativeCutRatio)}, + {0.0F, 0.0F}, 0.0F, WHITE); + // top portion + DrawTexturePro( + spriteSheet, + {(float)coords[0], (float)coords[1], (float)coords[2], + (float)coords[3] * relativeCutRatio}, + {splitX + width / 2.0F, splitY + (height * relativeCutRatio / 2.0F), + width, height * relativeCutRatio}, + {width / 2.0F, height * relativeCutRatio / 2.0F}, splitAngle, WHITE); } else { - width = MAX_FOOD_WH; - height = width / ratio; - } - - if (width > GetScreenWidth() && height <= GetScreenHeight()) { - if (ratio < 1.0F) { - height = GetScreenWidth() / ratio; - width = height * ratio; - } else { - width = GetScreenWidth(); - height = width / ratio; - } - } else if (width <= GetScreenWidth() && height > GetScreenHeight()) { - if (ratio < 1.0F) { - height = GetScreenHeight(); - width = height * ratio; - } else { - width = GetScreenHeight() * ratio; - height = width / ratio; - } - } - offsetX = (GetScreenWidth() - width) / 2.0F; - offsetY = (GetScreenHeight() - height) / 2.0F; - - switch (currentFood) { - case (unsigned int)FoodType::FT_APPLE: - DrawTexturePro( - spriteSheet, - {APPLE_COORDS[0], APPLE_COORDS[1], APPLE_COORDS[2], APPLE_COORDS[3]}, - {offsetX, offsetY, width, height}, {0.0F, 0.0F}, 0.0F, WHITE); - break; - case (unsigned int)FoodType::FT_BANANA: DrawTexturePro(spriteSheet, - {BANANA_COORDS[0], BANANA_COORDS[1], BANANA_COORDS[2], - BANANA_COORDS[3]}, + {(float)coords[0], (float)coords[1], (float)coords[2], + (float)coords[3]}, {offsetX, offsetY, width, height}, {0.0F, 0.0F}, 0.0F, WHITE); - break; - case (unsigned int)FoodType::FT_BROCCOLI: - DrawTexturePro(spriteSheet, - {BROCCOLI_COORDS[0], BROCCOLI_COORDS[1], BROCCOLI_COORDS[2], - BROCCOLI_COORDS[3]}, - {offsetX, offsetY, width, height}, {0.0F, 0.0F}, 0.0F, - WHITE); - break; - case (unsigned int)FoodType::FT_CORN: - DrawTexturePro( - spriteSheet, - {CORN_COORDS[0], CORN_COORDS[1], CORN_COORDS[2], CORN_COORDS[3]}, - {offsetX, offsetY, width, height}, {0.0F, 0.0F}, 0.0F, WHITE); - break; - case (unsigned int)FoodType::FT_GRAPES: - DrawTexturePro(spriteSheet, - {GRAPES_COORDS[0], GRAPES_COORDS[1], GRAPES_COORDS[2], - GRAPES_COORDS[3]}, - {offsetX, offsetY, width, height}, {0.0F, 0.0F}, 0.0F, - WHITE); - break; - default: - break; } DrawRectangle(0, offsetY, GetScreenWidth(), height / 3.0F, {255, 255, 255, 127}); - float cutPos = cutTimer * height; - - DrawLine(0, cutPos + offsetY - height / 3.0F, GetScreenWidth(), - cutPos + offsetY - height / 3.0F, BLACK); + DrawLine(0, cutPos, GetScreenWidth(), cutPos, BLACK); Helpers::draw_eyes_full(offsetX + width / 2.0F, offsetY + height / 2.0F, - width, EYE_RADIUS, (FoodType)currentFood, + width, height, EYE_RADIUS, (FoodType)currentFood, flags.test(1)); if (flags.test(2)) { - Helpers::draw_happy_mouth(offsetX + width / 2.0F, offsetY + height / 2.0F, - MOUTH_RADIUS); + Helpers::draw_happy_mouth(offsetX + width / 2.0F, + offsetY + height / 2.0F * 1.1F, width, + MOUTH_RADIUS, (FoodType)currentFood); } DrawText(scoreString.c_str(), 2, 2, 32, BLACK); EndDrawing(); } -void Game::reset() { +void Game::reset(bool wasGameOver) { flags.set(0); - score = 0; + flags.reset(1); + flags.reset(2); + flags.set(3); + flags.reset(4); + flags.reset(5); + flags.reset(6); + if (wasGameOver) { + score = 0; + cutTimerRateInc = 1.0F; + } areaSizeRatio = 1.0F; - currentFood = dist(re); + unsigned int prevFood = currentFood; + while (prevFood == currentFood) { + currentFood = dist(re); + } blinkTimer = 10.0F; - cutTimer = 0.0F; + cutTimer = std::uniform_real_distribution(0.0F, 1.0F)(re); + postCutTimer = 0.0F; } diff --git a/src/game.h b/src/game.h index 12eb9d6..539426a 100644 --- a/src/game.h +++ b/src/game.h @@ -18,7 +18,7 @@ private: void update_impl(); void draw_impl(); - void reset(); + void reset(bool wasGameOver); std::default_random_engine re; std::uniform_int_distribution dist; @@ -29,6 +29,10 @@ private: * 0 - score dirty * 1 - is blinking * 2 - happy + * 3 - fruit dirty + * 4 - cut has happened + * 5 - sad + * 6 - relativeCutPos is set */ std::bitset<32> flags; float areaSizeRatio; @@ -37,6 +41,20 @@ private: float blinkTimer; float cutTimer; float cutTimerRateInc; + float ratio; + float width; + float height; + float offsetX; + float offsetY; + float cutPos; + float relativeCutRatio; + float splitX; + float splitY; + float splitAngle; + float splitDX; + float splitDY; + float splitDAngle; + float postCutTimer; }; #endif diff --git a/src/helpers.cc b/src/helpers.cc index c074355..e851380 100644 --- a/src/helpers.cc +++ b/src/helpers.cc @@ -9,26 +9,7 @@ // local includes #include "constants.h" -void Helpers::draw_eye(float x, float y, float radius) { - DrawCircle(x + 0.5F, y + 0.5F, radius, BLACK); - DrawCircleSector({x, y}, radius / 1.5F, 180.0F, 270.0F, 32, WHITE); -} - -void Helpers::draw_blinking_eye(float x, float y, float radius) { - DrawLineEx({x - radius, y}, {x + radius, y}, BLINKING_EYE_SIZE, BLACK); -} - -void Helpers::draw_open_mouth(float x, float y, float radius) { - DrawCircle(x, y, radius, BLACK); -} - -void Helpers::draw_happy_mouth(float x, float y, float radius) { - DrawCircleSector({x, y}, radius, -90.0F, 90.0F, 32, BLACK); -} - -void Helpers::draw_eyes_full(float x, float y, float width, float radius, - FoodType foodType, bool isBlinking) { - float offsets[2]; +void internal_get_offsets(float offsets[2], FoodType foodType) { switch (foodType) { case FoodType::FT_CORN: offsets[0] = CORN_EYE_OFFSET[0]; @@ -55,17 +36,47 @@ void Helpers::draw_eyes_full(float x, float y, float width, float radius, offsets[1] = 0.0F; break; } +} + +void Helpers::draw_eye(float x, float y, float radius) { + DrawCircle(x + 0.5F, y + 0.5F, radius, BLACK); + DrawCircleSector({x, y}, radius / 1.5F, 180.0F, 270.0F, 32, WHITE); +} + +void Helpers::draw_blinking_eye(float x, float y, float radius) { + DrawLineEx({x - radius, y}, {x + radius, y}, BLINKING_EYE_SIZE, BLACK); +} + +void Helpers::draw_open_mouth(float x, float y, float radius) { + DrawCircle(x, y, radius, BLACK); +} + +void Helpers::draw_happy_mouth(float x, float y, float width, float radius, + FoodType foodType) { + float offsets[2]; + internal_get_offsets(offsets, foodType); + + DrawCircleSector({x + offsets[0] * width, y}, radius, -90.0F, 90.0F, 32, + BLACK); +} + +void Helpers::draw_eyes_full(float x, float y, float width, float height, + float radius, FoodType foodType, bool isBlinking) { + float offsets[2]; + internal_get_offsets(offsets, foodType); const float eye_width = width * EYE_WIDTH_RATIO; if (isBlinking) { - draw_blinking_eye(x - eye_width / 2.0F + offsets[0], y + offsets[1], - radius); - draw_blinking_eye(x + eye_width / 2.0F + offsets[0], y + offsets[1], - radius); + draw_blinking_eye(x - eye_width / 2.0F + offsets[0] * width, + y + offsets[1] * height, radius); + draw_blinking_eye(x + eye_width / 2.0F + offsets[0] * width, + y + offsets[1] * height, radius); } else { - draw_eye(x - eye_width / 2.0F + offsets[0], y + offsets[1], radius); - draw_eye(x + eye_width / 2.0F + offsets[0], y + offsets[1], radius); + draw_eye(x - eye_width / 2.0F + offsets[0] * width, y + offsets[1] * height, + radius); + draw_eye(x + eye_width / 2.0F + offsets[0] * width, y + offsets[1] * height, + radius); } } @@ -84,3 +95,44 @@ float Helpers::get_cut_pos(float timer, FoodType foodType) { } return 0.0F; } + +void Helpers::get_fruit_coords(int coords[4], FoodType foodType) { + switch (foodType) { + case FoodType::FT_CORN: + coords[0] = CORN_COORDS[0]; + coords[1] = CORN_COORDS[1]; + coords[2] = CORN_COORDS[2]; + coords[3] = CORN_COORDS[3]; + break; + case FoodType::FT_GRAPES: + coords[0] = GRAPES_COORDS[0]; + coords[1] = GRAPES_COORDS[1]; + coords[2] = GRAPES_COORDS[2]; + coords[3] = GRAPES_COORDS[3]; + break; + case FoodType::FT_APPLE: + coords[0] = APPLE_COORDS[0]; + coords[1] = APPLE_COORDS[1]; + coords[2] = APPLE_COORDS[2]; + coords[3] = APPLE_COORDS[3]; + break; + case FoodType::FT_BROCCOLI: + coords[0] = BROCCOLI_COORDS[0]; + coords[1] = BROCCOLI_COORDS[1]; + coords[2] = BROCCOLI_COORDS[2]; + coords[3] = BROCCOLI_COORDS[3]; + break; + case FoodType::FT_BANANA: + coords[0] = BANANA_COORDS[0]; + coords[1] = BANANA_COORDS[1]; + coords[2] = BANANA_COORDS[2]; + coords[3] = BANANA_COORDS[3]; + break; + default: + coords[0] = 0; + coords[1] = 0; + coords[2] = 0; + coords[3] = 0; + break; + } +} diff --git a/src/helpers.h b/src/helpers.h index 7944ca5..0208294 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -8,13 +8,16 @@ namespace Helpers { extern void draw_eye(float x, float y, float radius); extern void draw_blinking_eye(float x, float y, float radius); extern void draw_open_mouth(float x, float y, float radius); -extern void draw_happy_mouth(float x, float y, float radius); +extern void draw_happy_mouth(float x, float y, float width, float radius, + FoodType foodType); -extern void draw_eyes_full(float x, float y, float width, float radius, - FoodType foodType, bool isBlinking); +extern void draw_eyes_full(float x, float y, float width, float height, + float radius, FoodType foodType, bool isBlinking); extern float get_cut_pos(float timer, FoodType foodType); +extern void get_fruit_coords(int coords[4], FoodType foodType); + } // namespace Helpers #endif