diff --git a/Makefile b/Makefile index e1ececd..ccafaa3 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,8 @@ SOURCES = \ src/ems.cc \ src/walker.cc \ src/surface_triangle.cc \ - src/screen_walker_hack.cc + src/screen_walker_hack.cc \ + src/electricity_effect.cc HEADERS = \ src/game.h \ @@ -30,8 +31,9 @@ HEADERS = \ src/3d_helpers.h \ src/ems.h \ src/walker.h \ - src/surface_triangle.h\ - src/screen_walker_hack.h + src/surface_triangle.h \ + src/screen_walker_hack.h \ + src/electricity_effect.h OBJECTS = $(addprefix ${OBJDIR}/,$(subst .cc,.cc.o,${SOURCES})) diff --git a/src/electricity_effect.cc b/src/electricity_effect.cc new file mode 100644 index 0000000..e449c93 --- /dev/null +++ b/src/electricity_effect.cc @@ -0,0 +1,86 @@ +#include "electricity_effect.h" + +// third party includes +#include +#include + +// local includes +#include "3d_helpers.h" +#include "ems.h" + +ElectricityEffect::ElectricityEffect(Vector3 center, float radius, + int line_count, float lifetime) + : cylinders(), + center(center), + cylinder_radius(CYLINDER_MAX_RADIUS), + lifetime(lifetime), + timer(0.0F) { + cylinders.reserve(line_count); + + // Generate cylinders. + int sub_count = 0; + Vector3 dir, pos; + for (; line_count > 0; --line_count) { + if (sub_count == 0) { + dir.x = call_js_get_random() * 2.0F - 1.0F; + dir.y = call_js_get_random() * 2.0F - 1.0F; + dir.z = call_js_get_random() * 2.0F - 1.0F; + + dir = Vector3Normalize(dir); + + pos = center + dir * (radius * 0.7F); + + dir.x = call_js_get_random() * 2.0F - 1.0F; + dir.y = call_js_get_random() * 2.0F - 1.0F; + dir.z = call_js_get_random() * 2.0F - 1.0F; + + dir = Vector3Normalize(dir); + + auto coll = GetRayCollisionSphere( + Ray{.position = center, .direction = dir}, center, radius); + + cylinders.push_back(Cylinder{.start = pos, .end = coll.point}); + + pos = coll.point; + } else { + dir = Vector3Normalize(center - pos); + + pos = pos + dir * (radius * CYLINDER_EDGE_OFFSET); + + for (unsigned int idx = 0; idx < CYLINDER_SPLIT_COUNT; ++idx) { + dir.x = call_js_get_random() * 2.0F - 1.0F; + dir.y = call_js_get_random() * 2.0F - 1.0F; + dir.z = call_js_get_random() * 2.0F - 1.0F; + + dir = Vector3Normalize(dir); + + auto coll = GetRayCollisionSphere( + Ray{.position = pos, .direction = dir}, center, radius); + + cylinders.push_back(Cylinder{.start = pos, .end = coll.point}); + + if (idx == CYLINDER_SPLIT_COUNT - 1) { + pos = coll.point; + } + } + } + if (++sub_count >= CYLINDER_SUB_COUNT_MAX) { + sub_count = 0; + } + } +} + +bool ElectricityEffect::update(float dt) { + timer += dt; + + return timer >= lifetime; +} + +void ElectricityEffect::draw(Color color) { + float ratio = timer < lifetime ? (1.0F - timer / lifetime) : 0.0F; + + for (const auto &cylinder : cylinders) { + DrawCylinderEx(cylinder.start, cylinder.end, CYLINDER_MAX_RADIUS * ratio, + CYLINDER_MAX_RADIUS * ratio, 8, color); + } +} diff --git a/src/electricity_effect.h b/src/electricity_effect.h new file mode 100644 index 0000000..7842fd5 --- /dev/null +++ b/src/electricity_effect.h @@ -0,0 +1,38 @@ +#ifndef JUMPARTIFACT_DOT_COM_DEMO_0_ELECTRICITY_EFFECT_H_ +#define JUMPARTIFACT_DOT_COM_DEMO_0_ELECTRICITY_EFFECT_H_ + +// standard library includes +#include + +// third party includes +#include + +constexpr int CYLINDER_SUB_COUNT_MAX = 3; +constexpr int CYLINDER_SPLIT_COUNT = 3; +constexpr int CYLINDER_SIDES = 8; +constexpr float CYLINDER_MAX_RADIUS = 0.03F; +constexpr float CYLINDER_EDGE_OFFSET = 0.01F; + +class ElectricityEffect { + public: + ElectricityEffect(Vector3 center, float radius, int line_count, + float lifetime); + + /// Returns true if lifetime ended. + bool update(float dt); + /// Assumes draw mode is active. + void draw(Color color); + + private: + struct Cylinder { + Vector3 start, end; + }; + + std::vector cylinders; + Vector3 center; + float cylinder_radius; + float lifetime; + float timer; +}; + +#endif diff --git a/src/screen_trunner.cc b/src/screen_trunner.cc index 91070a4..967e7d8 100644 --- a/src/screen_trunner.cc +++ b/src/screen_trunner.cc @@ -49,6 +49,7 @@ TRunnerScreen::TRunnerScreen(std::weak_ptr stack) camera_target{0.0F, 0.0F, 0.0F}, mouse_hit{0.0F, 0.0F, 0.0F}, surface_triangles(), + electricityEffects(), idx_hit(SURFACE_UNIT_WIDTH / 2 + (SURFACE_UNIT_HEIGHT / 2) * SURFACE_UNIT_WIDTH), controlled_walker_idx(std::nullopt), @@ -99,6 +100,10 @@ bool TRunnerScreen::update(float dt, bool is_resized) { if (flags.test(1)) { if (walker_hack_success && controlled_walker_idx.has_value()) { walkers[controlled_walker_idx.value()].set_player_controlled(true); + electricityEffects.push_back(ElectricityEffect( + walkers[controlled_walker_idx.value()].get_body_pos(), 1.7F, 15, + 1.0F)); + } else { controlled_walker_idx.reset(); } @@ -278,6 +283,21 @@ post_check_click: SURFACE_UNIT_HEIGHT); } + std::vector to_remove; + for (decltype(electricityEffects.size()) idx = 0; + idx < electricityEffects.size(); ++idx) { + if (electricityEffects[idx].update(dt)) { + to_remove.push_back(idx); + } + } + + for (auto iter = to_remove.rbegin(); iter != to_remove.rend(); ++iter) { + if (*iter != electricityEffects.size() - 1) { + electricityEffects[*iter] = *electricityEffects.rbegin(); + } + electricityEffects.pop_back(); + } + return false; } @@ -319,6 +339,10 @@ bool TRunnerScreen::draw(RenderTexture *render_texture) { walker.draw(TEMP_cube_model); } + for (auto &ee : electricityEffects) { + ee.draw(GREEN); + } + // TODO DEBUG if (!controlled_walker_idx.has_value() && !flags.test(0)) { DrawLine3D(Vector3{0.0F, 3.0F, 0.0F}, mouse_hit, BLACK); diff --git a/src/screen_trunner.h b/src/screen_trunner.h index 27674cd..7a47347 100644 --- a/src/screen_trunner.h +++ b/src/screen_trunner.h @@ -14,6 +14,7 @@ // local includes #include "common_constants.h" +#include "electricity_effect.h" #include "surface_triangle.h" #include "walker.h" @@ -82,6 +83,7 @@ class TRunnerScreen : public Screen { std::unique_ptr > surface_triangles; + std::vector electricityEffects; unsigned int idx_hit; std::optional controlled_walker_idx; const int left_text_width; diff --git a/wasm_build/Makefile b/wasm_build/Makefile index 2fc73b3..aeb738e 100644 --- a/wasm_build/Makefile +++ b/wasm_build/Makefile @@ -17,7 +17,8 @@ SOURCES = \ ../src/raymath.cc \ ../src/walker.cc \ ../src/surface_triangle.cc \ - ../src/screen_walker_hack.cc + ../src/screen_walker_hack.cc \ + ../src/electricity_effect.cc HEADERS = \ ../src/ems.h \ @@ -28,7 +29,8 @@ HEADERS = \ ../src/3d_helpers.h \ ../src/walker.h \ ../src/surface_triangle.h \ - ../src/screen_walker_hack.h + ../src/screen_walker_hack.h \ + ../src/electricity_effect.h OBJECTS = $(addprefix ${OBJDIR}/,$(subst ..,PREVDIR,$(subst .cc,.cc.o,${SOURCES})))