diff --git a/src/electricity_effect.cc b/src/electricity_effect.cc index 33eebcc..699b422 100644 --- a/src/electricity_effect.cc +++ b/src/electricity_effect.cc @@ -2,6 +2,7 @@ // standard library includes #include +#include // third party includes #include @@ -13,39 +14,60 @@ ElectricityEffect::ElectricityEffect(Vector3 center, float radius, int line_count, float lifetime) - : cylinders(), lifetime(lifetime), timer(0.0F) { + : cylinders(), + center(center), + radius(radius), + lifetime(lifetime), + timer(0.0F) { cylinders.reserve(line_count); + const float line_max_length = radius * CYLINDER_LINE_MAX_LENGTH_RATIO; + // Generate cylinders. - std::queue positions; - Vector3 next, dir; - for (unsigned int idx = 0; idx < CYLINDER_SPLIT_COUNT; ++idx) { - positions.push(center); + std::queue> positions; + std::tuple next; + Vector3 next_pos, dir; + for (unsigned int idx = 0; idx < CYLINDER_SPLIT_COUNT && line_count > 0; + ++idx, --line_count) { + cylinders.push_back(Cylinder{.next_idx = -1, + .point = center, + .mdir = Vector3Normalize(Vector3{ + call_js_get_random() * 2.0F - 1.0F, + call_js_get_random() * 2.0F - 1.0F, + call_js_get_random() * 2.0F - 1.0F, + })}); + positions.push({center, cylinders.size() - 1}); } while (line_count-- > 0 && !positions.empty()) { next = positions.front(); + next_pos = std::get(next); positions.pop(); - dir = Vector3Normalize(center - next); + dir = Vector3Normalize(center - next_pos); dir = Vector3Normalize(Vector3{call_js_get_random() * 2.0F - 1.0F, call_js_get_random() * 2.0F - 1.0F, call_js_get_random() * 2.0F - 1.0F} + dir); - auto coll = GetRayCollisionSphere(Ray{.position = next, .direction = dir}, - center, radius); + auto coll = GetRayCollisionSphere( + Ray{.position = next_pos, .direction = dir}, center, radius); - if (coll.distance > CYLINDER_LINE_MAX_LENGTH) { + if (coll.distance > line_max_length) { coll.point = - next + Vector3Normalize(coll.point - next) * CYLINDER_LINE_MAX_LENGTH; + next_pos + Vector3Normalize(coll.point - next_pos) * line_max_length; } - cylinders.push_back(Cylinder{.start = next, .end = coll.point}); + cylinders.push_back(Cylinder{ + .next_idx = std::get(next), + .point = coll.point, + .mdir = Vector3Normalize(Vector3{call_js_get_random() * 2.0F - 1.0F, + call_js_get_random() * 2.0F - 1.0F, + call_js_get_random() * 2.0F - 1.0F})}); dir = Vector3Normalize(center - coll.point); coll.point = coll.point + dir * (radius * CYLINDER_EDGE_OFFSET); for (unsigned int idx = 0; idx < CYLINDER_SPLIT_COUNT; ++idx) { - positions.push(coll.point); + positions.push({coll.point, cylinders.size() - 1}); } } } @@ -53,6 +75,21 @@ ElectricityEffect::ElectricityEffect(Vector3 center, float radius, bool ElectricityEffect::update(float dt) { timer += dt; + for (auto &cylinder : cylinders) { + cylinder.point = cylinder.point + cylinder.mdir * (dt * CYLINDER_MOVE_RATE); + if (Vector3Distance(cylinder.point, center) > radius) { + cylinder.point = + cylinder.point - cylinder.mdir * (dt * CYLINDER_MOVE_RATE); + Vector3 to_center = center - cylinder.point; + Vector3 perpendicular = Vector3Normalize(Vector3Perpendicular(to_center)); + cylinder.mdir = Vector3Normalize( + to_center + Vector3RotateByAxisAngle(perpendicular, + Vector3Normalize(to_center), + call_js_get_random() * PI * 2) * + (call_js_get_random() * radius)); + } + } + return timer >= lifetime; } @@ -60,7 +97,10 @@ 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, CYLINDER_SIDES, color); + if (cylinder.next_idx >= 0) { + DrawCylinderEx(cylinder.point, cylinders.at(cylinder.next_idx).point, + CYLINDER_MAX_RADIUS * ratio, CYLINDER_MAX_RADIUS * ratio, + CYLINDER_SIDES, color); + } } } diff --git a/src/electricity_effect.h b/src/electricity_effect.h index bb43010..e82d63a 100644 --- a/src/electricity_effect.h +++ b/src/electricity_effect.h @@ -11,7 +11,8 @@ constexpr int CYLINDER_SPLIT_COUNT = 3; constexpr int CYLINDER_SIDES = 3; constexpr float CYLINDER_MAX_RADIUS = 0.03F; constexpr float CYLINDER_EDGE_OFFSET = 0.01F; -constexpr float CYLINDER_LINE_MAX_LENGTH = 1.5F; +constexpr float CYLINDER_LINE_MAX_LENGTH_RATIO = 0.85F; +constexpr float CYLINDER_MOVE_RATE = 0.05F; class ElectricityEffect { public: @@ -25,10 +26,13 @@ class ElectricityEffect { private: struct Cylinder { - Vector3 start, end; + int next_idx; + Vector3 point, mdir; }; std::vector cylinders; + Vector3 center; + float radius; float lifetime; float timer; }; diff --git a/src/screen_trunner.cc b/src/screen_trunner.cc index 1b9e472..fea5b55 100644 --- a/src/screen_trunner.cc +++ b/src/screen_trunner.cc @@ -101,8 +101,9 @@ bool TRunnerScreen::update(float dt, bool is_resized) { 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, - ELECTRICITY_EFFECT_LINE_COUNT, 1.0F)); + walkers[controlled_walker_idx.value()].get_body_pos(), + ELECTRICITY_EFFECT_RADIUS, ELECTRICITY_EFFECT_LINE_COUNT, + ELECTRICITY_EFFECT_LIFETIME)); } else { controlled_walker_idx.reset(); diff --git a/src/screen_trunner.h b/src/screen_trunner.h index 2289d72..966cf61 100644 --- a/src/screen_trunner.h +++ b/src/screen_trunner.h @@ -30,6 +30,8 @@ constexpr float SURFACE_RESET_TIME_TRI_DRAW = 3.0F; constexpr float SURFACE_RESET_Y_OFFSET = 40.0F; constexpr int ELECTRICITY_EFFECT_LINE_COUNT = 35; +constexpr float ELECTRICITY_EFFECT_RADIUS = 2.0F; +constexpr float ELECTRICITY_EFFECT_LIFETIME = 3.0F; class TRunnerScreen : public Screen { public: