src/raymath.cc \
src/ems.cc \
src/walker.cc \
- src/surface_triangle.cc
+ src/surface_triangle.cc \
+ src/screen_walker_hack.cc
HEADERS = \
src/game.h \
src/3d_helpers.h \
src/ems.h \
src/walker.h \
- src/surface_triangle.h
+ src/surface_triangle.h\
+ src/screen_walker_hack.h
OBJECTS = $(addprefix ${OBJDIR}/,$(subst .cc,.cc.o,${SOURCES}))
#include "screen.h"
// standard library includes
+#include <raylib.h>
+
#include <cassert>
#ifndef NDEBUG
#include <iostream>
return ptr;
}
+ScreenStack::~ScreenStack() {
+ UnloadRenderTexture(*render_texture);
+ render_texture.reset();
+}
+
void ScreenStack::update(float dt) {
handle_pending_actions();
+ bool resized = IsWindowResized();
+ if (resized) {
+ reset_render_texture();
+ }
+
auto idx = stack.size();
if (idx == 0) {
#ifndef NDEBUG
update(dt);
return;
}
- while (idx > 0 && stack.at(--idx)->update(dt)) {
+ while (idx > 0 && stack.at(--idx)->update(dt, resized)) {
}
}
void ScreenStack::draw() {
for (decltype(stack.size()) idx = 0;
- idx < stack.size() && stack.at(idx)->draw(); ++idx) {
+ idx < stack.size() && stack.at(idx)->draw(render_texture.get()); ++idx) {
}
+
+ BeginDrawing();
+ DrawTextureRec(
+ render_texture->texture,
+ Rectangle{0, 0, (float)GetScreenWidth(), (float)-GetScreenHeight()},
+ {0, 0}, WHITE);
+ EndDrawing();
}
void ScreenStack::push_screen(Screen::Ptr &&screen) {
actions.push_back(PendingAction(Action::CLEAR_SCREENS));
}
-ScreenStack::ScreenStack() : self_weak(), stack(), actions() {}
+void ScreenStack::reset_render_texture() {
+ UnloadRenderTexture(*render_texture);
+
+ *render_texture = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
+}
+
+ScreenStack::ScreenStack()
+ : render_texture(new RenderTexture), self_weak(), stack(), actions() {
+ *render_texture = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
+}
void ScreenStack::handle_pending_actions() {
while (!actions.empty()) {
#ifndef JUMPARTIFACT_DOT_COM_DEMO_0_SCREEN_H_
#define JUMPARTIFACT_DOT_COM_DEMO_0_SCREEN_H_
+#include <raylib.h>
+
#include <deque>
#include <functional>
#include <memory>
#include <variant>
#include <vector>
-// Forward declaration.
+// Forward declarations.
class ScreenStack;
+struct RenderTexture;
class Screen {
public:
template <typename SubScreen>
static Ptr new_screen(std::weak_ptr<ScreenStack> stack);
+ template <typename SubScreen, typename... Args>
+ static Ptr new_screen_args(std::weak_ptr<ScreenStack> stack, Args... args);
+
virtual ~Screen() {}
// No copy.
Screen& operator=(Screen&&) = default;
/// Return true if next screen should be updated.
- virtual bool update(float dt) = 0;
+ virtual bool update(float dt, bool screen_resized) = 0;
/// Return true if next screen should be drawn.
- virtual bool draw() = 0;
+ virtual bool draw(RenderTexture* renderTexture) = 0;
protected:
Screen(std::weak_ptr<ScreenStack> stack);
public:
static Ptr new_instance();
+ ~ScreenStack();
+
// No copy.
ScreenStack(const ScreenStack&) = delete;
ScreenStack& operator=(const ScreenStack&) = delete;
template <typename SubScreen>
void push_constructing_screen();
+ template <typename SubScreen, typename... Args>
+ void push_constructing_screen_args(Args... args);
+
void pop_screen();
void clear_screens();
+ void reset_render_texture();
+
private:
ScreenStack();
void handle_pending_actions();
+ std::unique_ptr<RenderTexture> render_texture;
Weak self_weak;
std::vector<Screen::Ptr> stack;
std::deque<PendingAction> actions;
return std::unique_ptr<SubScreen>(new SubScreen{stack});
}
+template <typename SubScreen, typename... Args>
+Screen::Ptr Screen::new_screen_args(std::weak_ptr<ScreenStack> stack,
+ Args... args) {
+ return std::unique_ptr<SubScreen>(new SubScreen{stack, args...});
+}
+
template <typename SubScreen>
void ScreenStack::push_screen() {
actions.emplace_back(Screen::new_screen<SubScreen>(self_weak));
});
}
+template <typename SubScreen, typename... Args>
+void ScreenStack::push_constructing_screen_args(Args... args) {
+ actions.emplace_back([args...](ScreenStack::Weak ss) -> Screen::Ptr {
+ return Screen::new_screen_args<SubScreen>(ss, args...);
+ });
+}
+
#endif
: Screen(weak_ptr), TEMP_cached_dt(0.0F) {}
TestScreen::~TestScreen() {}
-bool TestScreen::update(float dt) {
+bool TestScreen::update(float dt, bool) {
TEMP_cached_dt = dt;
return false;
}
-bool TestScreen::draw() {
+bool TestScreen::draw(RenderTexture *render_texture) {
std::string dt_string =
std::string("Delta-time: ") + std::to_string(TEMP_cached_dt);
- BeginDrawing();
+ BeginTextureMode(*render_texture);
ClearBackground(BLACK);
DrawText("Testing...", 100, 100, 30, RAYWHITE);
DrawText(dt_string.c_str(), 100, 140, 30, RAYWHITE);
- EndDrawing();
+ EndTextureMode();
return false;
}
TestScreen(ScreenStack::Weak weak_ptr);
~TestScreen() override;
- bool update(float dt) override;
- bool draw() override;
+ bool update(float dt, bool is_resized) override;
+ bool draw(RenderTexture *render_texture) override;
private:
float TEMP_cached_dt;
// local includes
#include "3d_helpers.h"
#include "ems.h"
+#include "screen_walker_hack.h"
TRunnerScreen::TRunnerScreen(std::weak_ptr<ScreenStack> stack)
: Screen(stack),
right_text_width(MeasureText("Right", 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) {
+ surface_reset_anim_timer(0.0F),
+ walker_hack_success(false) {
#ifndef NDEBUG
std::cout << "idx_hit initialized to " << idx_hit << std::endl;
#endif
UnloadModel(TEMP_cube_model);
}
-bool TRunnerScreen::update(float dt) {
- if (IsWindowResized()) {
+bool TRunnerScreen::update(float dt, bool is_resized) {
+ if (is_resized) {
UnloadRenderTexture(fgRenderTexture);
UnloadRenderTexture(bgRenderTexture);
fgRenderTexture = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
}
+ if (flags.test(1)) {
+ if (walker_hack_success && controlled_walker_idx.has_value()) {
+ walkers[controlled_walker_idx.value()].set_player_controlled(true);
+ } else {
+ controlled_walker_idx.reset();
+ }
+ flags.reset(1);
+ }
+
if (controlled_walker_idx.has_value()) {
auto walker_body_pos =
walkers[controlled_walker_idx.value()].get_body_pos();
walkers[controlled_walker_idx.value()].set_player_controlled(false);
}
controlled_walker_idx = idx;
- walkers[controlled_walker_idx.value()].set_player_controlled(true);
+ auto s_stack = stack.lock();
+ if (s_stack) {
+ s_stack->push_constructing_screen_args<WalkerHackScreen>(
+ &walker_hack_success);
+ flags.set(1);
+ }
+ // walkers[controlled_walker_idx.value()].set_player_controlled(true);
idx_hit = SURFACE_UNIT_WIDTH * SURFACE_UNIT_HEIGHT;
return false;
}
-bool TRunnerScreen::draw() {
+bool TRunnerScreen::draw(RenderTexture *render_texture) {
BeginTextureMode(bgRenderTexture);
ClearBackground(PixelToColor(Pixel::PIXEL_SKY));
BeginMode3D(camera);
EndMode3D();
if (!flags.test(0)) {
- if (controlled_walker_idx.has_value()) {
+ if (!flags.test(1) && 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, 180});
EndTextureMode();
}
- BeginDrawing();
+ BeginTextureMode(*render_texture);
DrawTextureRec(
bgRenderTexture.texture,
Rectangle{0, 0, (float)GetScreenWidth(), (float)-GetScreenHeight()},
Rectangle{0, 0, (float)GetScreenWidth(), (float)-GetScreenHeight()},
{0, 0}, WHITE);
}
- EndDrawing();
+ EndTextureMode();
- return false;
+ return true;
}
Color TRunnerScreen::PixelToColor(Pixel p) {
TRunnerScreen(std::weak_ptr<ScreenStack> stack);
~TRunnerScreen() override;
- bool update(float dt) override;
- bool draw() override;
+ bool update(float dt, bool is_resized) override;
+ bool draw(RenderTexture *render_texture) override;
private:
enum Pixel : unsigned char {
Camera3D camera;
/*
* 0 - resetting surface
+ * 1 - walker hack attempted
*/
std::bitset<64> flags;
Model TEMP_cube_model;
const int forward_text_width;
const int reset_surface_text_width;
float surface_reset_anim_timer;
+ bool walker_hack_success;
void camera_to_targets(float dt);
void generate_surface();
--- /dev/null
+#include "screen_walker_hack.h"
+
+// standard library includes
+#include <cassert>
+#ifndef NDEBUG
+#include <iostream>
+#endif
+
+// third party includes
+#include <raylib.h>
+
+// local includes
+#include "ems.h"
+
+static const char *WALKER_HACK_SCREEN_INSTRUCTIONS =
+ "Press The Correct Button!";
+
+WalkerHackScreen::WalkerHackScreen(ScreenStack::Weak ss_weak,
+ bool *walker_hack_success)
+ : Screen(ss_weak),
+ walker_hack_success(walker_hack_success),
+ timer(WALKER_HACK_SCREEN_DURATION),
+ font_size(10),
+ instructions_size(1),
+ instructions_font_size(font_size),
+ type_f_size(1),
+ type_j_size(1),
+ type_a_size(1),
+ type_l_size(1),
+ button_type(BUTTON_TYPE_F) {
+ button_type =
+ (ButtonType)((int)(call_js_get_random() * (float)BUTTON_TYPE_SIZE));
+ *walker_hack_success = false;
+ set_sizes();
+}
+
+WalkerHackScreen::~WalkerHackScreen() {}
+
+bool WalkerHackScreen::update(float dt, bool resized) {
+ if (resized) {
+ set_sizes();
+ }
+
+ timer -= dt;
+ if (timer < 0.0F) {
+#ifndef NDEBUG
+ std::clog << "WalkerHackScreen: timer ended.\n";
+#endif
+ timer = WALKER_HACK_SCREEN_DURATION;
+ auto s_stack = stack.lock();
+ if (s_stack) {
+ s_stack->pop_screen();
+ }
+ }
+
+ if (IsMouseButtonPressed(0)) {
+ switch (button_type) {
+ case BUTTON_TYPE_F:
+ if (GetTouchX() >=
+ GetScreenWidth() / 2 - type_f_size - BUTTON_DRAW_OFFSET &&
+ GetTouchX() <= GetScreenWidth() / 2 - BUTTON_DRAW_OFFSET &&
+ GetTouchY() <= font_size) {
+ *walker_hack_success = true;
+ button_type = BUTTON_TYPE_SIZE;
+ }
+ break;
+ case BUTTON_TYPE_J:
+ if (GetTouchX() >= GetScreenWidth() / 2 + BUTTON_DRAW_OFFSET &&
+ GetTouchX() <=
+ GetScreenWidth() / 2 + BUTTON_DRAW_OFFSET + type_j_size &&
+ GetTouchY() <= font_size) {
+ *walker_hack_success = true;
+ button_type = BUTTON_TYPE_SIZE;
+ }
+ break;
+ case BUTTON_TYPE_A:
+ if (GetTouchX() >=
+ GetScreenWidth() / 2 - type_f_size - BUTTON_DRAW_OFFSET &&
+ GetTouchX() <= GetScreenWidth() / 2 - BUTTON_DRAW_OFFSET &&
+ GetTouchY() >= font_size + BUTTON_DRAW_OFFSET &&
+ GetTouchY() <= font_size * 2 + BUTTON_DRAW_OFFSET) {
+ *walker_hack_success = true;
+ button_type = BUTTON_TYPE_SIZE;
+ }
+ break;
+ case BUTTON_TYPE_L:
+ if (GetTouchX() >= GetScreenWidth() / 2 + BUTTON_DRAW_OFFSET &&
+ GetTouchX() <=
+ GetScreenWidth() / 2 + BUTTON_DRAW_OFFSET + type_l_size &&
+ GetTouchY() >= font_size + BUTTON_DRAW_OFFSET &&
+ GetTouchY() <= font_size * 2 + BUTTON_DRAW_OFFSET) {
+ *walker_hack_success = true;
+ button_type = BUTTON_TYPE_SIZE;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ switch (GetKeyPressed()) {
+ case KEY_F:
+ if (button_type == BUTTON_TYPE_F) {
+ *walker_hack_success = true;
+ button_type = BUTTON_TYPE_SIZE;
+ }
+ break;
+ case KEY_J:
+ if (button_type == BUTTON_TYPE_J) {
+ *walker_hack_success = true;
+ button_type = BUTTON_TYPE_SIZE;
+ }
+ break;
+ case KEY_A:
+ if (button_type == BUTTON_TYPE_A) {
+ *walker_hack_success = true;
+ button_type = BUTTON_TYPE_SIZE;
+ }
+ break;
+ case KEY_L:
+ if (button_type == BUTTON_TYPE_L) {
+ *walker_hack_success = true;
+ button_type = BUTTON_TYPE_SIZE;
+ }
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+bool WalkerHackScreen::draw(RenderTexture *render_texture) {
+ BeginTextureMode(*render_texture);
+
+ DrawRectangle(GetScreenWidth() / 2 - instructions_size / 2,
+ (GetScreenHeight() / 4) * 3, instructions_size,
+ instructions_font_size, BLACK);
+ DrawText(WALKER_HACK_SCREEN_INSTRUCTIONS,
+ GetScreenWidth() / 2 - instructions_size / 2,
+ (GetScreenHeight() / 4) * 3, instructions_font_size, WHITE);
+
+ float ratio =
+ (WALKER_HACK_SCREEN_DURATION - timer) / WALKER_HACK_SCREEN_DURATION;
+ DrawRectangle(GetScreenWidth() * ratio,
+ (float)GetScreenHeight() * BUTTON_FONT_SIZE_RATIO * 2.0F +
+ BUTTON_DRAW_OFFSET * 3.0F,
+ GetScreenWidth() * (1.0F - ratio), 30, GREEN);
+
+ DrawRectangle(GetScreenWidth() / 2 - type_f_size - BUTTON_DRAW_OFFSET, 0,
+ type_f_size, font_size,
+ button_type == BUTTON_TYPE_F ? GREEN : BLACK);
+ DrawText("F", GetScreenWidth() / 2 - type_f_size - BUTTON_DRAW_OFFSET, 0,
+ font_size, WHITE);
+
+ DrawRectangle(GetScreenWidth() / 2 + BUTTON_DRAW_OFFSET, 0, type_j_size,
+ font_size, button_type == BUTTON_TYPE_J ? GREEN : BLACK);
+ DrawText("J", GetScreenWidth() / 2 + BUTTON_DRAW_OFFSET, 0, font_size, WHITE);
+
+ DrawRectangle(GetScreenWidth() / 2 - type_a_size - BUTTON_DRAW_OFFSET,
+ font_size + BUTTON_DRAW_OFFSET, type_a_size, font_size,
+ button_type == BUTTON_TYPE_A ? GREEN : BLACK);
+ DrawText("A", GetScreenWidth() / 2 - type_a_size - BUTTON_DRAW_OFFSET,
+ font_size + BUTTON_DRAW_OFFSET, font_size, WHITE);
+
+ DrawRectangle(GetScreenWidth() / 2 + BUTTON_DRAW_OFFSET,
+ font_size + BUTTON_DRAW_OFFSET, type_l_size, font_size,
+ button_type == BUTTON_TYPE_L ? GREEN : BLACK);
+ DrawText("L", GetScreenWidth() / 2 + BUTTON_DRAW_OFFSET,
+ font_size + BUTTON_DRAW_OFFSET, font_size, WHITE);
+
+ EndTextureMode();
+
+ return true;
+}
+
+void WalkerHackScreen::set_sizes() {
+ font_size = GetScreenHeight() * BUTTON_FONT_SIZE_RATIO;
+ instructions_font_size = font_size;
+ instructions_size =
+ MeasureText(WALKER_HACK_SCREEN_INSTRUCTIONS, instructions_font_size);
+ while (instructions_size > GetScreenWidth() && instructions_font_size > 1) {
+ --instructions_font_size;
+ instructions_size =
+ MeasureText(WALKER_HACK_SCREEN_INSTRUCTIONS, instructions_font_size);
+ }
+
+ type_f_size = MeasureText("F", font_size);
+ type_j_size = MeasureText("J", font_size);
+ type_a_size = MeasureText("A", font_size);
+ type_l_size = MeasureText("L", font_size);
+}
--- /dev/null
+#ifndef JUMPARTIFACT_DOT_COM_DEMO_0_WALKER_HACK_SCREEN_H_
+#define JUMPARTIFACT_DOT_COM_DEMO_0_WALKER_HACK_SCREEN_H_
+
+// local includes
+#include "screen.h"
+
+constexpr float WALKER_HACK_SCREEN_DURATION = 2.0F;
+constexpr float BUTTON_FONT_SIZE_RATIO = 0.28F;
+constexpr int BUTTON_DRAW_OFFSET = 5;
+
+class WalkerHackScreen : public Screen {
+ public:
+ WalkerHackScreen(ScreenStack::Weak ss_weak, bool *walkerHackSuccess);
+ ~WalkerHackScreen() override;
+
+ // Disallow copy.
+ WalkerHackScreen(const WalkerHackScreen &) = delete;
+ WalkerHackScreen &operator=(const WalkerHackScreen &) = delete;
+
+ // Allow move.
+ WalkerHackScreen(WalkerHackScreen &&) = default;
+ WalkerHackScreen &operator=(WalkerHackScreen &&) = default;
+
+ bool update(float dt, bool is_resized) override;
+ bool draw(RenderTexture *render_texture) override;
+
+ private:
+ enum ButtonType {
+ BUTTON_TYPE_F = 0,
+ BUTTON_TYPE_J,
+ BUTTON_TYPE_A,
+ BUTTON_TYPE_L,
+ BUTTON_TYPE_SIZE
+ };
+
+ bool *walker_hack_success;
+ float timer;
+ int font_size;
+ int instructions_size;
+ int instructions_font_size;
+ int type_f_size;
+ int type_j_size;
+ int type_a_size;
+ int type_l_size;
+ ButtonType button_type;
+
+ void set_sizes();
+};
+
+#endif
../src/3d_helpers.cc \
../src/raymath.cc \
../src/walker.cc \
- ../src/surface_triangle.cc
+ ../src/surface_triangle.cc \
+ ../src/screen_walker_hack.cc
HEADERS = \
../src/ems.h \
../src/screen_trunner.h \
../src/3d_helpers.h \
../src/walker.h \
- ../src/surface_triangle.h
+ ../src/surface_triangle.h \
+ ../src/screen_walker_hack.h
OBJECTS = $(addprefix ${OBJDIR}/,$(subst ..,PREVDIR,$(subst .cc,.cc.o,${SOURCES})))