LD52/src/game.cc

303 lines
9.1 KiB
C++

#include "game.h"
// third party includes
#include <random>
#include <raylib.h>
// local includes
#include "constants.h"
#include "helpers.h"
Game::Game()
: re(std::random_device{}()), dist(0, FOOD_COUNT - 1), score(0),
highScore(0), areaSizeRatio(1.0F), currentFood(dist(re)),
blinkTimer(10.0F), cutTimer(0.0F), cutTimerRateInc(1.0F),
postCutTimer(0.0F), audioNoticeTimer(7.0F) {
flags.set(0);
flags.set(3);
spriteSheet = LoadTexture("resources/produceStuff.png");
}
void Game::do_update() {
update_impl();
draw_impl();
}
void Game::screen_resized() { flags.set(3); }
void Game::update_impl() {
const float dt = GetFrameTime();
if (flags.test(0)) {
flags.set(0);
scoreString = std::string("Score: ") + std::to_string(score);
}
blinkTimer -= dt;
if (blinkTimer <= 0.0F) {
flags.flip(1);
if (flags.test(1)) {
blinkTimer = BLINK_DURATION;
} else {
blinkTimer = std::uniform_real_distribution<float>{MIN_BLINK_TIME,
MAX_BLINK_TIME}(re);
}
}
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 (IsMouseButtonPressed(0)) {
if (flags.test(7) && GetTouchX() >= GetScreenWidth() - MUSIC_NOTE_WH &&
GetTouchX() <= GetScreenWidth() && GetTouchY() >= 0 &&
GetTouchY() <= MUSIC_NOTE_WH) {
flags.flip(8);
if (flags.test(8)) {
PlayMusicStream(music);
} else {
PauseMusicStream(music);
}
} else if (!flags.test(4)) {
flags.set(4);
if (cutPos >= offsetY && cutPos <= offsetY + height / 3.0F) {
// in correct range
flags.set(2);
++score;
flags.set(0);
PlaySound(nicecut.at(std::uniform_int_distribution<unsigned int>(
0, nicecut.size() - 1)(re)));
} else if (cutPos > offsetY + height / 3.0F) {
// past range
flags.set(5);
postCutTimer = POST_CUT_TIME;
PlaySound(ohno.at(std::uniform_int_distribution<unsigned int>(
0, ohno.size() - 1)(re)));
} else {
// before range
postCutTimer = POST_CUT_TIME;
PlaySound(ohno.at(std::uniform_int_distribution<unsigned int>(
0, ohno.size() - 1)(re)));
}
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<float>(-SPLIT_DX, SPLIT_DX)(re);
splitDY =
std::uniform_real_distribution<float>(-SPLIT_DY, SPLIT_DY)(re);
splitDAngle =
std::uniform_real_distribution<float>(-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));
}
}
if (!flags.test(7)) {
InitAudioDevice();
if (IsAudioDeviceReady()) {
nicecut.at(0) = LoadSound("resources/nicecut0.ogg");
nicecut.at(1) = LoadSound("resources/nicecut1.ogg");
nicecut.at(2) = LoadSound("resources/nicecut2.ogg");
nicecut.at(3) = LoadSound("resources/nicecut3.ogg");
nicecut.at(4) = LoadSound("resources/nicecut4.ogg");
nicecut.at(5) = LoadSound("resources/nicecut5.ogg");
nicecut.at(6) = LoadSound("resources/nicecut6.ogg");
ohno.at(0) = LoadSound("resources/ohno0.ogg");
ohno.at(1) = LoadSound("resources/ohno1.ogg");
ohno.at(2) = LoadSound("resources/ohno2.ogg");
ohno.at(3) = LoadSound("resources/ohno3.ogg");
ohno.at(4) = LoadSound("resources/ohno4.ogg");
ohno.at(5) = LoadSound("resources/ohno5.ogg");
ohno.at(6) = LoadSound("resources/ohno6.ogg");
music = LoadMusicStream("resources/LD52_00.ogg");
SetMusicVolume(music, 0.4F);
flags.set(7);
}
}
if (audioNoticeTimer > 0.0F) {
audioNoticeTimer -= dt;
}
if (flags.test(7)) {
UpdateMusicStream(music);
}
}
void Game::draw_impl() {
BeginDrawing();
ClearBackground(RAYWHITE);
int coords[4];
Helpers::get_fruit_coords(coords, (FoodType)currentFood);
DrawRectangle(0, 0, GetScreenWidth(), offsetY, {160, 160, 160, 255});
DrawRectangle(0, offsetY + height, GetScreenWidth(),
GetScreenHeight() - (offsetY + height), {160, 160, 160, 255});
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 {
DrawTexturePro(spriteSheet,
{(float)coords[0], (float)coords[1], (float)coords[2],
(float)coords[3]},
{offsetX, offsetY, width, height}, {0.0F, 0.0F}, 0.0F,
WHITE);
}
DrawRectangle(0, offsetY, GetScreenWidth(), height / 3.0F,
{255, 255, 255, 160});
DrawLine(0, cutPos, GetScreenWidth(), cutPos, BLACK);
Helpers::draw_eyes_full(offsetX + width / 2.0F, offsetY + height / 2.0F,
width, height, EYE_RADIUS, (FoodType)currentFood,
flags.test(1), flags.test(5));
if (flags.test(2)) {
Helpers::draw_happy_mouth(offsetX + width / 2.0F,
offsetY + height / 2.0F * 1.1F, width,
MOUTH_RADIUS, (FoodType)currentFood);
} else if (flags.test(4) && !flags.test(5)) {
Helpers::draw_open_mouth(offsetX + width / 2.0F,
offsetY + height / 2.0F * 1.1F, width,
OPEN_MOUTH_RADIUS, (FoodType)currentFood);
}
if (flags.test(7)) {
DrawRectangle(GetScreenWidth() - MUSIC_NOTE_WH, 0, MUSIC_NOTE_WH,
MUSIC_NOTE_WH, {100, 100, 100, 255});
Helpers::draw_music_note(GetScreenWidth() - MUSIC_NOTE_WH, 0, MUSIC_NOTE_WH,
flags.test(8));
}
DrawText(scoreString.c_str(), 2, 2, 32, BLACK);
DrawText(highScoreString.c_str(), 2, 34, 32, BLACK);
if (audioNoticeTimer > 0.0F) {
DrawText("Try refreshing if there is no audio", 2, 70, 32, BLACK);
}
EndDrawing();
}
void Game::reset(bool wasGameOver) {
flags.set(0);
flags.reset(1);
flags.reset(2);
flags.set(3);
flags.reset(4);
flags.reset(5);
flags.reset(6);
if (wasGameOver) {
if (score > highScore) {
highScore = score;
highScoreString = std::string("High score: ") + std::to_string(highScore);
}
score = 0;
cutTimerRateInc = 1.0F;
}
areaSizeRatio = 1.0F;
unsigned int prevFood = currentFood;
while (prevFood == currentFood) {
currentFood = dist(re);
}
blinkTimer =
std::uniform_real_distribution<float>{MIN_BLINK_TIME, MAX_BLINK_TIME}(re);
cutTimer = std::uniform_real_distribution<float>(0.0F, 1.0F)(re);
postCutTimer = 0.0F;
}