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/raymath.cc \
|
||||
src/ems.cc \
|
||||
src/walker.cc
|
||||
src/walker.cc \
|
||||
src/surface_triangle.cc
|
||||
|
||||
HEADERS = \
|
||||
src/game.h \
|
||||
|
@ -27,7 +28,8 @@ HEADERS = \
|
|||
src/screen_trunner.h \
|
||||
src/3d_helpers.h \
|
||||
src/ems.h \
|
||||
src/walker.h
|
||||
src/walker.h \
|
||||
src/surface_triangle.h
|
||||
|
||||
OBJECTS = $(addprefix ${OBJDIR}/,$(subst .cc,.cc.o,${SOURCES}))
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ TRunnerScreen::TRunnerScreen(std::weak_ptr<ScreenStack> stack)
|
|||
: Screen(stack),
|
||||
surface(),
|
||||
surface_bbs(),
|
||||
surface_triangles(),
|
||||
// NOLINTBEGIN(bugprone-integer-division)
|
||||
walkers{Walker{(float)(SURFACE_UNIT_WIDTH / 4) - SURFACE_X_OFFSET,
|
||||
(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_texture(LoadTexture("res/test_cube_texture.png")),
|
||||
TEMP_matrix(get_identity_matrix()),
|
||||
bgRenderTexture(),
|
||||
fgRenderTexture(),
|
||||
camera_pos{0.0F, 4.0F, 4.0F},
|
||||
camera_target{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),
|
||||
left_text_width(MeasureText("Left", 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
|
||||
std::cout << "idx_hit initialized to " << idx_hit << std::endl;
|
||||
#endif
|
||||
|
@ -63,17 +68,32 @@ TRunnerScreen::TRunnerScreen(std::weak_ptr<ScreenStack> stack)
|
|||
// Initialize surface.
|
||||
generate_surface();
|
||||
|
||||
// Set up render textures
|
||||
bgRenderTexture = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
|
||||
fgRenderTexture = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
|
||||
|
||||
#ifndef NDEBUG
|
||||
std::cout << "Screen finished init.\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
TRunnerScreen::~TRunnerScreen() {
|
||||
UnloadRenderTexture(fgRenderTexture);
|
||||
UnloadRenderTexture(bgRenderTexture);
|
||||
|
||||
UnloadTexture(TEMP_cube_texture);
|
||||
UnloadModel(TEMP_cube_model);
|
||||
}
|
||||
|
||||
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()) {
|
||||
auto walker_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;
|
||||
}
|
||||
|
||||
if (controlled_walker_idx.has_value() && IsMouseButtonDown(0)) {
|
||||
// Check if clicked on button.
|
||||
if (!walkers[controlled_walker_idx.value()].player_is_turning_left() &&
|
||||
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 (!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();
|
||||
if (!flags.test(0)) {
|
||||
if (controlled_walker_idx.has_value() && IsMouseButtonDown(0)) {
|
||||
// Check if clicked on button.
|
||||
if (!walkers[controlled_walker_idx.value()].player_is_turning_left() &&
|
||||
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 (IsMouseButtonReleased(0)) {
|
||||
if (controlled_walker_idx.has_value()) {
|
||||
walkers[controlled_walker_idx.value()].player_idle();
|
||||
goto post_check_click;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsMouseButtonPressed(0)) {
|
||||
float press_x = GetTouchX();
|
||||
float press_y = GetTouchY();
|
||||
Ray ray = GetMouseRay(Vector2{press_x, press_y}, camera);
|
||||
#ifndef NDEBUG
|
||||
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
|
||||
|
||||
// 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);
|
||||
} 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;
|
||||
}
|
||||
controlled_walker_idx = idx;
|
||||
walkers[controlled_walker_idx.value()].set_player_controlled(true);
|
||||
|
||||
idx_hit = SURFACE_UNIT_WIDTH * SURFACE_UNIT_HEIGHT;
|
||||
|
||||
}
|
||||
} else if (IsMouseButtonReleased(0)) {
|
||||
if (controlled_walker_idx.has_value()) {
|
||||
walkers[controlled_walker_idx.value()].player_idle();
|
||||
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;
|
||||
if (IsMouseButtonPressed(0)) {
|
||||
float press_x = GetTouchX();
|
||||
float press_y = GetTouchY();
|
||||
|
||||
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};
|
||||
// Check if clicked on reset surface.
|
||||
if (!flags.test(0) &&
|
||||
press_x >= GetScreenWidth() - reset_surface_text_width &&
|
||||
press_y <= BUTTON_FONT_SIZE) {
|
||||
generate_surface_with_triangles();
|
||||
goto post_check_click;
|
||||
}
|
||||
|
||||
const auto on_collide_fn = [this, idx, xf, zf,
|
||||
¤t](const auto &collision) {
|
||||
this->idx_hit = idx;
|
||||
Ray ray = GetMouseRay(Vector2{press_x, press_y}, camera);
|
||||
#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
|
||||
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;
|
||||
}
|
||||
};
|
||||
// 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);
|
||||
|
||||
idx_hit = SURFACE_UNIT_WIDTH * SURFACE_UNIT_HEIGHT;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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:
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool TRunnerScreen::draw() {
|
||||
BeginDrawing();
|
||||
BeginTextureMode(bgRenderTexture);
|
||||
ClearBackground(PixelToColor(Pixel::PIXEL_SKY));
|
||||
BeginMode3D(camera);
|
||||
|
||||
|
@ -237,12 +281,20 @@ bool TRunnerScreen::draw() {
|
|||
: Color{(unsigned char)(200 + ox * 2),
|
||||
(unsigned char)(150 + oy * 2), 20, 255};
|
||||
const auto ¤t = surface[idx].value();
|
||||
DrawTriangle3D(Vector3{xf - 0.5F, current.nw, zf - 0.5F},
|
||||
Vector3{xf - 0.5F, current.sw, zf + 0.5F},
|
||||
Vector3{xf + 0.5F, current.ne, zf - 0.5F}, color);
|
||||
DrawTriangle3D(Vector3{xf + 0.5F, current.se, zf + 0.5F},
|
||||
Vector3{xf + 0.5F, current.ne, zf - 0.5F},
|
||||
Vector3{xf - 0.5F, current.sw, zf + 0.5F}, color);
|
||||
float reset_y_offset = 0.0F;
|
||||
if (flags.test(0)) {
|
||||
reset_y_offset = (1.0F - std::sin(surface_reset_anim_timer /
|
||||
SURFACE_RESET_TIME * PI / 2.0F)) *
|
||||
-SURFACE_RESET_Y_OFFSET;
|
||||
}
|
||||
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) {
|
||||
|
@ -250,7 +302,7 @@ bool TRunnerScreen::draw() {
|
|||
}
|
||||
|
||||
// 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);
|
||||
|
||||
for (const auto &walker : walkers) {
|
||||
|
@ -262,29 +314,77 @@ bool TRunnerScreen::draw() {
|
|||
}
|
||||
|
||||
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()) {
|
||||
int total_width = 0;
|
||||
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,
|
||||
BLACK);
|
||||
|
||||
total_width += left_text_width;
|
||||
DrawRectangle(total_width, GetScreenHeight() - 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,
|
||||
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});
|
||||
Color{255, 255, 255, 180});
|
||||
DrawText("Forward", total_width, GetScreenHeight() - BUTTON_FONT_SIZE * 2,
|
||||
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();
|
||||
|
||||
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
|
||||
#include "common_constants.h"
|
||||
#include "surface_triangle.h"
|
||||
#include "walker.h"
|
||||
|
||||
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 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 {
|
||||
public:
|
||||
struct SurfaceUnit {
|
||||
float nw, ne, sw, se;
|
||||
};
|
||||
|
||||
TRunnerScreen(std::weak_ptr<ScreenStack> stack);
|
||||
~TRunnerScreen() override;
|
||||
|
||||
|
@ -47,24 +56,26 @@ class TRunnerScreen : public Screen {
|
|||
PIXEL_WHITE
|
||||
};
|
||||
|
||||
struct SurfaceUnit {
|
||||
float nw, ne, sw, se;
|
||||
};
|
||||
|
||||
static Color PixelToColor(Pixel p);
|
||||
|
||||
std::array<std::optional<SurfaceUnit>,
|
||||
SURFACE_UNIT_WIDTH * SURFACE_UNIT_HEIGHT>
|
||||
surface;
|
||||
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;
|
||||
|
||||
Camera3D camera;
|
||||
/*
|
||||
* 0 - resetting surface
|
||||
*/
|
||||
std::bitset<64> flags;
|
||||
Model TEMP_cube_model;
|
||||
Texture2D TEMP_cube_texture;
|
||||
Matrix TEMP_matrix;
|
||||
RenderTexture2D bgRenderTexture;
|
||||
RenderTexture2D fgRenderTexture;
|
||||
Vector3 camera_pos;
|
||||
Vector3 camera_target;
|
||||
Vector3 mouse_hit;
|
||||
|
@ -73,9 +84,12 @@ class TRunnerScreen : public Screen {
|
|||
const int left_text_width;
|
||||
const int right_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 generate_surface();
|
||||
void generate_surface_with_triangles();
|
||||
};
|
||||
|
||||
#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/3d_helpers.cc \
|
||||
../src/raymath.cc \
|
||||
../src/walker.cc
|
||||
../src/walker.cc \
|
||||
../src/surface_triangle.cc
|
||||
|
||||
HEADERS = \
|
||||
../src/ems.h \
|
||||
|
@ -24,7 +25,8 @@ HEADERS = \
|
|||
../src/screen_test.h \
|
||||
../src/screen_trunner.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})))
|
||||
|
||||
|
|
Loading…
Reference in a new issue