Impl. resetting surface with neat visual effect
All checks were successful
Build and Publish WASM version of demo / Build-And-Deploy (push) Successful in 21s
All checks were successful
Build and Publish WASM version of demo / Build-And-Deploy (push) Successful in 21s
This commit is contained in:
parent
530920c811
commit
d8b81f29cc
6 changed files with 380 additions and 123 deletions
6
Makefile
6
Makefile
|
@ -18,7 +18,8 @@ SOURCES = \
|
||||||
src/3d_helpers.cc \
|
src/3d_helpers.cc \
|
||||||
src/raymath.cc \
|
src/raymath.cc \
|
||||||
src/ems.cc \
|
src/ems.cc \
|
||||||
src/walker.cc
|
src/walker.cc \
|
||||||
|
src/surface_triangle.cc
|
||||||
|
|
||||||
HEADERS = \
|
HEADERS = \
|
||||||
src/game.h \
|
src/game.h \
|
||||||
|
@ -27,7 +28,8 @@ HEADERS = \
|
||||||
src/screen_trunner.h \
|
src/screen_trunner.h \
|
||||||
src/3d_helpers.h \
|
src/3d_helpers.h \
|
||||||
src/ems.h \
|
src/ems.h \
|
||||||
src/walker.h
|
src/walker.h \
|
||||||
|
src/surface_triangle.h
|
||||||
|
|
||||||
OBJECTS = $(addprefix ${OBJDIR}/,$(subst .cc,.cc.o,${SOURCES}))
|
OBJECTS = $(addprefix ${OBJDIR}/,$(subst .cc,.cc.o,${SOURCES}))
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ TRunnerScreen::TRunnerScreen(std::weak_ptr<ScreenStack> stack)
|
||||||
: Screen(stack),
|
: Screen(stack),
|
||||||
surface(),
|
surface(),
|
||||||
surface_bbs(),
|
surface_bbs(),
|
||||||
|
surface_triangles(),
|
||||||
// NOLINTBEGIN(bugprone-integer-division)
|
// NOLINTBEGIN(bugprone-integer-division)
|
||||||
walkers{Walker{(float)(SURFACE_UNIT_WIDTH / 4) - SURFACE_X_OFFSET,
|
walkers{Walker{(float)(SURFACE_UNIT_WIDTH / 4) - SURFACE_X_OFFSET,
|
||||||
(float)(SURFACE_UNIT_HEIGHT / 4) - SURFACE_Y_OFFSET, true},
|
(float)(SURFACE_UNIT_HEIGHT / 4) - SURFACE_Y_OFFSET, true},
|
||||||
|
@ -42,6 +43,8 @@ TRunnerScreen::TRunnerScreen(std::weak_ptr<ScreenStack> stack)
|
||||||
TEMP_cube_model(LoadModel("res/test_cube.obj")),
|
TEMP_cube_model(LoadModel("res/test_cube.obj")),
|
||||||
TEMP_cube_texture(LoadTexture("res/test_cube_texture.png")),
|
TEMP_cube_texture(LoadTexture("res/test_cube_texture.png")),
|
||||||
TEMP_matrix(get_identity_matrix()),
|
TEMP_matrix(get_identity_matrix()),
|
||||||
|
bgRenderTexture(),
|
||||||
|
fgRenderTexture(),
|
||||||
camera_pos{0.0F, 4.0F, 4.0F},
|
camera_pos{0.0F, 4.0F, 4.0F},
|
||||||
camera_target{0.0F, 0.0F, 0.0F},
|
camera_target{0.0F, 0.0F, 0.0F},
|
||||||
mouse_hit{0.0F, 0.0F, 0.0F},
|
mouse_hit{0.0F, 0.0F, 0.0F},
|
||||||
|
@ -50,7 +53,9 @@ TRunnerScreen::TRunnerScreen(std::weak_ptr<ScreenStack> stack)
|
||||||
controlled_walker_idx(std::nullopt),
|
controlled_walker_idx(std::nullopt),
|
||||||
left_text_width(MeasureText("Left", BUTTON_FONT_SIZE)),
|
left_text_width(MeasureText("Left", BUTTON_FONT_SIZE)),
|
||||||
right_text_width(MeasureText("Right", BUTTON_FONT_SIZE)),
|
right_text_width(MeasureText("Right", BUTTON_FONT_SIZE)),
|
||||||
forward_text_width(MeasureText("Forward", BUTTON_FONT_SIZE)) {
|
forward_text_width(MeasureText("Forward", BUTTON_FONT_SIZE)),
|
||||||
|
reset_surface_text_width(MeasureText("Reset Surface", BUTTON_FONT_SIZE)),
|
||||||
|
surface_reset_anim_timer(0.0F) {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
std::cout << "idx_hit initialized to " << idx_hit << std::endl;
|
std::cout << "idx_hit initialized to " << idx_hit << std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
@ -63,17 +68,32 @@ TRunnerScreen::TRunnerScreen(std::weak_ptr<ScreenStack> stack)
|
||||||
// Initialize surface.
|
// Initialize surface.
|
||||||
generate_surface();
|
generate_surface();
|
||||||
|
|
||||||
|
// Set up render textures
|
||||||
|
bgRenderTexture = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
|
||||||
|
fgRenderTexture = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
std::cout << "Screen finished init.\n";
|
std::cout << "Screen finished init.\n";
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
TRunnerScreen::~TRunnerScreen() {
|
TRunnerScreen::~TRunnerScreen() {
|
||||||
|
UnloadRenderTexture(fgRenderTexture);
|
||||||
|
UnloadRenderTexture(bgRenderTexture);
|
||||||
|
|
||||||
UnloadTexture(TEMP_cube_texture);
|
UnloadTexture(TEMP_cube_texture);
|
||||||
UnloadModel(TEMP_cube_model);
|
UnloadModel(TEMP_cube_model);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TRunnerScreen::update(float dt) {
|
bool TRunnerScreen::update(float dt) {
|
||||||
|
if (IsWindowResized()) {
|
||||||
|
UnloadRenderTexture(fgRenderTexture);
|
||||||
|
UnloadRenderTexture(bgRenderTexture);
|
||||||
|
|
||||||
|
bgRenderTexture = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
|
||||||
|
fgRenderTexture = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
|
||||||
|
}
|
||||||
|
|
||||||
if (controlled_walker_idx.has_value()) {
|
if (controlled_walker_idx.has_value()) {
|
||||||
auto walker_body_pos =
|
auto walker_body_pos =
|
||||||
walkers[controlled_walker_idx.value()].get_body_pos();
|
walkers[controlled_walker_idx.value()].get_body_pos();
|
||||||
|
@ -89,138 +109,162 @@ bool TRunnerScreen::update(float dt) {
|
||||||
camera_pos = walkers[controlled_walker_idx.value()].get_body_pos() + offset;
|
camera_pos = walkers[controlled_walker_idx.value()].get_body_pos() + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (controlled_walker_idx.has_value() && IsMouseButtonDown(0)) {
|
if (!flags.test(0)) {
|
||||||
// Check if clicked on button.
|
if (controlled_walker_idx.has_value() && IsMouseButtonDown(0)) {
|
||||||
if (!walkers[controlled_walker_idx.value()].player_is_turning_left() &&
|
// Check if clicked on button.
|
||||||
GetTouchX() >= 0 && GetTouchX() <= left_text_width &&
|
if (!walkers[controlled_walker_idx.value()].player_is_turning_left() &&
|
||||||
GetTouchY() >= GetScreenHeight() - BUTTON_FONT_SIZE &&
|
GetTouchX() >= 0 && GetTouchX() <= left_text_width &&
|
||||||
GetTouchY() <= GetScreenHeight()) {
|
GetTouchY() >= GetScreenHeight() - BUTTON_FONT_SIZE &&
|
||||||
walkers[controlled_walker_idx.value()].player_turn_left();
|
GetTouchY() <= GetScreenHeight()) {
|
||||||
goto post_check_click;
|
walkers[controlled_walker_idx.value()].player_turn_left();
|
||||||
} else if (!walkers[controlled_walker_idx.value()]
|
|
||||||
.player_is_turning_right() &&
|
|
||||||
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 (!walkers[controlled_walker_idx.value()]
|
|
||||||
.player_is_going_forward()) {
|
|
||||||
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;
|
goto post_check_click;
|
||||||
}
|
} else if (!walkers[controlled_walker_idx.value()]
|
||||||
}
|
.player_is_turning_right() &&
|
||||||
} else if (IsMouseButtonReleased(0)) {
|
GetTouchX() >= left_text_width &&
|
||||||
if (controlled_walker_idx.has_value()) {
|
GetTouchX() <= left_text_width + right_text_width &&
|
||||||
walkers[controlled_walker_idx.value()].player_idle();
|
GetTouchY() >= GetScreenHeight() - BUTTON_FONT_SIZE &&
|
||||||
goto post_check_click;
|
GetTouchY() <= GetScreenHeight()) {
|
||||||
}
|
walkers[controlled_walker_idx.value()].player_turn_right();
|
||||||
}
|
goto post_check_click;
|
||||||
|
} else if (!walkers[controlled_walker_idx.value()]
|
||||||
if (IsMouseButtonPressed(0)) {
|
.player_is_going_forward()) {
|
||||||
float press_x = GetTouchX();
|
if (int width_mid = (left_text_width + right_text_width) / 2 -
|
||||||
float press_y = GetTouchY();
|
forward_text_width / 2;
|
||||||
Ray ray = GetMouseRay(Vector2{press_x, press_y}, camera);
|
GetTouchX() >= width_mid &&
|
||||||
#ifndef NDEBUG
|
GetTouchX() <= width_mid + forward_text_width &&
|
||||||
std::cout << "X: " << press_x << ", Y: " << press_y << std::endl;
|
GetTouchY() >= GetScreenHeight() - BUTTON_FONT_SIZE * 2 &&
|
||||||
std::cout << "Ray pos: " << ray.position.x << ", " << ray.position.y << ", "
|
GetTouchY() <= GetScreenHeight() - BUTTON_FONT_SIZE) {
|
||||||
<< ray.position.z << " Ray dir: " << ray.direction.x << ", "
|
walkers[controlled_walker_idx.value()].player_go_forward();
|
||||||
<< ray.direction.y << ", " << ray.direction.z << std::endl;
|
goto post_check_click;
|
||||||
#endif
|
|
||||||
|
|
||||||
// Check if clicked on a Walker.
|
|
||||||
for (unsigned int idx = 0; idx < walkers.size(); ++idx) {
|
|
||||||
if (GetRayCollisionBox(ray, walkers[idx].get_body_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);
|
} else if (IsMouseButtonReleased(0)) {
|
||||||
|
if (controlled_walker_idx.has_value()) {
|
||||||
idx_hit = SURFACE_UNIT_WIDTH * SURFACE_UNIT_HEIGHT;
|
walkers[controlled_walker_idx.value()].player_idle();
|
||||||
|
|
||||||
goto post_check_click;
|
goto post_check_click;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if clicked on ground.
|
if (IsMouseButtonPressed(0)) {
|
||||||
for (unsigned int idx = 0; idx < SURFACE_UNIT_WIDTH * SURFACE_UNIT_HEIGHT;
|
float press_x = GetTouchX();
|
||||||
++idx) {
|
float press_y = GetTouchY();
|
||||||
int x = idx % SURFACE_UNIT_WIDTH;
|
|
||||||
int y = idx / SURFACE_UNIT_WIDTH;
|
|
||||||
float xf = (float)(x)-SURFACE_X_OFFSET;
|
|
||||||
float zf = (float)(y)-SURFACE_Y_OFFSET;
|
|
||||||
|
|
||||||
const auto ¤t = surface[idx].value();
|
// Check if clicked on reset surface.
|
||||||
Vector3 nw{xf - 0.5F, current.nw, zf - 0.5F};
|
if (!flags.test(0) &&
|
||||||
Vector3 ne{xf + 0.5F, current.ne, zf - 0.5F};
|
press_x >= GetScreenWidth() - reset_surface_text_width &&
|
||||||
Vector3 sw{xf - 0.5F, current.sw, zf + 0.5F};
|
press_y <= BUTTON_FONT_SIZE) {
|
||||||
Vector3 se{xf + 0.5F, current.se, zf + 0.5F};
|
generate_surface_with_triangles();
|
||||||
|
goto post_check_click;
|
||||||
|
}
|
||||||
|
|
||||||
const auto on_collide_fn = [this, idx, xf, zf,
|
Ray ray = GetMouseRay(Vector2{press_x, press_y}, camera);
|
||||||
¤t](const auto &collision) {
|
|
||||||
this->idx_hit = idx;
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
std::cout << "idx_hit set to " << idx_hit << std::endl;
|
std::cout << "X: " << press_x << ", Y: " << press_y << std::endl;
|
||||||
|
std::cout << "Ray pos: " << ray.position.x << ", " << ray.position.y
|
||||||
|
<< ", " << ray.position.z << " Ray dir: " << ray.direction.x
|
||||||
|
<< ", " << ray.direction.y << ", " << ray.direction.z
|
||||||
|
<< std::endl;
|
||||||
#endif
|
#endif
|
||||||
this->mouse_hit = collision;
|
|
||||||
|
|
||||||
this->camera_target.x = xf;
|
// Check if clicked on a Walker.
|
||||||
this->camera_target.y =
|
for (unsigned int idx = 0; idx < walkers.size(); ++idx) {
|
||||||
(current.nw + current.ne + current.sw + current.se) / 4.0F;
|
if (GetRayCollisionBox(ray, walkers[idx].get_body_bb()).hit) {
|
||||||
this->camera_target.z = zf;
|
if (controlled_walker_idx.has_value()) {
|
||||||
if (idx != SURFACE_UNIT_WIDTH / 2 +
|
walkers[controlled_walker_idx.value()].set_player_controlled(false);
|
||||||
(SURFACE_UNIT_HEIGHT / 2) * SURFACE_UNIT_WIDTH) {
|
}
|
||||||
this->camera_pos = (Vector3Normalize(this->camera_target) * 4.0F) +
|
controlled_walker_idx = idx;
|
||||||
this->camera_target;
|
walkers[controlled_walker_idx.value()].set_player_controlled(true);
|
||||||
this->camera_pos.y += 4.0F;
|
|
||||||
} else {
|
idx_hit = SURFACE_UNIT_WIDTH * SURFACE_UNIT_HEIGHT;
|
||||||
this->camera_pos.x = 0.0F;
|
|
||||||
this->camera_pos.y = this->camera_target.y + 4.0F;
|
|
||||||
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 (GetRayCollisionBox(ray, surface_bbs[idx]).hit) {
|
|
||||||
if (auto collision = GetRayCollisionTriangle(ray, nw, sw, ne);
|
|
||||||
collision.hit) {
|
|
||||||
on_collide_fn(collision.point);
|
|
||||||
goto post_check_click;
|
|
||||||
} else if (auto collision = GetRayCollisionTriangle(ray, ne, sw, se);
|
|
||||||
collision.hit) {
|
|
||||||
on_collide_fn(collision.point);
|
|
||||||
goto post_check_click;
|
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;
|
||||||
|
int y = idx / SURFACE_UNIT_WIDTH;
|
||||||
|
float xf = (float)(x)-SURFACE_X_OFFSET;
|
||||||
|
float zf = (float)(y)-SURFACE_Y_OFFSET;
|
||||||
|
|
||||||
|
const auto ¤t = surface[idx].value();
|
||||||
|
Vector3 nw{xf - 0.5F, current.nw, zf - 0.5F};
|
||||||
|
Vector3 ne{xf + 0.5F, current.ne, zf - 0.5F};
|
||||||
|
Vector3 sw{xf - 0.5F, current.sw, zf + 0.5F};
|
||||||
|
Vector3 se{xf + 0.5F, current.se, zf + 0.5F};
|
||||||
|
|
||||||
|
const auto on_collide_fn = [this, idx, xf, zf,
|
||||||
|
¤t](const auto &collision) {
|
||||||
|
this->idx_hit = idx;
|
||||||
|
#ifndef NDEBUG
|
||||||
|
std::cout << "idx_hit set to " << idx_hit << std::endl;
|
||||||
|
#endif
|
||||||
|
this->mouse_hit = collision;
|
||||||
|
|
||||||
|
this->camera_target.x = xf;
|
||||||
|
this->camera_target.y =
|
||||||
|
(current.nw + current.ne + current.sw + current.se) / 4.0F;
|
||||||
|
this->camera_target.z = zf;
|
||||||
|
if (idx != SURFACE_UNIT_WIDTH / 2 +
|
||||||
|
(SURFACE_UNIT_HEIGHT / 2) * SURFACE_UNIT_WIDTH) {
|
||||||
|
this->camera_pos = (Vector3Normalize(this->camera_target) * 4.0F) +
|
||||||
|
this->camera_target;
|
||||||
|
this->camera_pos.y += 4.0F;
|
||||||
|
} else {
|
||||||
|
this->camera_pos.x = 0.0F;
|
||||||
|
this->camera_pos.y = this->camera_target.y + 4.0F;
|
||||||
|
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 (GetRayCollisionBox(ray, surface_bbs[idx]).hit) {
|
||||||
|
if (auto collision = GetRayCollisionTriangle(ray, nw, sw, ne);
|
||||||
|
collision.hit) {
|
||||||
|
on_collide_fn(collision.point);
|
||||||
|
goto post_check_click;
|
||||||
|
} else if (auto collision = GetRayCollisionTriangle(ray, ne, sw, se);
|
||||||
|
collision.hit) {
|
||||||
|
on_collide_fn(collision.point);
|
||||||
|
goto post_check_click;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
post_check_click:
|
post_check_click:
|
||||||
|
|
||||||
|
if (flags.test(0)) {
|
||||||
|
surface_reset_anim_timer += dt;
|
||||||
|
if (surface_reset_anim_timer > SURFACE_RESET_TIME) {
|
||||||
|
flags.reset(0);
|
||||||
|
} else {
|
||||||
|
for (auto &tri : surface_triangles) {
|
||||||
|
tri.update(dt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
camera_to_targets(dt);
|
camera_to_targets(dt);
|
||||||
|
|
||||||
for (auto &walker : walkers) {
|
for (auto &walker : walkers) {
|
||||||
walker.update(dt, surface_bbs, SURFACE_UNIT_WIDTH, SURFACE_UNIT_HEIGHT);
|
walker.update(flags.test(0) ? 0.0F : dt, surface_bbs, SURFACE_UNIT_WIDTH,
|
||||||
|
SURFACE_UNIT_HEIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TRunnerScreen::draw() {
|
bool TRunnerScreen::draw() {
|
||||||
BeginDrawing();
|
BeginTextureMode(bgRenderTexture);
|
||||||
ClearBackground(PixelToColor(Pixel::PIXEL_SKY));
|
ClearBackground(PixelToColor(Pixel::PIXEL_SKY));
|
||||||
BeginMode3D(camera);
|
BeginMode3D(camera);
|
||||||
|
|
||||||
|
@ -237,12 +281,20 @@ bool TRunnerScreen::draw() {
|
||||||
: Color{(unsigned char)(200 + ox * 2),
|
: Color{(unsigned char)(200 + ox * 2),
|
||||||
(unsigned char)(150 + oy * 2), 20, 255};
|
(unsigned char)(150 + oy * 2), 20, 255};
|
||||||
const auto ¤t = surface[idx].value();
|
const auto ¤t = surface[idx].value();
|
||||||
DrawTriangle3D(Vector3{xf - 0.5F, current.nw, zf - 0.5F},
|
float reset_y_offset = 0.0F;
|
||||||
Vector3{xf - 0.5F, current.sw, zf + 0.5F},
|
if (flags.test(0)) {
|
||||||
Vector3{xf + 0.5F, current.ne, zf - 0.5F}, color);
|
reset_y_offset = (1.0F - std::sin(surface_reset_anim_timer /
|
||||||
DrawTriangle3D(Vector3{xf + 0.5F, current.se, zf + 0.5F},
|
SURFACE_RESET_TIME * PI / 2.0F)) *
|
||||||
Vector3{xf + 0.5F, current.ne, zf - 0.5F},
|
-SURFACE_RESET_Y_OFFSET;
|
||||||
Vector3{xf - 0.5F, current.sw, zf + 0.5F}, color);
|
}
|
||||||
|
DrawTriangle3D(Vector3{xf - 0.5F, current.nw + reset_y_offset, zf - 0.5F},
|
||||||
|
Vector3{xf - 0.5F, current.sw + reset_y_offset, zf + 0.5F},
|
||||||
|
Vector3{xf + 0.5F, current.ne + reset_y_offset, zf - 0.5F},
|
||||||
|
color);
|
||||||
|
DrawTriangle3D(Vector3{xf + 0.5F, current.se + reset_y_offset, zf + 0.5F},
|
||||||
|
Vector3{xf + 0.5F, current.ne + reset_y_offset, zf - 0.5F},
|
||||||
|
Vector3{xf - 0.5F, current.sw + reset_y_offset, zf + 0.5F},
|
||||||
|
color);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &walker : walkers) {
|
for (auto &walker : walkers) {
|
||||||
|
@ -250,7 +302,7 @@ bool TRunnerScreen::draw() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO DEBUG
|
// TODO DEBUG
|
||||||
if (!controlled_walker_idx.has_value()) {
|
if (!controlled_walker_idx.has_value() && !flags.test(0)) {
|
||||||
DrawLine3D(Vector3{0.0F, 3.0F, 0.0F}, mouse_hit, BLACK);
|
DrawLine3D(Vector3{0.0F, 3.0F, 0.0F}, mouse_hit, BLACK);
|
||||||
|
|
||||||
for (const auto &walker : walkers) {
|
for (const auto &walker : walkers) {
|
||||||
|
@ -262,29 +314,77 @@ bool TRunnerScreen::draw() {
|
||||||
}
|
}
|
||||||
|
|
||||||
EndMode3D();
|
EndMode3D();
|
||||||
|
EndTextureMode();
|
||||||
|
|
||||||
|
BeginTextureMode(fgRenderTexture);
|
||||||
|
ClearBackground(Color{0, 0, 0, 0});
|
||||||
|
if (flags.test(0)) {
|
||||||
|
BeginMode3D(camera);
|
||||||
|
for (unsigned int idx = 0; idx < SURFACE_UNIT_WIDTH * SURFACE_UNIT_HEIGHT;
|
||||||
|
++idx) {
|
||||||
|
int x = idx % SURFACE_UNIT_WIDTH;
|
||||||
|
int y = idx / SURFACE_UNIT_WIDTH;
|
||||||
|
int ox = x - SURFACE_UNIT_WIDTH / 2;
|
||||||
|
int oy = y - SURFACE_UNIT_HEIGHT / 2;
|
||||||
|
Color color = idx == idx_hit
|
||||||
|
? RAYWHITE
|
||||||
|
: Color{(unsigned char)(200 + ox * 2),
|
||||||
|
(unsigned char)(150 + oy * 2), 20, 255};
|
||||||
|
|
||||||
|
if (surface_reset_anim_timer < SURFACE_RESET_TIME_TRI_DRAW) {
|
||||||
|
unsigned char alpha =
|
||||||
|
((1.0F - surface_reset_anim_timer / SURFACE_RESET_TIME_TRI_DRAW) *
|
||||||
|
255.0F);
|
||||||
|
surface_triangles.at(x * 2 + y * SURFACE_UNIT_WIDTH * 2)
|
||||||
|
.draw(Color{color.r, color.g, color.b, alpha});
|
||||||
|
surface_triangles.at(x * 2 + 1 + y * SURFACE_UNIT_WIDTH * 2)
|
||||||
|
.draw(Color{color.r, color.g, color.b, alpha});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EndMode3D();
|
||||||
|
}
|
||||||
|
|
||||||
if (controlled_walker_idx.has_value()) {
|
if (controlled_walker_idx.has_value()) {
|
||||||
int total_width = 0;
|
int total_width = 0;
|
||||||
DrawRectangle(0, GetScreenHeight() - BUTTON_FONT_SIZE, left_text_width,
|
DrawRectangle(0, GetScreenHeight() - BUTTON_FONT_SIZE, left_text_width,
|
||||||
BUTTON_FONT_SIZE, Color{255, 255, 255, 120});
|
BUTTON_FONT_SIZE, Color{255, 255, 255, 180});
|
||||||
DrawText("Left", 0, GetScreenHeight() - BUTTON_FONT_SIZE, BUTTON_FONT_SIZE,
|
DrawText("Left", 0, GetScreenHeight() - BUTTON_FONT_SIZE, BUTTON_FONT_SIZE,
|
||||||
BLACK);
|
BLACK);
|
||||||
|
|
||||||
total_width += left_text_width;
|
total_width += left_text_width;
|
||||||
DrawRectangle(total_width, GetScreenHeight() - BUTTON_FONT_SIZE,
|
DrawRectangle(total_width, GetScreenHeight() - BUTTON_FONT_SIZE,
|
||||||
right_text_width, BUTTON_FONT_SIZE,
|
right_text_width, BUTTON_FONT_SIZE,
|
||||||
Color{255, 255, 255, 120});
|
Color{255, 255, 255, 180});
|
||||||
DrawText("Right", total_width, GetScreenHeight() - BUTTON_FONT_SIZE,
|
DrawText("Right", total_width, GetScreenHeight() - BUTTON_FONT_SIZE,
|
||||||
BUTTON_FONT_SIZE, BLACK);
|
BUTTON_FONT_SIZE, BLACK);
|
||||||
|
|
||||||
total_width = (total_width + right_text_width) / 2 - forward_text_width / 2;
|
total_width = (total_width + right_text_width) / 2 - forward_text_width / 2;
|
||||||
DrawRectangle(total_width, GetScreenHeight() - BUTTON_FONT_SIZE * 2,
|
DrawRectangle(total_width, GetScreenHeight() - BUTTON_FONT_SIZE * 2,
|
||||||
forward_text_width, BUTTON_FONT_SIZE,
|
forward_text_width, BUTTON_FONT_SIZE,
|
||||||
Color{255, 255, 255, 120});
|
Color{255, 255, 255, 180});
|
||||||
DrawText("Forward", total_width, GetScreenHeight() - BUTTON_FONT_SIZE * 2,
|
DrawText("Forward", total_width, GetScreenHeight() - BUTTON_FONT_SIZE * 2,
|
||||||
BUTTON_FONT_SIZE, BLACK);
|
BUTTON_FONT_SIZE, BLACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!flags.test(0)) {
|
||||||
|
DrawRectangle(GetScreenWidth() - reset_surface_text_width, 0,
|
||||||
|
reset_surface_text_width, BUTTON_FONT_SIZE,
|
||||||
|
Color{255, 255, 255, 180});
|
||||||
|
DrawText("Reset Surface", GetScreenWidth() - reset_surface_text_width, 0,
|
||||||
|
BUTTON_FONT_SIZE, BLACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
EndTextureMode();
|
||||||
|
|
||||||
|
BeginDrawing();
|
||||||
|
DrawTextureRec(
|
||||||
|
bgRenderTexture.texture,
|
||||||
|
Rectangle{0, 0, (float)GetScreenWidth(), (float)-GetScreenHeight()},
|
||||||
|
{0, 0}, WHITE);
|
||||||
|
DrawTextureRec(
|
||||||
|
fgRenderTexture.texture,
|
||||||
|
Rectangle{0, 0, (float)GetScreenWidth(), (float)-GetScreenHeight()},
|
||||||
|
{0, 0}, WHITE);
|
||||||
EndDrawing();
|
EndDrawing();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -496,3 +596,10 @@ void TRunnerScreen::generate_surface() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TRunnerScreen::generate_surface_with_triangles() {
|
||||||
|
surface_triangles = surface_to_triangles(surface, SURFACE_UNIT_WIDTH);
|
||||||
|
generate_surface();
|
||||||
|
surface_reset_anim_timer = 0.0F;
|
||||||
|
flags.set(0);
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
// local includes
|
// local includes
|
||||||
#include "common_constants.h"
|
#include "common_constants.h"
|
||||||
|
#include "surface_triangle.h"
|
||||||
#include "walker.h"
|
#include "walker.h"
|
||||||
|
|
||||||
constexpr float POS_VALUE_INC_RATE = 0.2F;
|
constexpr float POS_VALUE_INC_RATE = 0.2F;
|
||||||
|
@ -22,8 +23,16 @@ constexpr float SURFACE_HEIGHT_INTERVAL = 0.7F;
|
||||||
|
|
||||||
constexpr int BUTTON_FONT_SIZE = 30;
|
constexpr int BUTTON_FONT_SIZE = 30;
|
||||||
|
|
||||||
|
constexpr float SURFACE_RESET_TIME = 4.0F;
|
||||||
|
constexpr float SURFACE_RESET_TIME_TRI_DRAW = 3.0F;
|
||||||
|
constexpr float SURFACE_RESET_Y_OFFSET = 40.0F;
|
||||||
|
|
||||||
class TRunnerScreen : public Screen {
|
class TRunnerScreen : public Screen {
|
||||||
public:
|
public:
|
||||||
|
struct SurfaceUnit {
|
||||||
|
float nw, ne, sw, se;
|
||||||
|
};
|
||||||
|
|
||||||
TRunnerScreen(std::weak_ptr<ScreenStack> stack);
|
TRunnerScreen(std::weak_ptr<ScreenStack> stack);
|
||||||
~TRunnerScreen() override;
|
~TRunnerScreen() override;
|
||||||
|
|
||||||
|
@ -47,24 +56,26 @@ class TRunnerScreen : public Screen {
|
||||||
PIXEL_WHITE
|
PIXEL_WHITE
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SurfaceUnit {
|
|
||||||
float nw, ne, sw, se;
|
|
||||||
};
|
|
||||||
|
|
||||||
static Color PixelToColor(Pixel p);
|
static Color PixelToColor(Pixel p);
|
||||||
|
|
||||||
std::array<std::optional<SurfaceUnit>,
|
std::array<std::optional<SurfaceUnit>,
|
||||||
SURFACE_UNIT_WIDTH * SURFACE_UNIT_HEIGHT>
|
SURFACE_UNIT_WIDTH * SURFACE_UNIT_HEIGHT>
|
||||||
surface;
|
surface;
|
||||||
std::array<BoundingBox, SURFACE_UNIT_WIDTH * SURFACE_UNIT_HEIGHT> surface_bbs;
|
std::array<BoundingBox, SURFACE_UNIT_WIDTH * SURFACE_UNIT_HEIGHT> surface_bbs;
|
||||||
|
std::array<SurfaceTriangle, SURFACE_UNIT_WIDTH * SURFACE_UNIT_HEIGHT * 2>
|
||||||
|
surface_triangles;
|
||||||
std::array<Walker, 4> walkers;
|
std::array<Walker, 4> walkers;
|
||||||
|
|
||||||
Camera3D camera;
|
Camera3D camera;
|
||||||
|
/*
|
||||||
|
* 0 - resetting surface
|
||||||
|
*/
|
||||||
std::bitset<64> flags;
|
std::bitset<64> flags;
|
||||||
Model TEMP_cube_model;
|
Model TEMP_cube_model;
|
||||||
Texture2D TEMP_cube_texture;
|
Texture2D TEMP_cube_texture;
|
||||||
Matrix TEMP_matrix;
|
Matrix TEMP_matrix;
|
||||||
|
RenderTexture2D bgRenderTexture;
|
||||||
|
RenderTexture2D fgRenderTexture;
|
||||||
Vector3 camera_pos;
|
Vector3 camera_pos;
|
||||||
Vector3 camera_target;
|
Vector3 camera_target;
|
||||||
Vector3 mouse_hit;
|
Vector3 mouse_hit;
|
||||||
|
@ -73,9 +84,12 @@ class TRunnerScreen : public Screen {
|
||||||
const int left_text_width;
|
const int left_text_width;
|
||||||
const int right_text_width;
|
const int right_text_width;
|
||||||
const int forward_text_width;
|
const int forward_text_width;
|
||||||
|
const int reset_surface_text_width;
|
||||||
|
float surface_reset_anim_timer;
|
||||||
|
|
||||||
void camera_to_targets(float dt);
|
void camera_to_targets(float dt);
|
||||||
void generate_surface();
|
void generate_surface();
|
||||||
|
void generate_surface_with_triangles();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
60
src/surface_triangle.cc
Normal file
60
src/surface_triangle.cc
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
#include "surface_triangle.h"
|
||||||
|
|
||||||
|
// third party includes
|
||||||
|
#include <raylib.h>
|
||||||
|
#include <raymath.h>
|
||||||
|
|
||||||
|
// local includes
|
||||||
|
#include "3d_helpers.h"
|
||||||
|
#include "ems.h"
|
||||||
|
|
||||||
|
SurfaceTriangle::SurfaceTriangle()
|
||||||
|
: triangle_coords{Vector3{0.5F, 0.0F, -0.5F}, Vector3{-0.5F, 0.0F, -0.5F},
|
||||||
|
Vector3{-0.5F, 0.0F, 0.5F}},
|
||||||
|
triangle_pos{0.0F, 0.0F, 0.0F},
|
||||||
|
rotate_axis{0.0F, 1.0F, 0.0F},
|
||||||
|
pos_move_dir{0.0F, 1.0F, 0.0F},
|
||||||
|
rotation(0.0F),
|
||||||
|
move_amount(0.0F) {}
|
||||||
|
|
||||||
|
SurfaceTriangle::SurfaceTriangle(Vector3 a, Vector3 b, Vector3 c, Vector3 pos)
|
||||||
|
: triangle_coords{a, b, c},
|
||||||
|
triangle_pos{pos},
|
||||||
|
rotate_axis{call_js_get_random() * 2.0F - 1.0F,
|
||||||
|
call_js_get_random() * 2.0F - 1.0F,
|
||||||
|
call_js_get_random() * 2.0F - 1.0F},
|
||||||
|
pos_move_dir{call_js_get_random() * 2.0F - 1.0F,
|
||||||
|
call_js_get_random() * 2.0F - 1.0F,
|
||||||
|
call_js_get_random() * 2.0F - 1.0F},
|
||||||
|
rotation(0.0F),
|
||||||
|
move_amount(0.0F) {
|
||||||
|
if (FloatEquals(rotate_axis.x, 0.0F) && FloatEquals(rotate_axis.x, 0.0F) &&
|
||||||
|
FloatEquals(rotate_axis.x, 0.0F)) {
|
||||||
|
rotate_axis.x = 1.0F;
|
||||||
|
}
|
||||||
|
if (FloatEquals(pos_move_dir.x, 0.0F) && FloatEquals(pos_move_dir.x, 0.0F) &&
|
||||||
|
FloatEquals(pos_move_dir.x, 0.0F)) {
|
||||||
|
pos_move_dir.x = 1.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
rotate_axis = Vector3Normalize(rotate_axis);
|
||||||
|
pos_move_dir = Vector3Normalize(pos_move_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SurfaceTriangle::update(float dt) {
|
||||||
|
rotation += dt * SURFACE_TRIANGLE_ROTATION_RATE;
|
||||||
|
move_amount += dt * SURFACE_TRIANGLE_MOVE_RATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SurfaceTriangle::draw(Color color) {
|
||||||
|
const auto mat =
|
||||||
|
MatrixRotate(rotate_axis, rotation) *
|
||||||
|
MatrixTranslate(triangle_pos.x + pos_move_dir.x * move_amount,
|
||||||
|
triangle_pos.y + pos_move_dir.y * move_amount,
|
||||||
|
triangle_pos.z + pos_move_dir.z * move_amount);
|
||||||
|
Vector3 a = mat * triangle_coords[0];
|
||||||
|
Vector3 b = mat * triangle_coords[1];
|
||||||
|
Vector3 c = mat * triangle_coords[2];
|
||||||
|
|
||||||
|
DrawTriangle3D(a, b, c, color);
|
||||||
|
}
|
72
src/surface_triangle.h
Normal file
72
src/surface_triangle.h
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
#ifndef JUMPARTIFACT_DOT_COM_DEMO_0_SURFACE_TRIANGLE_H_
|
||||||
|
#define JUMPARTIFACT_DOT_COM_DEMO_0_SURFACE_TRIANGLE_H_
|
||||||
|
|
||||||
|
// standard library includes
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
// third party includes
|
||||||
|
#include <raylib.h>
|
||||||
|
|
||||||
|
// local includes
|
||||||
|
#include "common_constants.h"
|
||||||
|
|
||||||
|
constexpr float SURFACE_TRIANGLE_ROTATION_RATE = 0.4F;
|
||||||
|
constexpr float SURFACE_TRIANGLE_MOVE_RATE = 1.0F;
|
||||||
|
|
||||||
|
struct SurfaceTriangle {
|
||||||
|
SurfaceTriangle();
|
||||||
|
SurfaceTriangle(Vector3 a, Vector3 b, Vector3 c, Vector3 pos);
|
||||||
|
|
||||||
|
std::array<Vector3, 3> triangle_coords;
|
||||||
|
Vector3 triangle_pos;
|
||||||
|
Vector3 rotate_axis;
|
||||||
|
Vector3 pos_move_dir;
|
||||||
|
float rotation;
|
||||||
|
float move_amount;
|
||||||
|
|
||||||
|
void update(float dt);
|
||||||
|
void draw(Color color);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename SurfaceUnitOptT, std::size_t ASize>
|
||||||
|
extern std::array<SurfaceTriangle, ASize * 2> surface_to_triangles(
|
||||||
|
const std::array<SurfaceUnitOptT, ASize> &surface,
|
||||||
|
const std::size_t width) {
|
||||||
|
std::array<SurfaceTriangle, ASize * 2> triangles;
|
||||||
|
|
||||||
|
for (std::size_t idx = 0; idx < ASize; ++idx) {
|
||||||
|
std::size_t x = idx % width;
|
||||||
|
std::size_t y = idx / width;
|
||||||
|
|
||||||
|
float posx = ((float)x) - SURFACE_X_OFFSET;
|
||||||
|
float posz = ((float)y) - SURFACE_Y_OFFSET;
|
||||||
|
|
||||||
|
std::size_t toffset = x * 2 + y * width * 2;
|
||||||
|
|
||||||
|
if (!surface[idx].has_value()) {
|
||||||
|
triangles.at(toffset) = SurfaceTriangle();
|
||||||
|
triangles.at(toffset + 1) = SurfaceTriangle();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &surface_unit = surface[idx].value();
|
||||||
|
triangles.at(toffset) = SurfaceTriangle(
|
||||||
|
Vector3{0.5F, surface_unit.ne, -0.5F},
|
||||||
|
Vector3{-0.5F, surface_unit.nw, -0.5F},
|
||||||
|
Vector3{-0.5F, surface_unit.sw, 0.5F},
|
||||||
|
Vector3{posx,
|
||||||
|
(surface_unit.ne + surface_unit.nw + surface_unit.sw) / 3.0F,
|
||||||
|
posz});
|
||||||
|
triangles.at(toffset + 1) = SurfaceTriangle(
|
||||||
|
Vector3{0.5F, surface_unit.ne, -0.5F},
|
||||||
|
Vector3{-0.5F, surface_unit.sw, 0.5F},
|
||||||
|
Vector3{0.5F, surface_unit.se, 0.5F},
|
||||||
|
Vector3{posx,
|
||||||
|
(surface_unit.ne + surface_unit.sw + surface_unit.se) / 3.0F,
|
||||||
|
posz});
|
||||||
|
}
|
||||||
|
|
||||||
|
return triangles;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -15,7 +15,8 @@ SOURCES = \
|
||||||
../src/screen_trunner.cc \
|
../src/screen_trunner.cc \
|
||||||
../src/3d_helpers.cc \
|
../src/3d_helpers.cc \
|
||||||
../src/raymath.cc \
|
../src/raymath.cc \
|
||||||
../src/walker.cc
|
../src/walker.cc \
|
||||||
|
../src/surface_triangle.cc
|
||||||
|
|
||||||
HEADERS = \
|
HEADERS = \
|
||||||
../src/ems.h \
|
../src/ems.h \
|
||||||
|
@ -24,7 +25,8 @@ HEADERS = \
|
||||||
../src/screen_test.h \
|
../src/screen_test.h \
|
||||||
../src/screen_trunner.h \
|
../src/screen_trunner.h \
|
||||||
../src/3d_helpers.h \
|
../src/3d_helpers.h \
|
||||||
../src/walker.h
|
../src/walker.h \
|
||||||
|
../src/surface_triangle.h
|
||||||
|
|
||||||
OBJECTS = $(addprefix ${OBJDIR}/,$(subst ..,PREVDIR,$(subst .cc,.cc.o,${SOURCES})))
|
OBJECTS = $(addprefix ${OBJDIR}/,$(subst ..,PREVDIR,$(subst .cc,.cc.o,${SOURCES})))
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue