]> git.seodisparate.com - jumpartifact.com_demo_0/commitdiff
Impl. walker thing
authorStephen Seo <seo.disparate@gmail.com>
Thu, 10 Aug 2023 04:28:45 +0000 (13:28 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Thu, 10 Aug 2023 04:28:45 +0000 (13:28 +0900)
Probably requires some more tweaking to get it working properly. Also
need to create a model/texture for the walker.

Makefile
src/screen_trunner.cc
src/screen_trunner.h
src/walker.cc [new file with mode: 0644]
src/walker.h [new file with mode: 0644]
wasm_build/Makefile

index 09c40267a8879600f6ee1bb4756626a7ddc878f4..36103dd9428910535ef7d7eeeb1ecad6344f6bed 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,8 @@ SOURCES = \
                src/screen_trunner.cc \
                src/3d_helpers.cc \
                src/raymath.cc \
-               src/ems.cc
+               src/ems.cc \
+               src/walker.cc
 
 HEADERS = \
                src/game.h \
@@ -25,7 +26,8 @@ HEADERS = \
                src/screen_test.h \
                src/screen_trunner.h \
                src/3d_helpers.h \
-               src/ems.h
+               src/ems.h \
+               src/walker.h
 
 OBJECTS = $(addprefix ${OBJDIR}/,$(subst .cc,.cc.o,${SOURCES}))
 
index 1f41f6926886bbd0ff3a66b0c8774600620243fe..c652728004166b7b82900cc781e9a0321385cf8f 100644 (file)
@@ -20,6 +20,7 @@ TRunnerScreen::TRunnerScreen(std::weak_ptr<ScreenStack> stack)
     : Screen(stack),
       surface(),
       surface_bbs(),
+      walker(),
       camera{Vector3{0.0F, 1.0F, 0.5F}, Vector3{0.0F, 0.0F, 0.0F},
              Vector3{0.0F, 1.0F, 0.0F}, 80.0F, CAMERA_PERSPECTIVE},
       flags(),
@@ -240,6 +241,7 @@ bool TRunnerScreen::update(float dt) {
         this->camera_target.y =
             (current.nw + current.ne + current.sw + current.se) / 4.0F;
         this->camera_target.z = zf;
+        this->walker.set_body_pos(this->camera_target);
         if (idx != SURFACE_UNIT_WIDTH / 2 +
                        (SURFACE_UNIT_HEIGHT / 2) * SURFACE_UNIT_WIDTH) {
           this->camera_pos = Vector3Add(
@@ -251,6 +253,7 @@ bool TRunnerScreen::update(float dt) {
           this->camera_pos.y = this->camera_target.y + 4.0F;
           this->camera_pos.z = 0.0F;
         }
+        this->camera_target.y += 1.0F;
       };
 
       if (auto bb_collision = GetRayCollisionBox(ray, surface_bbs[idx]);
@@ -270,6 +273,8 @@ bool TRunnerScreen::update(float dt) {
 
   camera_to_targets(dt);
 
+  walker.update(dt, surface_bbs, SURFACE_UNIT_WIDTH, SURFACE_UNIT_HEIGHT);
+
   return false;
 }
 
@@ -310,6 +315,8 @@ bool TRunnerScreen::draw() {
   //                 .bindPose = TEMP_cube_model.bindPose},
   //           Vector3{0.0F, 0.0F, -4.0F}, 1.0F, WHITE);
 
+  walker.draw(TEMP_cube_model);
+
   // TODO DEBUG
   DrawLine3D(Vector3{0.0F, 3.0F, 0.0F}, mouse_hit, BLACK);
 
index ff55e1fc70a9eb719bbb6c44629dbc285c0f02b3..24e6c234b0c0cf814827a39741734fe8a4e4476a 100644 (file)
@@ -11,6 +11,9 @@
 // third party includes
 #include <raylib.h>
 
+// local includes
+#include "walker.h"
+
 constexpr float POS_VALUE_INC_RATE = 0.2F;
 constexpr float CAMERA_UPDATE_RATE = 1.0F;
 
@@ -57,6 +60,9 @@ class TRunnerScreen : public Screen {
              SURFACE_UNIT_WIDTH * SURFACE_UNIT_HEIGHT>
       surface;
   std::array<BoundingBox, SURFACE_UNIT_WIDTH * SURFACE_UNIT_HEIGHT> surface_bbs;
+
+  Walker walker;
+
   Camera3D camera;
   std::bitset<64> flags;
   Model TEMP_cube_model;
diff --git a/src/walker.cc b/src/walker.cc
new file mode 100644 (file)
index 0000000..44bba1b
--- /dev/null
@@ -0,0 +1,71 @@
+#include "walker.h"
+
+// third party includes
+#include <raymath.h>
+
+// local includes
+#include "ems.h"
+
+Walker::Walker(float body_height, float body_feet_radius, float feet_radius)
+    : body_pos{0.0F, body_height, 0.0F},
+      target_body_pos{0.0F, body_height, 0.0F},
+      leg_nw(),
+      leg_ne(),
+      leg_sw(),
+      leg_se(),
+      target_leg_nw(),
+      target_leg_ne(),
+      target_leg_sw(),
+      target_leg_se(),
+      nw_flags(0x0),
+      ne_flags(0x08),
+      sw_flags(0x10),
+      se_flags(0x18),
+      flags(0),
+      body_height(body_height),
+      body_feet_radius(body_feet_radius),
+      feet_radius(feet_radius),
+      lift_start_y(0.0F) {
+  const Vector3 nw = Vector3Normalize(Vector3{-1.0F, 0.0F, -1.0F});
+  const Vector3 ne = Vector3Normalize(Vector3{1.0F, 0.0F, -1.0F});
+  const Vector3 sw = Vector3Normalize(Vector3{-1.0F, 0.0F, 1.0F});
+  const Vector3 se = Vector3Normalize(Vector3{1.0F, 0.0F, 1.0F});
+
+  leg_nw = Vector3Add(
+      Vector3{(call_js_get_random() - 0.5F) / FEET_INIT_POS_VARIANCE_DIV, 0.0F,
+              (call_js_get_random() - 0.5F) / FEET_INIT_POS_VARIANCE_DIV},
+      Vector3Scale(nw, body_feet_radius));
+  target_leg_nw = leg_nw;
+  leg_ne = Vector3Add(
+      Vector3{(call_js_get_random() - 0.5F) / FEET_INIT_POS_VARIANCE_DIV, 0.0F,
+              (call_js_get_random() - 0.5F) / FEET_INIT_POS_VARIANCE_DIV},
+      Vector3Scale(ne, body_feet_radius));
+  target_leg_ne = leg_ne;
+  leg_sw = Vector3Add(
+      Vector3{(call_js_get_random() - 0.5F) / FEET_INIT_POS_VARIANCE_DIV, 0.0F,
+              (call_js_get_random() - 0.5F) / FEET_INIT_POS_VARIANCE_DIV},
+      Vector3Scale(sw, body_feet_radius));
+  target_leg_sw = leg_sw;
+  leg_se = Vector3Add(
+      Vector3{(call_js_get_random() - 0.5F) / FEET_INIT_POS_VARIANCE_DIV, 0.0F,
+              (call_js_get_random() - 0.5F) / FEET_INIT_POS_VARIANCE_DIV},
+      Vector3Scale(se, body_feet_radius));
+  target_leg_se = leg_se;
+}
+
+void Walker::draw(const Model &model) {
+  // draw body
+  DrawModel(model, body_pos, 1.0F, WHITE);
+
+  // draw legs
+  DrawModel(model, leg_nw, 1.0F, WHITE);
+  DrawModel(model, leg_ne, 1.0F, WHITE);
+  DrawModel(model, leg_sw, 1.0F, WHITE);
+  DrawModel(model, leg_se, 1.0F, WHITE);
+}
+
+void Walker::set_body_pos(Vector3 pos) {
+  target_body_pos = pos;
+  target_body_pos.y += body_height;
+  flags &= ~1;
+}
diff --git a/src/walker.h b/src/walker.h
new file mode 100644 (file)
index 0000000..b9f6ce9
--- /dev/null
@@ -0,0 +1,227 @@
+#ifndef JUMPARTIFACT_DOT_COM_DEMO_0_WALKER_H_
+#define JUMPARTIFACT_DOT_COM_DEMO_0_WALKER_H_
+
+// standard library includes
+#include <array>
+
+// third party includes
+#include <raylib.h>
+#include <raymath.h>
+
+constexpr float FEET_RADIUS_PLACEMENT_CHECK_SCALE = 1.0F;
+constexpr float FEET_RADIUS_PLACEMENT_SCALE = 0.9F;
+constexpr float FEET_TARGET_RATE = 1.0F;
+constexpr float BODY_TARGET_SPEED = 1.5F;
+constexpr float FEET_LIFT_HEIGHT = 1.0F;
+constexpr float FEET_LIFT_SPEED = 5.0F;
+constexpr float FEET_HORIZ_MOVE_SPEED = 7.0F;
+constexpr float FEET_INIT_POS_VARIANCE_DIV = 4.0F;
+
+class Walker {
+ public:
+  Walker(float body_height = 2.0F, float body_feet_radius = 1.7F,
+         float feet_radius = 1.5F);
+
+  template <typename TBBS>
+  void update(float dt, const TBBS &bbs, unsigned int width,
+              unsigned int height);
+
+  void draw(const Model &model);
+
+  void set_body_pos(Vector3 pos);
+
+ private:
+  Vector3 body_pos;
+  Vector3 target_body_pos;
+
+  Vector3 leg_nw, leg_ne, leg_sw, leg_se;
+  Vector3 target_leg_nw, target_leg_ne, target_leg_sw, target_leg_se;
+  // ???? ?000 - initialized
+  // ???? ?001 - grounded
+  // ???? ?010 - lifting
+  // ???? ?011 - lifted, horizontally moving to next pos
+  // ???? ?100 - lowering to next pos
+  // ???0 0??? - is nw
+  // ???0 1??? - is ne
+  // ???1 0??? - is sw
+  // ???1 1??? - is se
+  unsigned int nw_flags, ne_flags, sw_flags, se_flags;
+  // ???? ???1 - body stopped
+  unsigned int flags;
+
+  const float body_height;
+  const float body_feet_radius;
+  const float feet_radius;
+  float lift_start_y;
+};
+
+template <typename TBBS>
+void Walker::update(float dt, const TBBS &bbs, unsigned int width,
+                    unsigned int height) {
+  const auto initialized_setup_fn = [&bbs](Vector3 &leg, Vector3 &leg_target) {
+    Ray downwards{.position = leg, .direction = Vector3{0.0F, -1.0F, 0.0F}};
+    for (const auto &bb : bbs) {
+      if (GetRayCollisionBox(downwards, bb).hit) {
+        leg_target.y = (bb.min.y + bb.max.y) / 2.0F;
+        break;
+      }
+    }
+  };
+
+  if ((nw_flags & 7) == 0) {
+    initialized_setup_fn(leg_nw, target_leg_nw);
+    nw_flags |= 1;
+  }
+  if ((ne_flags & 7) == 0) {
+    initialized_setup_fn(leg_ne, target_leg_ne);
+    ne_flags |= 1;
+  }
+  if ((sw_flags & 7) == 0) {
+    initialized_setup_fn(leg_sw, target_leg_sw);
+    sw_flags |= 1;
+  }
+  if ((se_flags & 7) == 0) {
+    initialized_setup_fn(leg_se, target_leg_se);
+    se_flags |= 1;
+  }
+
+  // body to target pos
+  if ((flags & 1) == 0) {
+    float diff = Vector3Distance(target_body_pos, body_pos);
+    body_pos =
+        Vector3Add(body_pos, Vector3Scale(Vector3Normalize(Vector3Subtract(
+                                              target_body_pos, body_pos)),
+                                          dt * BODY_TARGET_SPEED));
+    if (Vector3Distance(target_body_pos, body_pos) > diff) {
+      flags |= 1;
+      body_pos = target_body_pos;
+    }
+  }
+
+  // moving legs
+  const auto update_leg_fn = [this, &bbs, dt](Vector3 &leg_target,
+                                              Vector3 &leg_pos,
+                                              unsigned int &flags,
+                                              unsigned int grounded_count) {
+    if ((flags & 7) == 1 && grounded_count > 1) {
+      // Grounded.
+      bool should_lift = false;
+      Vector3 body_pos_same_y = this->body_pos;
+      body_pos_same_y.y = leg_target.y;
+      Vector3 ideal_foot_pos;
+      if ((flags & 0x18) == 0) {
+        // Is nw.
+        ideal_foot_pos = Vector3Normalize(Vector3{-1.0F, 0.0F, -1.0F});
+      } else if ((flags & 0x18) == 0x8) {
+        // Is ne.
+        ideal_foot_pos = Vector3Normalize(Vector3{1.0F, 0.0F, -1.0F});
+      } else if ((flags & 0x18) == 0x10) {
+        // Is sw.
+        ideal_foot_pos = Vector3Normalize(Vector3{-1.0F, 0.0F, 1.0F});
+      } else if ((flags & 0x18) == 0x18) {
+        // Is se.
+        ideal_foot_pos = Vector3Normalize(Vector3{1.0F, 0.0F, 1.0F});
+      }
+      ideal_foot_pos =
+          Vector3Add(body_pos_same_y,
+                     Vector3Scale(ideal_foot_pos, this->body_feet_radius));
+      // Check if body is past threshold.
+      if (Vector3Distance(ideal_foot_pos, leg_target) >
+          FEET_RADIUS_PLACEMENT_CHECK_SCALE * this->feet_radius) {
+        should_lift = true;
+        Vector3 diff = Vector3Subtract(this->target_body_pos, this->body_pos);
+        if (Vector3Length(diff) > 0.1F) {
+          Vector3 dir = Vector3Normalize(diff);
+          leg_target =
+              Vector3Add(ideal_foot_pos,
+                         Vector3Scale(dir, this->feet_radius *
+                                               FEET_RADIUS_PLACEMENT_SCALE));
+        } else {
+          Vector3 dir =
+              Vector3Normalize(Vector3Subtract(ideal_foot_pos, leg_target));
+          leg_target =
+              Vector3Add(ideal_foot_pos,
+                         Vector3Scale(dir, this->feet_radius *
+                                               FEET_RADIUS_PLACEMENT_SCALE));
+        }
+        // Get average .y of ground at target position.
+        Ray downwards{.position = Vector3{leg_target.x, leg_target.y + 5.0F,
+                                          leg_target.z},
+                      .direction = Vector3{0.0F, -1.0F, 0.0F}};
+        for (const auto &bb : bbs) {
+          if (GetRayCollisionBox(downwards, bb).hit) {
+            leg_target.y = (bb.min.y + bb.max.y) / 2.0F;
+          }
+        }
+      }
+      if (should_lift) {
+        this->lift_start_y = leg_pos.y;
+        flags = (flags & ~7) | 2;
+      }
+    }
+    if ((flags & 7) == 2) {
+      // Lifting.
+      leg_pos.y += dt * FEET_LIFT_SPEED;
+      if (leg_pos.y > this->lift_start_y + FEET_LIFT_HEIGHT) {
+        leg_pos.y = this->lift_start_y + FEET_LIFT_HEIGHT;
+        flags = (flags & ~7) | 3;
+      }
+    }
+    if ((flags & 7) == 3) {
+      // Moving horizontally.
+      float prev_dist = Vector3Distance(
+          leg_pos, Vector3{leg_target.x, leg_pos.y, leg_target.z});
+      Vector3 dir = Vector3Normalize(Vector3Subtract(
+          Vector3{leg_target.x, leg_pos.y, leg_target.z}, leg_pos));
+      leg_pos =
+          Vector3Add(leg_pos, Vector3Scale(dir, dt * FEET_HORIZ_MOVE_SPEED));
+      if (Vector3Distance(leg_pos, Vector3{leg_target.x, leg_pos.y,
+                                           leg_target.z}) >= prev_dist) {
+        leg_pos.x = leg_target.x;
+        leg_pos.z = leg_target.z;
+        flags = (flags & ~7) | 4;
+      }
+    }
+    if ((flags & 7) == 4) {
+      // Lowering leg.
+      leg_pos.y -= dt * FEET_LIFT_SPEED;
+      if (leg_pos.y < leg_target.y) {
+        leg_pos.y = leg_target.y;
+        flags = (flags & ~7) | 1;
+      }
+    }
+  };
+
+  update_leg_fn(target_leg_nw, leg_nw, nw_flags,
+                ((ne_flags & 7) == 1 ? 1 : 0) + ((sw_flags & 7) == 1 ? 1 : 0) +
+                    ((se_flags & 7) == 1 ? 1 : 0));
+  update_leg_fn(target_leg_sw, leg_sw, sw_flags,
+                ((nw_flags & 7) == 1 ? 1 : 0) + ((ne_flags & 7) == 1 ? 1 : 0) +
+                    ((se_flags & 7) == 1 ? 1 : 0));
+  update_leg_fn(target_leg_ne, leg_ne, ne_flags,
+                ((nw_flags & 7) == 1 ? 1 : 0) + ((sw_flags & 7) == 1 ? 1 : 0) +
+                    ((se_flags & 7) == 1 ? 1 : 0));
+  update_leg_fn(target_leg_se, leg_se, se_flags,
+                ((nw_flags & 7) == 1 ? 1 : 0) + ((ne_flags & 7) == 1 ? 1 : 0) +
+                    ((sw_flags & 7) == 1 ? 1 : 0));
+
+  // legs to target pos
+  //  leg_nw =
+  //      Vector3Add(leg_nw, Vector3Scale(Vector3Subtract(target_leg_nw,
+  //      leg_nw),
+  //                                      dt * FEET_TARGET_RATE));
+  //  leg_ne =
+  //      Vector3Add(leg_ne, Vector3Scale(Vector3Subtract(target_leg_ne,
+  //      leg_ne),
+  //                                      dt * FEET_TARGET_RATE));
+  //  leg_sw =
+  //      Vector3Add(leg_sw, Vector3Scale(Vector3Subtract(target_leg_sw,
+  //      leg_sw),
+  //                                      dt * FEET_TARGET_RATE));
+  //  leg_se =
+  //      Vector3Add(leg_se, Vector3Scale(Vector3Subtract(target_leg_se,
+  //      leg_se),
+  //                                      dt * FEET_TARGET_RATE));
+}
+
+#endif
index 263416140e5894a1e77c415c2b393dfe4c37196f..e237bb9c4a2903c3909d24154537b6b731383fec 100644 (file)
@@ -12,7 +12,8 @@ SOURCES = \
                ../src/screen_test.cc \
                ../src/screen_trunner.cc \
                ../src/3d_helpers.cc \
-               ../src/raymath.cc
+               ../src/raymath.cc \
+               ../src/walker.cc
 
 HEADERS = \
                ../src/ems.h \
@@ -20,7 +21,8 @@ HEADERS = \
                ../src/screen.h \
                ../src/screen_test.h \
                ../src/screen_trunner.h \
-               ../src/3d_helpers.h
+               ../src/3d_helpers.h \
+               ../src/walker.h
 
 CXX = source ${HOME}/git/emsdk/emsdk_env.sh && em++