From 0c23c593c072f59d6f9e3d89ccca58addb1dd04d Mon Sep 17 00:00:00 2001 From: Stephen Seo Date: Thu, 10 Aug 2023 13:28:45 +0900 Subject: [PATCH] Impl. walker thing Probably requires some more tweaking to get it working properly. Also need to create a model/texture for the walker. --- Makefile | 6 +- src/screen_trunner.cc | 7 ++ src/screen_trunner.h | 6 ++ src/walker.cc | 71 +++++++++++++ src/walker.h | 227 ++++++++++++++++++++++++++++++++++++++++++ wasm_build/Makefile | 6 +- 6 files changed, 319 insertions(+), 4 deletions(-) create mode 100644 src/walker.cc create mode 100644 src/walker.h diff --git a/Makefile b/Makefile index 09c4026..36103dd 100644 --- 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})) diff --git a/src/screen_trunner.cc b/src/screen_trunner.cc index 1f41f69..c652728 100644 --- a/src/screen_trunner.cc +++ b/src/screen_trunner.cc @@ -20,6 +20,7 @@ TRunnerScreen::TRunnerScreen(std::weak_ptr 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); diff --git a/src/screen_trunner.h b/src/screen_trunner.h index ff55e1f..24e6c23 100644 --- a/src/screen_trunner.h +++ b/src/screen_trunner.h @@ -11,6 +11,9 @@ // third party includes #include +// 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 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 index 0000000..44bba1b --- /dev/null +++ b/src/walker.cc @@ -0,0 +1,71 @@ +#include "walker.h" + +// third party includes +#include + +// 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 index 0000000..b9f6ce9 --- /dev/null +++ b/src/walker.h @@ -0,0 +1,227 @@ +#ifndef JUMPARTIFACT_DOT_COM_DEMO_0_WALKER_H_ +#define JUMPARTIFACT_DOT_COM_DEMO_0_WALKER_H_ + +// standard library includes +#include + +// third party includes +#include +#include + +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 + 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 +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 diff --git a/wasm_build/Makefile b/wasm_build/Makefile index 2634161..e237bb9 100644 --- a/wasm_build/Makefile +++ b/wasm_build/Makefile @@ -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++