Impl. controlling a walker
All checks were successful
Build and Publish WASM version of demo / Build-And-Deploy (push) Successful in 18s
All checks were successful
Build and Publish WASM version of demo / Build-And-Deploy (push) Successful in 18s
This commit is contained in:
parent
64c5bcd1bc
commit
5008dd2067
4 changed files with 239 additions and 42 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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; }
|
||||
|
|
128
src/walker.h
128
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 <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;
|
||||
}
|
||||
} 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<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) {
|
||||
|
|
Loading…
Reference in a new issue