src/main.cc
src/game.cc
src/ems.cc
+ src/helpers.cc
+ src/constants.cc
)
add_executable(LD52Native ${LD52Native_SOURCES})
--- /dev/null
+#include "constants.h"
+
+// standard library includes
+#include <cmath>
+
+const float PI_F = std::acos(-1.0F);
#ifndef LD52_HARVEST_FOOD_CUTS_CONSTANTS_H_
#define LD52_HARVEST_FOOD_CUTS_CONSTANTS_H_
+extern const float PI_F;
+
constexpr int DEFAULT_SCREEN_WIDTH = 500;
constexpr int DEFAULT_SCREEN_HEIGHT = 800;
+constexpr int FOOD_COUNT = 5;
+
+enum class FoodType {
+ FT_CORN = 0,
+ FT_GRAPES,
+ FT_APPLE,
+ FT_BROCCOLI,
+ FT_BANANA,
+};
+
+constexpr int CORN_COORDS[4] = {0, 0, 281, 676};
+constexpr int GRAPES_COORDS[4] = {281, 0, 232, 434};
+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 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 EYE_WIDTH_RATIO = 0.3F;
+
+constexpr float AREA_REDUCTION_SCALE = 0.99F;
+constexpr float MIN_AREA = 15.0F;
+
+constexpr float MAX_FOOD_WH = 500.0F;
+
+constexpr float EYE_RADIUS = 14.0F;
+constexpr float BLINKING_EYE_SIZE = 4.0F;
+
+constexpr float MOUTH_RADIUS = 20.0F;
+
+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_TIMER_RATE_INC_AMT = 0.03F;
+
#endif
#include "game.h"
// third party includes
+#include <random>
#include <raylib.h>
-Game::Game() {}
+// local includes
+#include "constants.h"
+#include "helpers.h"
+
+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) {
+ flags.set(0);
+
+ spriteSheet = LoadTexture("resources/produceStuff.png");
+}
void Game::do_update() {
update_impl();
draw_impl();
}
-void Game::update_impl() {}
+void Game::update_impl() {
+ const float dt = GetFrameTime();
+
+ if (flags.test(0)) {
+ flags.set(0);
+ scoreString.clear();
+ if (score == 0) {
+ scoreString.push_back('0');
+ } else {
+ std::string temp;
+ for (unsigned long long i = score; i > 0; i /= 10) {
+ temp.push_back((i % 10) + '0');
+ }
+ for (auto c : temp) {
+ scoreString.push_back(c);
+ }
+ }
+ }
+
+ 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);
+ }
+ }
+
+ cutTimer += dt * CUT_TIMER_RATE * cutTimerRateInc;
+ if (cutTimer > 1.0F) {
+ cutTimer -= 1.0F;
+ }
+}
void Game::draw_impl() {
+
BeginDrawing();
- ClearBackground(BLACK);
- DrawText("Testing...", 100, 100, 30, RAYWHITE);
+ ClearBackground(RAYWHITE);
+
+ float ratio;
+ float width;
+ float height;
+ float offsetX;
+ float offsetY;
+
+ 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;
+
+ 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]},
+ {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);
+
+ Helpers::draw_eyes_full(offsetX + width / 2.0F, offsetY + height / 2.0F,
+ width, 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);
+ }
+
+ DrawText(scoreString.c_str(), 2, 2, 32, BLACK);
EndDrawing();
}
+
+void Game::reset() {
+ flags.set(0);
+ score = 0;
+ areaSizeRatio = 1.0F;
+ currentFood = dist(re);
+ blinkTimer = 10.0F;
+ cutTimer = 0.0F;
+}
#ifndef LD52_HARVEST_FOOD_CUTS_GAME_H_
#define LD52_HARVEST_FOOD_CUTS_GAME_H_
+// standard library includes
+#include <bitset>
+#include <random>
+
+// third party includes
+#include <raylib.h>
+
class Game {
public:
Game();
void do_update();
private:
-
void update_impl();
void draw_impl();
+ void reset();
+
+ std::default_random_engine re;
+ std::uniform_int_distribution<unsigned int> dist;
+ std::string scoreString;
+ Texture2D spriteSheet;
+ unsigned long long score;
+ /*
+ * 0 - score dirty
+ * 1 - is blinking
+ * 2 - happy
+ */
+ std::bitset<32> flags;
+ float areaSizeRatio;
+ float currentArea;
+ unsigned int currentFood;
+ float blinkTimer;
+ float cutTimer;
+ float cutTimerRateInc;
};
#endif
--- /dev/null
+#include "helpers.h"
+
+// standard library includes
+#include <cmath>
+
+// third party includes
+#include <raylib.h>
+
+// 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];
+ switch (foodType) {
+ case FoodType::FT_CORN:
+ offsets[0] = CORN_EYE_OFFSET[0];
+ offsets[1] = CORN_EYE_OFFSET[1];
+ break;
+ case FoodType::FT_GRAPES:
+ offsets[0] = GRAPES_EYE_OFFSET[0];
+ offsets[1] = GRAPES_EYE_OFFSET[1];
+ break;
+ case FoodType::FT_APPLE:
+ offsets[0] = APPLE_EYE_OFFSET[0];
+ offsets[1] = APPLE_EYE_OFFSET[1];
+ break;
+ case FoodType::FT_BROCCOLI:
+ offsets[0] = BROCCOLI_EYE_OFFSET[0];
+ offsets[1] = BROCCOLI_EYE_OFFSET[1];
+ break;
+ case FoodType::FT_BANANA:
+ offsets[0] = BANANA_EYE_OFFSET[0];
+ offsets[1] = BANANA_EYE_OFFSET[1];
+ break;
+ default:
+ offsets[0] = 0.0F;
+ offsets[1] = 0.0F;
+ break;
+ }
+
+ 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);
+ } 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);
+ }
+}
+
+float Helpers::get_cut_pos(float timer, FoodType foodType) {
+ switch (foodType) {
+ case FoodType::FT_CORN:
+ return std::cos(timer) * (float)CORN_COORDS[3];
+ case FoodType::FT_GRAPES:
+ return std::cos(timer) * (float)GRAPES_COORDS[3];
+ case FoodType::FT_APPLE:
+ return std::cos(timer) * (float)APPLE_COORDS[3];
+ case FoodType::FT_BROCCOLI:
+ return std::cos(timer) * (float)BROCCOLI_COORDS[3];
+ case FoodType::FT_BANANA:
+ return std::cos(timer) * (float)BANANA_COORDS[3];
+ }
+ return 0.0F;
+}
--- /dev/null
+#ifndef LD52_HARVEST_FOOD_CUTS_H_
+#define LD52_HARVEST_FOOD_CUTS_H_
+
+#include "constants.h"
+
+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_eyes_full(float x, float y, float width, float radius,
+ FoodType foodType, bool isBlinking);
+
+extern float get_cut_pos(float timer, FoodType foodType);
+
+} // namespace Helpers
+
+#endif
int main() {
#ifdef __EMSCRIPTEN__
- InitWindow(DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_HEIGHT, "LD52_Harvest_Food_Cuts");
+ InitWindow(DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_HEIGHT,
+ "LD52_Harvest_Food_Cuts");
#else
InitWindow(DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_HEIGHT,
"LD52_Harvest_Food_Cuts_Native");
SOURCES = \
../src/main.cc \
../src/ems.cc \
- ../src/game.cc
+ ../src/game.cc \
+ ../src/constants.cc \
+ ../src/helpers.cc
HEADERS = \
- ../src/constants.h
+ ../src/constants.h \
+ ../src/game.h \
+ ../src/ems.h \
+ ../src/helpers.h
CXX = source ${HOME}/git/emsdk/emsdk_env.sh && em++
--shell-file custom_shell.html \
-sEXPORTED_FUNCTIONS=_main \
-sEXPORTED_RUNTIME_METHODS=ccall \
+ --preload-file ../resources \
${OTHER_FLAGS} \
${SOURCES}