]> git.seodisparate.com - LD52/commitdiff
WIP work on LD52 game
authorStephen Seo <seo.disparate@gmail.com>
Sat, 7 Jan 2023 05:36:14 +0000 (14:36 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Sat, 7 Jan 2023 05:36:29 +0000 (14:36 +0900)
At this point, the produce is drawn, the cut line is animated, the produce can
blink, the ideal cut area is draw as a slightly transparent white rect, the
score counter is drawn.

CMakeLists.txt
resources/produceStuff.png [new file with mode: 0644]
src/constants.cc [new file with mode: 0644]
src/constants.h
src/game.cc
src/game.h
src/helpers.cc [new file with mode: 0644]
src/helpers.h [new file with mode: 0644]
src/main.cc
wasm_build/Makefile

index a677e678edd0752a90e37e9bb75b7c117e4f0f0f..b38fc4eee7234bae1d584d51b992c68029c02dba 100644 (file)
@@ -18,6 +18,8 @@ set(LD52Native_SOURCES
     src/main.cc
     src/game.cc
     src/ems.cc
+    src/helpers.cc
+    src/constants.cc
 )
 
 add_executable(LD52Native ${LD52Native_SOURCES})
diff --git a/resources/produceStuff.png b/resources/produceStuff.png
new file mode 100644 (file)
index 0000000..19a3bb9
Binary files /dev/null and b/resources/produceStuff.png differ
diff --git a/src/constants.cc b/src/constants.cc
new file mode 100644 (file)
index 0000000..5218267
--- /dev/null
@@ -0,0 +1,6 @@
+#include "constants.h"
+
+// standard library includes
+#include <cmath>
+
+const float PI_F = std::acos(-1.0F);
index 707985805ff51b9b1a7430aa1653e30ee0380c71..086443922b22c8ac392414ce4395d9d9085beda7 100644 (file)
@@ -1,7 +1,51 @@
 #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
index a8670d87d16cc3d111b59ebba527568c0bf608eb..dd038271ffb6e4bbf8824f8f1a2fefe87bb17006 100644 (file)
 #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;
+}
index 5c884ac024bc0f6e78037779f3acae6d83d52571..12eb9d64d310da8982380e88201c6717b13362f9 100644 (file)
@@ -1,6 +1,13 @@
 #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();
@@ -8,10 +15,28 @@ public:
   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
diff --git a/src/helpers.cc b/src/helpers.cc
new file mode 100644 (file)
index 0000000..c074355
--- /dev/null
@@ -0,0 +1,86 @@
+#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;
+}
diff --git a/src/helpers.h b/src/helpers.h
new file mode 100644 (file)
index 0000000..7944ca5
--- /dev/null
@@ -0,0 +1,20 @@
+#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
index a57f8adb0802e400f29b4fc61321a2052d9feb53..245593a9925a9a639739903151b12944c9fbef76 100644 (file)
@@ -31,7 +31,8 @@ void game_update(void *game_ptr) { ((Game *)game_ptr)->do_update(); }
 
 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");
index ac64b5d6d88c6d19f58f6bf6e8078716faec2d53..d69377659737ad0f1a6efc3ddf0b065d71cbdbc4 100644 (file)
@@ -7,10 +7,15 @@ endif
 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++
 
@@ -22,6 +27,7 @@ ld52_harvest_cut.html: ${SOURCES} ${HEADERS}
                --shell-file custom_shell.html \
                -sEXPORTED_FUNCTIONS=_main \
                -sEXPORTED_RUNTIME_METHODS=ccall \
+               --preload-file ../resources \
                ${OTHER_FLAGS} \
                ${SOURCES}