]> git.seodisparate.com - jumpartifact.com_demo_0/commitdiff
Impl. controlling a walker
authorStephen Seo <seo.disparate@gmail.com>
Tue, 15 Aug 2023 02:53:26 +0000 (11:53 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Tue, 15 Aug 2023 02:53:26 +0000 (11:53 +0900)
src/screen_trunner.cc
src/screen_trunner.h
src/walker.cc
src/walker.h

index 2e95e80b5c7eadd7cad24f98b293ea9212390bf2..8962617d736a59395409e6b4e1765331347439b5 100644 (file)
@@ -10,6 +10,7 @@
 #endif
 
 // third party includes
+#include <raylib.h>
 #include <raymath.h>
 
 // local includes
@@ -45,7 +46,11 @@ TRunnerScreen::TRunnerScreen(std::weak_ptr<ScreenStack> stack)
       camera_target{0.0F, 0.0F, 0.0F},
       mouse_hit{0.0F, 0.0F, 0.0F},
       idx_hit(SURFACE_UNIT_WIDTH / 2 +
-              (SURFACE_UNIT_HEIGHT / 2) * SURFACE_UNIT_WIDTH) {
+              (SURFACE_UNIT_HEIGHT / 2) * SURFACE_UNIT_WIDTH),
+      controlled_walker_idx(std::nullopt),
+      left_text_width(MeasureText("Left", BUTTON_FONT_SIZE)),
+      right_text_width(MeasureText("Right", BUTTON_FONT_SIZE)),
+      forward_text_width(MeasureText("Forward", BUTTON_FONT_SIZE)) {
 #ifndef NDEBUG
   std::cout << "idx_hit initialized to " << idx_hit << std::endl;
 #endif
@@ -219,6 +224,45 @@ TRunnerScreen::~TRunnerScreen() {
 }
 
 bool TRunnerScreen::update(float dt) {
+  if (controlled_walker_idx.has_value()) {
+    auto walker_body_pos =
+        walkers[controlled_walker_idx.value()].get_body_pos();
+
+    camera_target = walker_body_pos + Vector3{0.0F, 1.0F, 0.0F};
+
+    float rotation = walkers[controlled_walker_idx.value()].get_rotation();
+
+    Vector3 offset = get_rotation_matrix_about_y(rotation + PI) *
+                         Vector3{1.0F, 0.0F, 0.0F} * 4.0F +
+                     Vector3{0.0F, 4.0F, 0.0F};
+
+    camera_pos = walkers[controlled_walker_idx.value()].get_body_pos() + offset;
+  }
+
+  if (controlled_walker_idx.has_value() && IsMouseButtonDown(0)) {
+    // Check if clicked on button.
+    if (GetTouchX() >= 0 && GetTouchX() <= left_text_width &&
+        GetTouchY() >= GetScreenHeight() - BUTTON_FONT_SIZE &&
+        GetTouchY() <= GetScreenHeight()) {
+      walkers[controlled_walker_idx.value()].player_turn_left();
+      goto post_check_click;
+    } else if (GetTouchX() >= left_text_width &&
+               GetTouchX() <= left_text_width + right_text_width &&
+               GetTouchY() >= GetScreenHeight() - BUTTON_FONT_SIZE &&
+               GetTouchY() <= GetScreenHeight()) {
+      walkers[controlled_walker_idx.value()].player_turn_right();
+      goto post_check_click;
+    } else if (int width_mid = (left_text_width + right_text_width) / 2 -
+                               forward_text_width / 2;
+               GetTouchX() >= width_mid &&
+               GetTouchX() <= width_mid + forward_text_width &&
+               GetTouchY() >= GetScreenHeight() - BUTTON_FONT_SIZE * 2 &&
+               GetTouchY() <= GetScreenHeight() - BUTTON_FONT_SIZE) {
+      walkers[controlled_walker_idx.value()].player_go_forward();
+      goto post_check_click;
+    }
+  }
+
   if (IsMouseButtonPressed(0)) {
     float press_x = GetTouchX();
     float press_y = GetTouchY();
@@ -230,6 +274,23 @@ bool TRunnerScreen::update(float dt) {
               << ray.direction.y << ", " << ray.direction.z << std::endl;
 #endif
 
+    // Check if clicked on a Walker.
+    for (unsigned int idx = 0; idx < walkers.size(); ++idx) {
+      if (auto walker_bb = walkers[idx].get_body_bb();
+          GetRayCollisionBox(ray, walker_bb).hit) {
+        if (controlled_walker_idx.has_value()) {
+          walkers[controlled_walker_idx.value()].set_player_controlled(false);
+        }
+        controlled_walker_idx = idx;
+        walkers[controlled_walker_idx.value()].set_player_controlled(true);
+
+        idx_hit = SURFACE_UNIT_WIDTH * SURFACE_UNIT_HEIGHT;
+
+        goto post_check_click;
+      }
+    }
+
+    // Check if clicked on ground.
     for (unsigned int idx = 0; idx < SURFACE_UNIT_WIDTH * SURFACE_UNIT_HEIGHT;
          ++idx) {
       int x = idx % SURFACE_UNIT_WIDTH;
@@ -266,6 +327,11 @@ bool TRunnerScreen::update(float dt) {
           this->camera_pos.z = 0.0F;
         }
         this->camera_target.y += 1.0F;
+        if (this->controlled_walker_idx.has_value()) {
+          this->walkers[this->controlled_walker_idx.value()]
+              .set_player_controlled(false);
+          this->controlled_walker_idx = std::nullopt;
+        }
       };
 
       if (auto bb_collision = GetRayCollisionBox(ray, surface_bbs[idx]);
@@ -273,16 +339,22 @@ bool TRunnerScreen::update(float dt) {
         if (auto collision = GetRayCollisionTriangle(ray, nw, sw, ne);
             collision.hit) {
           on_collide_fn(collision.point);
-          break;
+          goto post_check_click;
         } else if (auto collision = GetRayCollisionTriangle(ray, ne, sw, se);
                    collision.hit) {
           on_collide_fn(collision.point);
-          break;
+          goto post_check_click;
         }
       }
     }
+  } else if (IsMouseButtonReleased(0)) {
+    if (controlled_walker_idx.has_value()) {
+      walkers[controlled_walker_idx.value()].player_idle();
+    }
   }
 
+post_check_click:
+
   camera_to_targets(dt);
 
   for (auto &walker : walkers) {
@@ -323,9 +395,34 @@ bool TRunnerScreen::draw() {
   }
 
   // TODO DEBUG
-  DrawLine3D(Vector3{0.0F, 3.0F, 0.0F}, mouse_hit, BLACK);
+  if (!controlled_walker_idx.has_value()) {
+    DrawLine3D(Vector3{0.0F, 3.0F, 0.0F}, mouse_hit, BLACK);
+  }
 
   EndMode3D();
+
+  if (controlled_walker_idx.has_value()) {
+    int total_width = 0;
+    DrawRectangle(0, GetScreenHeight() - BUTTON_FONT_SIZE, left_text_width,
+                  BUTTON_FONT_SIZE, Color{255, 255, 255, 120});
+    DrawText("Left", 0, GetScreenHeight() - BUTTON_FONT_SIZE, BUTTON_FONT_SIZE,
+             BLACK);
+
+    total_width += left_text_width;
+    DrawRectangle(total_width, GetScreenHeight() - BUTTON_FONT_SIZE,
+                  right_text_width, BUTTON_FONT_SIZE,
+                  Color{255, 255, 255, 120});
+    DrawText("Right", total_width, GetScreenHeight() - BUTTON_FONT_SIZE,
+             BUTTON_FONT_SIZE, BLACK);
+
+    total_width = (total_width + right_text_width) / 2 - forward_text_width / 2;
+    DrawRectangle(total_width, GetScreenHeight() - BUTTON_FONT_SIZE * 2,
+                  forward_text_width, BUTTON_FONT_SIZE,
+                  Color{255, 255, 255, 120});
+    DrawText("Forward", total_width, GetScreenHeight() - BUTTON_FONT_SIZE * 2,
+             BUTTON_FONT_SIZE, BLACK);
+  }
+
   EndDrawing();
 
   return false;
index d375309372de2071545698b10661df046115db46..57ec1e19bb41065a4894409f35efacc8b623ba7d 100644 (file)
@@ -20,6 +20,8 @@ constexpr float CAMERA_UPDATE_RATE = 1.0F;
 
 constexpr float SURFACE_HEIGHT_INTERVAL = 0.7F;
 
+constexpr int BUTTON_FONT_SIZE = 30;
+
 class TRunnerScreen : public Screen {
  public:
   TRunnerScreen(std::weak_ptr<ScreenStack> stack);
@@ -67,6 +69,10 @@ class TRunnerScreen : public Screen {
   Vector3 camera_target;
   Vector3 mouse_hit;
   unsigned int idx_hit;
+  std::optional<unsigned int> controlled_walker_idx;
+  const int left_text_width;
+  const int right_text_width;
+  const int forward_text_width;
 
   void camera_to_targets(float dt);
 };
index abc284c138b61309e8cad72801d63e274143ebe3..be02e14aadeb36cda8e201d066d19aead1c03158 100644 (file)
@@ -154,3 +154,45 @@ void Walker::set_body_pos(Vector3 pos) {
     flags |= 1;
   }
 }
+
+void Walker::set_player_controlled(bool player_controlled) {
+  if (player_controlled) {
+    flags &= ~0x3B;
+    flags |= 8;
+    target_body_pos = body_pos;
+  } else {
+    flags &= ~0x38;
+  }
+}
+
+void Walker::player_idle() { flags &= ~0x30; }
+
+void Walker::player_turn_left() {
+  flags &= ~0x30;
+  flags |= 0x10;
+  target_body_pos = body_pos;
+}
+
+void Walker::player_turn_right() {
+  flags &= ~0x30;
+  flags |= 0x20;
+  target_body_pos = body_pos;
+}
+
+void Walker::player_go_forward() { flags |= 0x30; }
+
+BoundingBox Walker::get_body_bb() const {
+  return BoundingBox{
+      .min = body_pos - Vector3{0.5F,
+                                0.5F + BODY_IDLE_MOVE_AMOUNT *
+                                           std::sin(body_idle_move_timer + PI),
+                                0.5F},
+      .max = body_pos + Vector3{0.5F,
+                                0.5F + BODY_IDLE_MOVE_AMOUNT *
+                                           std::sin(body_idle_move_timer + PI),
+                                0.5F}};
+}
+
+float Walker::get_rotation() const { return rotation; }
+
+Vector3 Walker::get_body_pos() const { return body_pos; }
index d05ea70fd8c6e742afc6fe50b5902da714884080..53ad022824bec0204d07a8f73bf0c5b23454a915 100644 (file)
@@ -43,6 +43,16 @@ class Walker {
 
   void set_body_pos(Vector3 pos);
 
+  void set_player_controlled(bool player_controlled);
+  void player_idle();
+  void player_turn_left();
+  void player_turn_right();
+  void player_go_forward();
+
+  BoundingBox get_body_bb() const;
+  float get_rotation() const;
+  Vector3 get_body_pos() const;
+
  private:
   Vector3 body_pos;
   Vector3 target_body_pos;
@@ -63,6 +73,11 @@ class Walker {
   // ???? ??01 - rotating to move
   // ???? ??10 - moving
   // ???? ?1?? - auto roaming
+  // ???? 1??? - player controlled
+  // ??00 ???? - player controlled: idle
+  // ??01 ???? - player controlled: turn left
+  // ??10 ???? - player controlled: turn right
+  // ??11 ???? - player controlled: go forward
   unsigned int flags;
 
   const float body_height;
@@ -79,7 +94,7 @@ class Walker {
 template <std::size_t BBCount>
 void Walker::update(float dt, const std::array<BoundingBox, BBCount> &bbs,
                     unsigned int width, unsigned int height) {
-  if ((flags & 4) != 0 && (flags & 3) == 0) {
+  if ((flags & 8) == 0 && (flags & 4) != 0 && (flags & 3) == 0) {
     roaming_timer += dt;
     if (roaming_timer > roaming_time) {
       roaming_timer = 0.0F;
@@ -122,49 +137,72 @@ void Walker::update(float dt, const std::array<BoundingBox, BBCount> &bbs,
   }
 
   // body rotation
-  if ((flags & 3) == 1) {
-    float diff = target_rotation - rotation;
-    if (diff > PI) {
-      rotation -= dt * BODY_ROTATION_SPEED;
-      if (rotation < 0.0F) {
-        rotation += PI * 2.0F;
+  if ((flags & 8) == 0) {
+    if ((flags & 3) == 1) {
+      float diff = target_rotation - rotation;
+      if (diff > PI) {
+        rotation -= dt * BODY_ROTATION_SPEED;
+        if (rotation < 0.0F) {
+          rotation += PI * 2.0F;
+        }
+      } else if (diff < -PI) {
+        rotation += dt * BODY_ROTATION_SPEED;
+        if (rotation > PI * 2.0F) {
+          rotation -= PI * 2.0F;
+        }
+      } else if (diff > 0.0F) {
+        rotation += dt * BODY_ROTATION_SPEED;
+        if (rotation > PI * 2.0F) {
+          rotation -= PI * 2.0F;
+        }
+      } else {
+        rotation -= dt * BODY_ROTATION_SPEED;
+        if (rotation < 0.0F) {
+          rotation += PI * 2.0F;
+        }
       }
-    } else if (diff < -PI) {
-      rotation += dt * BODY_ROTATION_SPEED;
-      if (rotation > PI * 2.0F) {
-        rotation -= PI * 2.0F;
+
+      if (std::abs(target_rotation - rotation) < dt * BODY_ROTATION_SPEED) {
+        rotation = target_rotation;
+        flags &= ~3;
+        flags |= 2;
       }
-    } else if (diff > 0.0F) {
+    }
+  } else {
+    if ((flags & 0x30) == 0x10) {
       rotation += dt * BODY_ROTATION_SPEED;
-      if (rotation > PI * 2.0F) {
-        rotation -= PI * 2.0F;
-      }
-    } else {
+    } else if ((flags & 0x30) == 0x20) {
       rotation -= dt * BODY_ROTATION_SPEED;
-      if (rotation < 0.0F) {
-        rotation += PI * 2.0F;
-      }
-    }
-
-    if (std::abs(target_rotation - rotation) < dt * BODY_ROTATION_SPEED) {
-      rotation = target_rotation;
-      flags &= ~3;
-      flags |= 2;
     }
   }
+
+  const Matrix rotationMatrix = get_rotation_matrix_about_y(rotation);
+
   // body to target pos
-  if ((flags & 3) == 2) {
-    float diff = Vector3Distance(target_body_pos, body_pos);
-    body_pos = body_pos + Vector3Normalize(target_body_pos - body_pos) *
-                              (dt * BODY_TARGET_SPEED);
-    if (Vector3Distance(target_body_pos, body_pos) > diff) {
-      flags &= ~3;
-      body_pos = target_body_pos;
+  if ((flags & 8) == 0) {
+    if ((flags & 3) == 2) {
+      float diff = Vector3Distance(target_body_pos, body_pos);
+      body_pos = body_pos + Vector3Normalize(target_body_pos - body_pos) *
+                                (dt * BODY_TARGET_SPEED);
+      if (Vector3Distance(target_body_pos, body_pos) > diff) {
+        flags &= ~3;
+        body_pos = target_body_pos;
+      }
+    }
+  } else if ((flags & 0x30) == 0x30) {
+    Vector3 dir = rotationMatrix * Vector3{1.0F, 0.0F, 0.0F};
+    Vector3 prev_body_pos = body_pos;
+    body_pos = body_pos + dir * (dt * BODY_TARGET_SPEED);
+    if (body_pos.x < SURFACE_X_OFFSET - (float)SURFACE_UNIT_WIDTH ||
+        body_pos.x > SURFACE_X_OFFSET + (float)SURFACE_UNIT_WIDTH ||
+        body_pos.z < SURFACE_Y_OFFSET - (float)SURFACE_UNIT_HEIGHT ||
+        body_pos.z > SURFACE_Y_OFFSET + (float)SURFACE_UNIT_HEIGHT) {
+      body_pos = prev_body_pos;
     }
+    target_body_pos = body_pos + dir * 1.0F;
   }
 
   // moving legs
-  const Matrix rotationMatrix = get_rotation_matrix_about_y(rotation);
   const auto update_leg_fn = [this, &bbs, dt, &rotationMatrix](
                                  Vector3 &leg_target, Vector3 &leg_pos,
                                  unsigned int &flags,
@@ -271,10 +309,24 @@ void Walker::update(float dt, const std::array<BoundingBox, BBCount> &bbs,
                 ((nw_flags & 7) == 1 ? 1 : 0) + ((ne_flags & 7) == 1 ? 1 : 0) +
                     ((se_flags & 7) == 1 ? 1 : 0));
 
-  if ((flags & 3) == 0) {
-    body_idle_move_timer += dt * BODY_IDLE_TIMER_RATE;
-    if (body_idle_move_timer > PI * 2.0F) {
-      body_idle_move_timer -= PI * 2.0F;
+  if ((flags & 8) == 0) {
+    if ((flags & 3) == 0) {
+      body_idle_move_timer += dt * BODY_IDLE_TIMER_RATE;
+      if (body_idle_move_timer > PI * 2.0F) {
+        body_idle_move_timer -= PI * 2.0F;
+      }
+    } else if (!FloatEquals(body_idle_move_timer, 0.0F)) {
+      if (body_idle_move_timer < PI) {
+        body_idle_move_timer += dt * BODY_IDLE_TIMER_RATE;
+        if (body_idle_move_timer > PI) {
+          body_idle_move_timer = 0;
+        }
+      } else {
+        body_idle_move_timer += dt * BODY_IDLE_TIMER_RATE;
+        if (body_idle_move_timer > PI * 2.0F) {
+          body_idle_move_timer = 0.0F;
+        }
+      }
     }
   } else if (!FloatEquals(body_idle_move_timer, 0.0F)) {
     if (body_idle_move_timer < PI) {