|
|
@@ -5,6 +5,8 @@
|
|
|
#include "../../game/systems/projectile_system.h"
|
|
|
#include "../../game/systems/stone_projectile.h"
|
|
|
#include "../scene_renderer.h"
|
|
|
+#include <algorithm>
|
|
|
+#include <unordered_set>
|
|
|
|
|
|
namespace Render::GL {
|
|
|
|
|
|
@@ -25,15 +27,45 @@ constexpr float kFlameColorG = 0.4F;
|
|
|
constexpr float kFlameColorB = 0.1F;
|
|
|
constexpr float kBuildingHealthThreshold = 0.5F;
|
|
|
|
|
|
-constexpr float kStoneImpactRadius = 4.0F;
|
|
|
-constexpr float kStoneImpactIntensity = 1.2F;
|
|
|
-constexpr float kStoneImpactColorR = 0.85F;
|
|
|
-constexpr float kStoneImpactColorG = 0.75F;
|
|
|
-constexpr float kStoneImpactColorB = 0.55F;
|
|
|
-constexpr float kStoneImpactYOffset = 0.15F;
|
|
|
-constexpr float kStoneImpactThreshold = 0.95F;
|
|
|
+constexpr float kStoneImpactRadius = 0.6F;
|
|
|
+constexpr float kStoneImpactIntensity = 1.5F;
|
|
|
+constexpr float kStoneImpactColorR = 0.75F;
|
|
|
+constexpr float kStoneImpactColorG = 0.65F;
|
|
|
+constexpr float kStoneImpactColorB = 0.45F;
|
|
|
+constexpr float kStoneImpactYOffset = 0.1F;
|
|
|
+constexpr float kStoneImpactDuration = 10.0F;
|
|
|
+constexpr float kStoneImpactTriggerProgress = 0.99F;
|
|
|
+
|
|
|
+std::unordered_set<const void *> g_tracked_projectiles;
|
|
|
} // namespace
|
|
|
|
|
|
+auto StoneImpactTracker::instance() -> StoneImpactTracker & {
|
|
|
+ static StoneImpactTracker instance;
|
|
|
+ return instance;
|
|
|
+}
|
|
|
+
|
|
|
+void StoneImpactTracker::add_impact(const QVector3D &position,
|
|
|
+ float current_time, float radius,
|
|
|
+ float intensity) {
|
|
|
+ StoneImpactEffect effect;
|
|
|
+ effect.position = position;
|
|
|
+ effect.start_time = current_time;
|
|
|
+ effect.duration = kStoneImpactDuration;
|
|
|
+ effect.radius = radius;
|
|
|
+ effect.intensity = intensity;
|
|
|
+ m_impacts.push_back(effect);
|
|
|
+}
|
|
|
+
|
|
|
+void StoneImpactTracker::update(float current_time) {
|
|
|
+ m_impacts.erase(
|
|
|
+ std::remove_if(m_impacts.begin(), m_impacts.end(),
|
|
|
+ [current_time](const StoneImpactEffect &impact) {
|
|
|
+ return (current_time - impact.start_time) >
|
|
|
+ impact.duration;
|
|
|
+ }),
|
|
|
+ m_impacts.end());
|
|
|
+}
|
|
|
+
|
|
|
void render_combat_dust(Renderer *renderer, ResourceManager *,
|
|
|
Engine::Core::World *world) {
|
|
|
if (renderer == nullptr || world == nullptr) {
|
|
|
@@ -123,14 +155,12 @@ void render_combat_dust(Renderer *renderer, ResourceManager *,
|
|
|
}
|
|
|
|
|
|
auto *projectile_sys = world->get_system<Game::Systems::ProjectileSystem>();
|
|
|
+ auto &impact_tracker = StoneImpactTracker::instance();
|
|
|
+
|
|
|
if (projectile_sys != nullptr) {
|
|
|
const auto &projectiles = projectile_sys->projectiles();
|
|
|
|
|
|
for (const auto &projectile : projectiles) {
|
|
|
- if (!projectile->is_active()) {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
auto *stone_proj = dynamic_cast<const Game::Systems::StoneProjectile *>(
|
|
|
projectile.get());
|
|
|
if (stone_proj == nullptr) {
|
|
|
@@ -138,28 +168,58 @@ void render_combat_dust(Renderer *renderer, ResourceManager *,
|
|
|
}
|
|
|
|
|
|
float progress = stone_proj->get_progress();
|
|
|
- if (progress < kStoneImpactThreshold) {
|
|
|
+ if (progress < kStoneImpactTriggerProgress) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ const void *proj_ptr = static_cast<const void *>(stone_proj);
|
|
|
+ if (g_tracked_projectiles.find(proj_ptr) != g_tracked_projectiles.end()) {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- const QVector3D delta = stone_proj->get_end() - stone_proj->get_start();
|
|
|
- QVector3D impact_pos =
|
|
|
- stone_proj->get_start() + delta * stone_proj->get_progress();
|
|
|
+ g_tracked_projectiles.insert(proj_ptr);
|
|
|
+
|
|
|
+ QVector3D impact_pos = stone_proj->get_end();
|
|
|
|
|
|
if (!visibility.is_entity_visible(impact_pos.x(), impact_pos.z(),
|
|
|
- kVisibilityCheckRadius)) {
|
|
|
+ kVisibilityCheckRadius * 2.0F)) {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- QVector3D position(impact_pos.x(),
|
|
|
- stone_proj->get_end().y() + kStoneImpactYOffset,
|
|
|
+ QVector3D position(impact_pos.x(), impact_pos.y() + kStoneImpactYOffset,
|
|
|
impact_pos.z());
|
|
|
- QVector3D color(kStoneImpactColorR, kStoneImpactColorG,
|
|
|
- kStoneImpactColorB);
|
|
|
|
|
|
- renderer->building_flame(position, color, kStoneImpactRadius,
|
|
|
- kStoneImpactIntensity, animation_time);
|
|
|
+ impact_tracker.add_impact(position, animation_time, kStoneImpactRadius,
|
|
|
+ kStoneImpactIntensity);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ std::erase_if(g_tracked_projectiles, [projectile_sys](const void *ptr) {
|
|
|
+ if (projectile_sys == nullptr) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ const auto &projectiles = projectile_sys->projectiles();
|
|
|
+ for (const auto &p : projectiles) {
|
|
|
+ if (static_cast<const void *>(p.get()) == ptr) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
}
|
|
|
+ return true;
|
|
|
+ });
|
|
|
+
|
|
|
+ impact_tracker.update(animation_time);
|
|
|
+
|
|
|
+ QVector3D color(kStoneImpactColorR, kStoneImpactColorG, kStoneImpactColorB);
|
|
|
+ for (const auto &impact : impact_tracker.impacts()) {
|
|
|
+ if (!visibility.is_entity_visible(impact.position.x(), impact.position.z(),
|
|
|
+ impact.radius)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ float impact_time = animation_time - impact.start_time;
|
|
|
+
|
|
|
+ renderer->stone_impact(impact.position, color, impact.radius,
|
|
|
+ impact.intensity, impact_time);
|
|
|
}
|
|
|
}
|
|
|
|