From 5008dd2067ce82983c75f4b713e2e96f2c66456f Mon Sep 17 00:00:00 2001 From: Stephen Seo Date: Tue, 15 Aug 2023 11:53:26 +0900 Subject: [PATCH] Impl. controlling a walker --- src/screen_trunner.cc | 105 ++++++++++++++++++++++++++++++++-- src/screen_trunner.h | 6 ++ src/walker.cc | 42 ++++++++++++++ src/walker.h | 128 +++++++++++++++++++++++++++++------------- 4 files changed, 239 insertions(+), 42 deletions(-) diff --git a/src/screen_trunner.cc b/src/screen_trunner.cc index 2e95e80..8962617 100644 --- a/src/screen_trunner.cc +++ b/src/screen_trunner.cc @@ -10,6 +10,7 @@ #endif // third party includes +#include #include // local includes @@ -45,7 +46,11 @@ TRunnerScreen::TRunnerScreen(std::weak_ptr 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; diff --git a/src/screen_trunner.h b/src/screen_trunner.h index d375309..57ec1e1 100644 --- a/src/screen_trunner.h +++ b/src/screen_trunner.h @@ -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 stack); @@ -67,6 +69,10 @@ class TRunnerScreen : public Screen { Vector3 camera_target; Vector3 mouse_hit; unsigned int idx_hit; + std::optional controlled_walker_idx; + const int left_text_width; + const int right_text_width; + const int forward_text_width; void camera_to_targets(float dt); }; diff --git a/src/walker.cc b/src/walker.cc index abc284c..be02e14 100644 --- a/src/walker.cc +++ b/src/walker.cc @@ -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; } diff --git a/src/walker.h b/src/walker.h index d05ea70..53ad022 100644 --- a/src/walker.h +++ b/src/walker.h @@ -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 void Walker::update(float dt, const std::array &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 &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; - } - } 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; + + if (std::abs(target_rotation - rotation) < dt * BODY_ROTATION_SPEED) { + rotation = target_rotation; + flags &= ~3; + flags |= 2; } } - - if (std::abs(target_rotation - rotation) < dt * BODY_ROTATION_SPEED) { - rotation = target_rotation; - flags &= ~3; - flags |= 2; + } else { + if ((flags & 0x30) == 0x10) { + rotation += dt * BODY_ROTATION_SPEED; + } else if ((flags & 0x30) == 0x20) { + rotation -= dt * BODY_ROTATION_SPEED; } } + + 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 &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) {