]> git.seodisparate.com - RockPaperScissorsDuel/commitdiff
Work on game, currently is usable, WIP anims
authorStephen Seo <seo.disparate@gmail.com>
Tue, 17 Jan 2023 08:45:41 +0000 (17:45 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Tue, 17 Jan 2023 08:45:41 +0000 (17:45 +0900)
27 files changed:
CMakeLists.txt
src/3d/anim_concurrent.cc
src/3d/anim_concurrent.h
src/3d/anim_model_attack.cc
src/3d/anim_model_attack.h
src/3d/anim_model_grow.cc
src/3d/anim_model_grow.h
src/3d/anim_model_shrink.cc
src/3d/anim_model_shrink.h
src/3d/anim_model_still.cc [new file with mode: 0644]
src/3d/anim_model_still.h [new file with mode: 0644]
src/3d/anim_sequence.cc
src/3d/anim_sequence.h
src/3d/anims.cc [new file with mode: 0644]
src/3d/anims.h
src/3d_renderer.cc
src/3d_renderer.h
src/basic_renderer.cc
src/basic_renderer.h
src/constants.h
src/game_renderer.h
src/helpers.cc
src/helpers.h
src/main.cc
wasm_build/Makefile
wasm_build/client.js
wasm_build/logic.js

index 4cae423f3c4bb5d856ad80c0410e2e192fd69dae..96c93aec20980856836ab83f78a53b75af2640ea 100644 (file)
@@ -25,11 +25,13 @@ set(RPSDuelNative_SOURCES
     "${CMAKE_CURRENT_SOURCE_DIR}/src/3d/a3f.cc"
     "${CMAKE_CURRENT_SOURCE_DIR}/src/3d/a3f_conv.cc"
     "${CMAKE_CURRENT_SOURCE_DIR}/src/3d/qm.cc"
+    "${CMAKE_CURRENT_SOURCE_DIR}/src/3d/anims.cc"
     "${CMAKE_CURRENT_SOURCE_DIR}/src/3d/anim_concurrent.cc"
     "${CMAKE_CURRENT_SOURCE_DIR}/src/3d/anim_sequence.cc"
     "${CMAKE_CURRENT_SOURCE_DIR}/src/3d/anim_model_shrink.cc"
     "${CMAKE_CURRENT_SOURCE_DIR}/src/3d/anim_model_grow.cc"
     "${CMAKE_CURRENT_SOURCE_DIR}/src/3d/anim_model_attack.cc"
+    "${CMAKE_CURRENT_SOURCE_DIR}/src/3d/anim_model_still.cc"
 )
 
 set(RPSDuelNative_HEADERS
@@ -48,6 +50,7 @@ set(RPSDuelNative_HEADERS
     "${CMAKE_CURRENT_SOURCE_DIR}/src/3d/anim_model_shrink.h"
     "${CMAKE_CURRENT_SOURCE_DIR}/src/3d/anim_model_grow.h"
     "${CMAKE_CURRENT_SOURCE_DIR}/src/3d/anim_model_attack.h"
+    "${CMAKE_CURRENT_SOURCE_DIR}/src/3d/anim_model_still.h"
 )
 
 add_executable(RPSDuelNative ${RPSDuelNative_SOURCES})
index 5dc66f1c2fb5c31ff6b7fdf78a2c6cc135e9cfcd..3d9c5d89e38b84d7c4b5f4f946f29564da79de87 100644 (file)
@@ -4,8 +4,6 @@ AnimConcurrent::AnimConcurrent(Model *model) : Anims(model) {}
 
 AnimConcurrent::~AnimConcurrent() {}
 
-bool AnimConcurrent::is_done() { return anims.empty(); }
-
 void AnimConcurrent::do_update(float dt) {
   for (auto iter = anims.begin(); iter != anims.end();) {
     (*iter)->do_update(dt);
@@ -26,3 +24,5 @@ void AnimConcurrent::do_draw() {
 void AnimConcurrent::push_anim(UPtr &&p) {
   anims.emplace_back(std::forward<UPtr>(p));
 }
+
+bool AnimConcurrent::is_done_impl() { return anims.empty(); }
index a77318769056e377429c14239020c338147afbd3..a103faa5b841074ae6275771e99ffa56db24f2f0 100644 (file)
@@ -11,13 +11,14 @@ class AnimConcurrent : public Anims {
   AnimConcurrent(Model *model);
   ~AnimConcurrent() override;
 
-  bool is_done() override;
-
   void do_update(float dt) override;
   void do_draw() override;
 
   void push_anim(UPtr &&p);
 
+ protected:
+  bool is_done_impl() override;
+
  private:
   std::list<UPtr> anims;
 };
index 64e98f88ca3966b4555a69350587b085ec726458..950cddf9bfe5139806f19e570aa396f834179077 100644 (file)
@@ -8,17 +8,16 @@
 #include "../helpers.h"
 #include "a3f_conv.h"
 
-AnimModelAttack::AnimModelAttack(Model *model, A3F pos)
+AnimModelAttack::AnimModelAttack(Model *model, A3F pos, bool is_p1)
     : Anims(model),
       pos(pos),
       offset{0.0F, 0.0F, 0.0F},
       timer(MODEL_ATTACK_TIME_0),
-      state(0) {}
+      state(0),
+      is_p1(is_p1) {}
 
 AnimModelAttack::~AnimModelAttack() {}
 
-bool AnimModelAttack::is_done() { return state == 3; }
-
 void AnimModelAttack::do_update(float dt) {
   timer -= dt;
   if (timer <= 0.0F) {
@@ -43,14 +42,16 @@ void AnimModelAttack::do_update(float dt) {
                                    1.0F - timer / MODEL_ATTACK_TIME_0);
       break;
     case 1:
-      offset.at(0) = Helpers::lerp(MODEL_ATTACK_0_X, MODEL_ATTACK_1_X,
+      offset.at(0) = Helpers::lerp(MODEL_ATTACK_0_X,
+                                   MODEL_ATTACK_1_X * (is_p1 ? 1.0F : -1.0F),
                                    1.0F - timer / MODEL_ATTACK_TIME_1);
       offset.at(1) = Helpers::lerp(MODEL_ATTACK_0_Y, MODEL_ATTACK_1_Y,
                                    1.0F - timer / MODEL_ATTACK_TIME_1);
       break;
     case 2:
-      offset.at(0) = Helpers::lerp(MODEL_ATTACK_1_X, MODEL_ATTACK_2_X,
-                                   1.0F - timer / MODEL_ATTACK_TIME_2);
+      offset.at(0) =
+          Helpers::lerp(MODEL_ATTACK_1_X * (is_p1 ? 1.0F : -1.0F),
+                        MODEL_ATTACK_2_X, 1.0F - timer / MODEL_ATTACK_TIME_2);
       offset.at(1) = Helpers::lerp(MODEL_ATTACK_1_Y, MODEL_ATTACK_2_Y,
                                    1.0F - timer / MODEL_ATTACK_TIME_2);
       break;
@@ -64,3 +65,5 @@ void AnimModelAttack::do_update(float dt) {
 void AnimModelAttack::do_draw() {
   DrawModel(*model, A3FToRV3(pos + offset), 1.0F, WHITE);
 }
+
+bool AnimModelAttack::is_done_impl() { return state == 3; }
index 2b77fa3618a03ccbfc3004ce2212433942b0d8ad..c07e8ce62a5fec9b273b125b2e117f00dd0a7963 100644 (file)
@@ -6,15 +6,15 @@
 
 class AnimModelAttack : public Anims {
  public:
-  AnimModelAttack(Model *model, A3F pos);
+  AnimModelAttack(Model *model, A3F pos, bool is_p1);
   ~AnimModelAttack() override;
 
-  bool is_done() override;
-
   void do_update(float dt) override;
   void do_draw() override;
 
  private:
+  bool is_done_impl() override;
+
   A3F pos;
   A3F offset;
   float timer;
@@ -25,6 +25,7 @@ class AnimModelAttack : public Anims {
    * 3 - done
    */
   int state;
+  bool is_p1;
 };
 
 #endif
index 78e776dd841e9df0f24b4eaaf4f75e70cf519b90..f06fb79412ac446c182c469d699feda10245f5a2 100644 (file)
@@ -12,11 +12,11 @@ AnimModelGrow::AnimModelGrow(Model *model, A3F pos)
 
 AnimModelGrow::~AnimModelGrow() {}
 
-bool AnimModelGrow::is_done() { return timer <= 0.0F; }
-
 void AnimModelGrow::do_update(float dt) { timer -= dt; }
 
 void AnimModelGrow::do_draw() {
   DrawModel(*model, A3FToRV3(pos),
             timer >= 0.0F ? (1.0F - timer / MODEL_GROW_TIME) : 1.0F, WHITE);
 }
+
+bool AnimModelGrow::is_done_impl() { return timer <= 0.0F; }
index bd97b28870bbebe77e40c95b30a451dac3abd79e..f881e4fd6db2e1dc75b42fcf7220db81feff1920 100644 (file)
@@ -9,12 +9,12 @@ class AnimModelGrow : public Anims {
   AnimModelGrow(Model *model, A3F pos);
   ~AnimModelGrow() override;
 
-  bool is_done() override;
-
   void do_update(float dt) override;
   void do_draw() override;
 
  private:
+  bool is_done_impl() override;
+
   A3F pos;
   float timer;
 };
index 49270cd3bbf57221d27f3fa2676f9b19e98ea148..5924b82f04a26b94972bdbc945cbe3c827ffef7b 100644 (file)
@@ -12,11 +12,11 @@ AnimModelShrink::AnimModelShrink(Model *model, A3F pos)
 
 AnimModelShrink::~AnimModelShrink() {}
 
-bool AnimModelShrink::is_done() { return timer <= 0.0F; }
-
 void AnimModelShrink::do_update(float dt) { timer -= dt; }
 
 void AnimModelShrink::do_draw() {
   DrawModel(*model, A3FToRV3(pos),
             timer >= 0.0F ? (timer / MODEL_SHRINK_TIME) : 0.0F, WHITE);
 }
+
+bool AnimModelShrink::is_done_impl() { return timer <= 0.0F; }
index 39c1a39391fa9298874b81399d207d6d8116f96a..4af0e7deb417ba93a3ac16f81539e36760796a89 100644 (file)
@@ -9,12 +9,12 @@ class AnimModelShrink : public Anims {
   AnimModelShrink(Model *model, A3F pos);
   ~AnimModelShrink() override;
 
-  bool is_done() override;
-
   void do_update(float dt) override;
   void do_draw() override;
 
  private:
+  bool is_done_impl() override;
+
   A3F pos;
   float timer;
 };
diff --git a/src/3d/anim_model_still.cc b/src/3d/anim_model_still.cc
new file mode 100644 (file)
index 0000000..87f9d37
--- /dev/null
@@ -0,0 +1,19 @@
+#include "anim_model_still.h"
+
+#include "a3f_conv.h"
+
+// third party includes
+#include <raylib.h>
+
+AnimModelStill::AnimModelStill(Model *model, A3F pos, float time)
+    : Anims(model), pos(pos), timer(time) {}
+
+AnimModelStill::~AnimModelStill() {}
+
+void AnimModelStill::do_update(float dt) { timer -= dt; }
+
+void AnimModelStill::do_draw() {
+  DrawModel(*model, A3FToRV3(pos), 1.0F, WHITE);
+}
+
+bool AnimModelStill::is_done_impl() { return timer <= 0.0F; }
diff --git a/src/3d/anim_model_still.h b/src/3d/anim_model_still.h
new file mode 100644 (file)
index 0000000..b59505f
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef ROCK_PAPER_SCISSORS_DUEL_3D_ANIM_MODEL_STILL_H_
+#define ROCK_PAPER_SCISSORS_DUEL_3D_ANIM_MODEL_STILL_H_
+
+#include "a3f.h"
+#include "anims.h"
+
+class AnimModelStill : public Anims {
+ public:
+  AnimModelStill(Model *model, A3F pos, float time);
+  ~AnimModelStill() override;
+
+  void do_update(float dt) override;
+  void do_draw() override;
+
+ private:
+  bool is_done_impl() override;
+
+  A3F pos;
+  float timer;
+};
+
+#endif
index 81d0c90754f2206052d44a6accf079b3b3b176e7..6695475fb3523e41ed019912bcee15641824e5ca 100644 (file)
@@ -4,8 +4,6 @@ AnimSequence::AnimSequence(Model *model) : Anims(model) {}
 
 AnimSequence::~AnimSequence() {}
 
-bool AnimSequence::is_done() { return anims.empty(); }
-
 void AnimSequence::do_update(float dt) {
   if (!anims.empty()) {
     anims.front()->do_update(dt);
@@ -24,3 +22,5 @@ void AnimSequence::do_draw() {
 void AnimSequence::push_anim(UPtr &&p) {
   anims.emplace_back(std::forward<UPtr>(p));
 }
+
+bool AnimSequence::is_done_impl() { return anims.empty(); }
index d08d615148de301e6a1521909e3a2673b663267e..f359196d78cd4f900cb8528ddef40f75fc8ad0c8 100644 (file)
@@ -11,13 +11,14 @@ class AnimSequence : public Anims {
   AnimSequence(Model *model);
   ~AnimSequence() override;
 
-  bool is_done() override;
-
   void do_update(float dt) override;
   void do_draw() override;
 
   void push_anim(UPtr &&p);
 
+ protected:
+  bool is_done_impl() override;
+
  private:
   std::list<UPtr> anims;
 };
diff --git a/src/3d/anims.cc b/src/3d/anims.cc
new file mode 100644 (file)
index 0000000..57d765d
--- /dev/null
@@ -0,0 +1,28 @@
+#include "anims.h"
+
+Anims::Anims(Model *model)
+    : model(model),
+      userdata(nullptr),
+      function_ptr(nullptr),
+      is_done_finished(false) {}
+
+bool Anims::is_done() {
+  if (is_done_finished) {
+    return true;
+  }
+  bool result = is_done_impl();
+  if (result) {
+    if (function_ptr) {
+      function_ptr(userdata);
+    }
+    is_done_finished = true;
+  }
+  return result;
+}
+
+void Anims::reset_is_done() { is_done_finished = false; }
+
+void Anims::set_end_callback(Anims::FP fp, void *ud) {
+  userdata = ud;
+  function_ptr = fp;
+}
index 1411fed0b1c7f08416e3c4bdbe01b444553677ed..d24efc0377aa7fff8729eb1d45f99bafd16047fc 100644 (file)
@@ -12,16 +12,26 @@ class Anims {
   using UPtr = std::unique_ptr<Anims>;
   using SPtr = std::shared_ptr<Anims>;
 
-  Anims(Model *model) : model(model) {}
+  using FP = void (*)(void *);
+
+  Anims(Model *model);
   virtual ~Anims() {}
 
-  virtual bool is_done() = 0;
+  bool is_done();
+  void reset_is_done();
 
   virtual void do_update(float dt) = 0;
   virtual void do_draw() = 0;
 
+  void set_end_callback(FP function_ptr, void *ud);
+
  protected:
+  virtual bool is_done_impl() = 0;
+
   Model *model;
+  void *userdata;
+  FP function_ptr;
+  bool is_done_finished;
 };
 
 #endif
index 037907c54eb2bab175e2e8109f9f5f0a53f22e33..beebd4fad60ff1fba4766e916aaa60fa2ffa7fc3 100644 (file)
@@ -8,14 +8,22 @@
 // third party includes
 #include <raylib.h>
 
+#include <memory>
+
 // local includes
 #include "3d/a3f_conv.h"
+#include "3d/anim_concurrent.h"
+#include "3d/anim_model_attack.h"
+#include "3d/anim_model_grow.h"
+#include "3d/anim_model_shrink.h"
+#include "3d/anim_model_still.h"
 #include "constants.h"
 #include "ems.h"
 #include "helpers.h"
 
 Renderer3D::Renderer3D()
     : qms{},
+      anims(nullptr),
       root_pos{0.0F, 0.0F, 0.0F},
       overview_timer(OVERVIEW_TIMER_MAX),
       button_color_timer(BUTTON_COLOR_TIME),
@@ -71,6 +79,7 @@ Renderer3D::Renderer3D()
   flags.set(1);
   flags.set(4);
   flags.set(5);
+  flags.set(14);
 
   qms.at(0).set_model(&qm_model);
   qms.at(0).set_pos({-1.0F, 0.0F, 0.0F});
@@ -106,7 +115,7 @@ void Renderer3D::update_state(const char *playerOne, const char *playerTwo,
                               char second_first, char second_second,
                               char second_third, bool first_ready,
                               bool second_ready, int pos, int matchup_idx,
-                              bool gameover) {
+                              bool gameover, bool matchup_started) {
   if (std::strcmp(playerOne, currentPlayer) == 0) {
     flags.set(2);
     flags.reset(3);
@@ -120,6 +129,7 @@ void Renderer3D::update_state(const char *playerOne, const char *playerTwo,
 
   flags.set(9, first_ready);
   flags.set(10, second_ready);
+  flags.set(13, matchup_started);
 
   flags.set(12);
 
@@ -127,18 +137,34 @@ void Renderer3D::update_state(const char *playerOne, const char *playerTwo,
     std::cout << "got pos: " << pos << std::endl;
     std::cout << "got matchup_idx: " << matchup_idx << std::endl;
     std::cout << "camera.target.x: " << camera.target.x << std::endl;
+    std::cout << "matchup started: " << (matchup_started ? "true" : "false")
+              << std::endl;
+    std::cout << "p1 is " << (first_ready ? "ready" : "NOT ready") << "\np2 is "
+              << (second_ready ? "ready" : "NOT ready") << std::endl;
   }
 
-  received_pos = pos;
+  if (!flags.test(13)) {
+    received_pos = pos;
+  }
+  if (received_matchup_idx != matchup_idx) {
+    flags.reset(7);
+  }
   received_matchup_idx = matchup_idx;
 
   if (second_first != '?') {
-    opponent_choices.at(0) = second_first;
-    opponent_choices.at(1) = second_second;
-    opponent_choices.at(2) = second_third;
+    if (flags.test(2)) {
+      opponent_choices.at(0) = second_first;
+      opponent_choices.at(1) = second_second;
+      opponent_choices.at(2) = second_third;
+    } else {
+      opponent_choices.at(0) = first_first;
+      opponent_choices.at(1) = first_second;
+      opponent_choices.at(2) = first_third;
+    }
   }
 
-  if (flags.test(11) && first_first == '?' && second_first == '?') {
+  if (flags.test(11) && first_first == '?' && second_first == '?' &&
+      flags.test(15) && !flags.test(13)) {
     choices.at(0) = '?';
     choices.at(1) = '?';
     choices.at(2) = '?';
@@ -148,8 +174,20 @@ void Renderer3D::update_state(const char *playerOne, const char *playerTwo,
     flags.reset(11);
     flags.reset(8);
     flags.reset(0);
+    flags.reset(15);
+    flags.set(14);
     overview_timer = OVERVIEW_TIMER_MAX;
     set_random_overview();
+    qms.at(0).set_pos_x(received_pos * 2.0F - 1.0F);
+    qms.at(1).set_pos_x(received_pos * 2.0F + 1.0F);
+    camera.target.x = received_pos * 2.0F;
+    if (flags.test(2)) {
+      std::cerr << "RESET STATE for next round" << std::endl;
+    }
+  }
+
+  if (flags.test(2)) {
+    std::cout << flags.to_string().substr(64 - 16) << std::endl;
   }
 }
 
@@ -296,27 +334,160 @@ void Renderer3D::update_impl() {
     button_color_timer += BUTTON_COLOR_TIME;
   }
 
+  if (flags.test(8) && flags.test(9) && flags.test(10) && !flags.test(11)) {
+    char buf[6] = {(char)choices.at(0), 0, (char)choices.at(1), 0,
+                   (char)choices.at(2), 0};
+    flags.set(11);
+    flags.set(0);
+    call_js_set_choices(&buf[0], &buf[2], &buf[4]);
+    call_js_request_update();
+  }
+
   if (flags.test(12)) {
-    if (flags.test(8) && flags.test(11)) {
-      call_js_set_ready();
-      call_js_request_update();
-    } else if (flags.test(8) && flags.test(9) && flags.test(10) &&
-               !flags.test(11)) {
-      char buf[6] = {(char)choices.at(0), 0, (char)choices.at(1), 0,
-                     (char)choices.at(2), 0};
-      call_js_set_choices(&buf[0], &buf[2], &buf[4]);
-      flags.set(11);
-      flags.set(0);
+    if (flags.test(11) && !flags.test(7) && flags.test(13) && anims.is_done()) {
+      flags.set(7);
+      flags.reset(14);
+      flags.set(15);
+
+      anims.reset_is_done();
+
+      auto newAnim = std::make_unique<AnimConcurrent>(nullptr);
+      newAnim->push_anim(std::make_unique<AnimModelShrink>(
+          &qm_model, A3F{received_pos * 2.0F - 1.0F, 0.0F, 0.0F}));
+      newAnim->push_anim(std::make_unique<AnimModelShrink>(
+          &qm_model, A3F{received_pos * 2.0F + 1.0F, 0.0F, 0.0F}));
+      anims.push_anim(std::move(newAnim));
+
+      newAnim = std::make_unique<AnimConcurrent>(nullptr);
+      Model *p1_model = &qm_model;
+      Model *p2_model = &qm_model;
+      switch (choices.at(received_matchup_idx)) {
+        case 'r':
+          if (flags.test(2)) {
+            p1_model = &rock_model;
+          } else {
+            p2_model = &rock_model;
+          }
+          break;
+        case 'p':
+          if (flags.test(2)) {
+            p1_model = &paper_model;
+          } else {
+            p2_model = &paper_model;
+          }
+          break;
+        case 's':
+          if (flags.test(2)) {
+            p1_model = &scissors_model;
+          } else {
+            p2_model = &scissors_model;
+          }
+          break;
+      }
+      switch (opponent_choices.at(received_matchup_idx)) {
+        case 'r':
+          if (flags.test(2)) {
+            p2_model = &rock_model;
+          } else {
+            p1_model = &rock_model;
+          }
+          break;
+        case 'p':
+          if (flags.test(2)) {
+            p2_model = &paper_model;
+          } else {
+            p1_model = &paper_model;
+          }
+          break;
+        case 's':
+          if (flags.test(2)) {
+            p2_model = &scissors_model;
+          } else {
+            p1_model = &scissors_model;
+          }
+          break;
+      }
+      newAnim->push_anim(std::make_unique<AnimModelGrow>(
+          p1_model, A3F{received_pos * 2.0F - 1.0F, 0.0F, 0.0F}));
+      newAnim->push_anim(std::make_unique<AnimModelGrow>(
+          p2_model, A3F{received_pos * 2.0F + 1.0F, 0.0F, 0.0F}));
+      anims.push_anim(std::move(newAnim));
+
+      newAnim = std::make_unique<AnimConcurrent>(nullptr);
+
+      const int result = Helpers::a_vs_b(
+          flags.test(2) ? choices.at(received_matchup_idx)
+                        : opponent_choices.at(received_matchup_idx),
+          flags.test(2) ? opponent_choices.at(received_matchup_idx)
+                        : choices.at(received_matchup_idx));
+
+      switch (result) {
+        case -1:
+          newAnim->push_anim(std::make_unique<AnimModelStill>(
+              p1_model, A3F{received_pos * 2.0F - 1.0F, 0.0F, 0.0F},
+              MODEL_ATTACK_TIME_0 + MODEL_ATTACK_TIME_1 + MODEL_ATTACK_TIME_2));
+          newAnim->push_anim(std::make_unique<AnimModelAttack>(
+              p2_model, A3F{received_pos * 2.0F + 1.0F, 0.0F, 0.0F}, false));
+          break;
+        case 1:
+          newAnim->push_anim(std::make_unique<AnimModelAttack>(
+              p1_model, A3F{received_pos * 2.0F - 1.0F, 0.0F, 0.0F}, true));
+          newAnim->push_anim(std::make_unique<AnimModelStill>(
+              p2_model, A3F{received_pos * 2.0F + 1.0F, 0.0F, 0.0F},
+              MODEL_ATTACK_TIME_0 + MODEL_ATTACK_TIME_1 + MODEL_ATTACK_TIME_2));
+          break;
+        case 0:
+        default:
+          break;
+      }
+
+      if (result != 0) {
+        anims.push_anim(std::move(newAnim));
+      }
+
+      newAnim = std::make_unique<AnimConcurrent>(nullptr);
+      newAnim->push_anim(std::make_unique<AnimModelShrink>(
+          p1_model, A3F{received_pos * 2.0F - 1.0F, 0.0F, 0.0F}));
+      newAnim->push_anim(std::make_unique<AnimModelShrink>(
+          p2_model, A3F{received_pos * 2.0F + 1.0F, 0.0F, 0.0F}));
+
+      using DataT = std::tuple<decltype(flags) *, int *, int>;
+      DataT *data = new DataT{&flags, &received_pos, result};
+      newAnim->set_end_callback(
+          [](void *ud) {
+            auto *d = (std::tuple<decltype(flags) *, int *, int> *)(ud);
+            std::get<0>(*d)->set(14);
+            *std::get<1>(*d) += std::get<2>(*d);
+            delete d;
+          },
+          data);
+
+      anims.push_anim(std::move(newAnim));
+
+      newAnim = std::make_unique<AnimConcurrent>(nullptr);
+      newAnim->push_anim(std::make_unique<AnimModelGrow>(
+          &qm_model, A3F{(result + received_pos) * 2.0F - 1.0F, 0.0F, 0.0F}));
+      newAnim->push_anim(std::make_unique<AnimModelGrow>(
+          &qm_model, A3F{(result + received_pos) * 2.0F + 1.0F, 0.0F, 0.0F}));
+
+      anims.push_anim(std::move(newAnim));
     }
   }
 
   flags.reset(12);
 
-  qms.at(0).get_pos().at(0) +=
-      ((received_pos * 2.0F - 1.0F) - qms.at(0).get_pos().at(0)) / 50.0F;
-  qms.at(1).get_pos().at(0) +=
-      ((received_pos * 2.0F + 1.0F) - qms.at(1).get_pos().at(0)) / 50.0F;
-  camera.target.x += (received_pos * 2.0F - camera.target.x) / 50.0F;
+  if (flags.test(8) && flags.test(11) && flags.test(7) && anims.is_done()) {
+    flags.set(14);
+    call_js_set_ready();
+    call_js_request_update();
+  }
+
+  if (flags.test(14)) {
+    float offset = received_pos * 2.0F - camera.target.x;
+    camera.target.x += offset / 4.0F;
+  }
+
+  anims.do_update(dt);
 }
 
 void Renderer3D::draw_impl() {
@@ -325,8 +496,12 @@ void Renderer3D::draw_impl() {
   BeginMode3D(camera);
   DrawModel(skybox_model, root_pos, 1.0F, WHITE);
   DrawModel(platform_model, root_pos, 1.0F, WHITE);
-  for (auto &obj : qms) {
-    obj.draw();
+  if (flags.test(0)) {
+    anims.do_draw();
+  } else {
+    for (auto &obj : qms) {
+      obj.draw();
+    }
   }
   EndMode3D();
 
index 9a57250457a34c35f624c4800bb2367693e865d6..c3e96250ccb913a5bad888fccf9de40a52a3b55b 100644 (file)
@@ -12,6 +12,8 @@
 #include <raylib.h>
 
 // local includes
+#include "3d/anim_sequence.h"
+#include "3d/anims.h"
 #include "3d/qm.h"
 
 class Renderer3D : public GameRenderer {
@@ -23,8 +25,8 @@ class Renderer3D : public GameRenderer {
                     const char *currentPlayer, char first_first,
                     char first_second, char first_third, char second_first,
                     char second_second, char second_third, bool first_ready,
-                    bool second_ready, int pos, int matchup_idx,
-                    bool gameover) override;
+                    bool second_ready, int pos, int matchup_idx, bool gameover,
+                    bool matchup_started) override;
 
   void do_update() override;
 
@@ -55,6 +57,8 @@ class Renderer3D : public GameRenderer {
   Model paper_model;
   Model scissors_model;
 
+  AnimSequence anims;
+
   Vector3 root_pos;
 
   /*
@@ -73,12 +77,15 @@ class Renderer3D : public GameRenderer {
    *    101 - UNUSED
    *    110 - UNUSED
    *    111 - UNUSED
-   * 7 - UNUSED
+   * 7 - anims set for current matchup
    * 8 - choices locked
    * 9 - p1 ready
    * 10 - p2 ready
    * 11 - choices submitted
    * 12 - update received
+   * 13 - matchup started
+   * 14 - do update camera target/pos
+   * 15 - anims was set for matchup
    */
   std::bitset<64> flags;
 
index 5d02b7ada84d85bc1c1afb8912f9fda28bc95513..d2e53955aac5d300fe2375cc562f4d22a22c0872 100644 (file)
@@ -39,7 +39,7 @@ void BasicRenderer::update_state(const char *playerOne, const char *playerTwo,
                                  char second_first, char second_second,
                                  char second_third, bool first_ready,
                                  bool second_ready, int pos, int matchup_idx,
-                                 bool gameover) {
+                                 bool gameover, bool matchup_started) {
   // TODO DEBUG
   // if (std::strcmp(playerOne, currentPlayer) == 0) {
   //  std::clog << "update_state:\n"
index 07659103e1422d86500e8c5b46cb901431c3df94..31d182e69baa476938c82c9a144cfcb36f371fd0 100644 (file)
@@ -21,8 +21,8 @@ class BasicRenderer : public GameRenderer {
                     const char *currentPlayer, char first_first,
                     char first_second, char first_third, char second_first,
                     char second_second, char second_third, bool first_ready,
-                    bool second_ready, int pos, int matchup_idx,
-                    bool gameover) override;
+                    bool second_ready, int pos, int matchup_idx, bool gameover,
+                    bool matchup_started) override;
 
   void do_update() override;
 
index 9093d9a890c147f580ad523ca1428b40c9af7dd4..ff91e9d724faa9587dd6344deead893aa5c14da8 100644 (file)
@@ -85,7 +85,7 @@ constexpr float MODEL_ATTACK_TIME_1 = 0.3F;
 constexpr float MODEL_ATTACK_TIME_2 = 0.4F;
 constexpr float MODEL_ATTACK_0_X = 0.0F;
 constexpr float MODEL_ATTACK_0_Y = 2.0F;
-constexpr float MODEL_ATTACK_1_X = -1.0F;
+constexpr float MODEL_ATTACK_1_X = 1.0F;
 constexpr float MODEL_ATTACK_1_Y = 0.2F;
 constexpr float MODEL_ATTACK_2_X = 0.0F;
 constexpr float MODEL_ATTACK_2_Y = 0.0F;
index 1cee95ec5b701f437581ad58bf1ecb69f68e182c..385fea88f046326e42511560efb78294bddf97b7 100644 (file)
@@ -12,7 +12,7 @@ class GameRenderer {
                             char second_first, char second_second,
                             char second_third, bool first_ready,
                             bool second_ready, int pos, int matchup_idx,
-                            bool gameover) = 0;
+                            bool gameover, bool matchup_started) = 0;
 
   virtual void do_update() = 0;
 
index 9fd7bf34d37bc2af0a1fb96fff938caae03c357c..a19ad1133b512418ab9888662065b1b5db72857d 100644 (file)
@@ -98,3 +98,39 @@ void Helpers::overview_orbit(Vector3 *out, float value, bool is_opposite,
   out->y = OVERVIEW_ORBIT_Y;
   out->z = -(value * value - 1.0F) * OVERVIEW_ORBIT_RADIUS;
 }
+
+int Helpers::a_vs_b(char a, char b) {
+  if (a == 'r') {
+    if (b == 'r') {
+      return 0;
+    } else if (b == 'p') {
+      return -1;
+    } else if (b == 's') {
+      return 1;
+    } else {
+      return 0;
+    }
+  } else if (a == 'p') {
+    if (b == 'r') {
+      return 1;
+    } else if (b == 'p') {
+      return 0;
+    } else if (b == 's') {
+      return -1;
+    } else {
+      return 0;
+    }
+  } else if (a == 's') {
+    if (b == 'r') {
+      return -1;
+    } else if (b == 'p') {
+      return 1;
+    } else if (b == 's') {
+      return 0;
+    } else {
+      return 0;
+    }
+  } else {
+    return 0;
+  }
+}
index c66b1d8428b81317df84d41f511d890d0f700bd8..b342a1562a05e2a4dc38c875a202fbe154b91793 100644 (file)
@@ -26,6 +26,8 @@ extern void overview_zoom_out_c(Vector3 *out, float value, bool is_opposite,
 extern void overview_orbit(Vector3 *out, float value, bool is_opposite,
                            float offset_x);
 
+extern int a_vs_b(char a, char b);
+
 }  // namespace Helpers
 
 #endif
index 4a58602ae6e6fa3aba3990548279d1c3de9c99cc..c40917a5d6f1cf0205261453f848c316baee348f 100644 (file)
@@ -30,12 +30,12 @@ int EMSCRIPTEN_KEEPALIVE game_visual_update(
     const char *playerOne, const char *playerTwo, const char *currentPlayer,
     char first_first, char first_second, char first_third, char second_first,
     char second_second, char second_third, bool first_ready, bool second_ready,
-    int pos, int matchup_idx, bool gameover) {
+    int pos, int matchup_idx, bool gameover, bool matchup_started) {
   ((GameRenderer *)global_game_ptr)
       ->update_state(playerOne, playerTwo, currentPlayer, first_first,
                      first_second, first_third, second_first, second_second,
                      second_third, first_ready, second_ready, pos, matchup_idx,
-                     gameover);
+                     gameover, matchup_started);
   return 0;
 }
 
index 2196f31c99a04e82012645a429f317f19db8ddb7..bb1e1edf9de4c84eeb3d26b2c946a8711d6eee98 100644 (file)
@@ -15,11 +15,13 @@ SOURCES = \
                ../src/3d/a3f.cc \
                ../src/3d/a3f_conv.cc \
                ../src/3d/qm.cc \
+               ../src/3d/anims.cc \
                ../src/3d/anim_concurrent.cc \
                ../src/3d/anim_sequence.cc \
                ../src/3d/anim_model_shrink.cc \
                ../src/3d/anim_model_grow.cc \
-               ../src/3d/anim_model_attack.cc
+               ../src/3d/anim_model_attack.cc \
+               ../src/3d/anim_model_still.cc
 
 HEADERS = \
                ../src/constants.h \
@@ -37,7 +39,8 @@ HEADERS = \
                ../src/3d/anim_sequence.h \
                ../src/3d/anim_model_shrink.h \
                ../src/3d/anim_model_grow.h \
-               ../src/3d/anim_model_attack.h
+               ../src/3d/anim_model_attack.h \
+               ../src/3d/anim_model_still.h
 
 CXX = source ${HOME}/git/emsdk/emsdk_env.sh && em++
 
index 726fa608ca054cdf05b54e2fa0eaaf25ba139899..e48f78a37b9a2308389263c95f1340a4c42138d4 100644 (file)
@@ -1,6 +1,6 @@
 Rune.initClient({
     visualUpdate: ({ newGame, yourPlayerId}) => {
-        const { player1, player2, first_choices, second_choices, ready, pos, matchup_idx, gameover } = newGame;
+        const { player1, player2, first_choices, second_choices, ready, pos, matchup_idx, gameover, matchup_started } = newGame;
 
         function is_choices_filled(choices) {
             for (let i = 0; i < 3; ++i) {
@@ -18,7 +18,7 @@ Rune.initClient({
                     'number', 'number', 'number',
                     'number', 'number', 'number',
                     'boolean', 'boolean',
-                    'number', 'number', 'boolean'],
+                    'number', 'number', 'boolean', 'boolean'],
                 [player1, player2,
                     yourPlayerId === undefined ? 'undefined' : yourPlayerId,
                     first_choices[0].charCodeAt(0),
@@ -28,7 +28,7 @@ Rune.initClient({
                     second_choices[1].charCodeAt(0),
                     second_choices[2].charCodeAt(0),
                     ready[0], ready[1],
-                    pos, matchup_idx, gameover]);
+                    pos, matchup_idx, gameover, matchup_started]);
         } else {
             Module.ccall('game_visual_update',
                 'number',
@@ -36,7 +36,7 @@ Rune.initClient({
                     'number', 'number', 'number',
                     'number', 'number', 'number',
                     'boolean', 'boolean',
-                    'number', 'number', 'boolean'],
+                    'number', 'number', 'boolean', 'boolean'],
                 [player1, player2,
                     yourPlayerId === undefined ? 'undefined' : yourPlayerId,
                     '?'.charCodeAt(0),
@@ -46,7 +46,7 @@ Rune.initClient({
                     '?'.charCodeAt(0),
                     '?'.charCodeAt(0),
                     ready[0], ready[1],
-                    pos, matchup_idx, gameover]);
+                    pos, matchup_idx, gameover, matchup_started]);
         }
     },
 });
index b3ddf582ac7062b2d709d670877cf11fa8ac3bc6..8e821d6271314c3c193c0b6331f4ef05847d6954 100644 (file)
@@ -10,6 +10,7 @@ Rune.initLogic({
         pos: 0,
         matchup_idx: 0,
         gameover: false,
+        matchup_started: false,
     }),
     actions: {
         set_choices: ({first, second, third}, { game, playerId }) => {
@@ -81,6 +82,12 @@ Rune.initLogic({
             }
 
             // Both sides are ready, iterate through matchups
+            if (!game.matchup_started) {
+                game.matchup_started = true;
+                game.ready[0] = false;
+                game.ready[1] = false;
+                return;
+            }
 
             // check if first won the matchup
             if ((game.first_choices[game.matchup_idx] === 'r'
@@ -121,6 +128,7 @@ Rune.initLogic({
                     }
                     game.matchup_idx = 0;
                 }
+                game.matchup_started = false;
             }
         },
     },