diff --git a/data/equipment/projectiles/gunbullet.ini b/data/equipment/projectiles/gunbullet.ini index a04e3bad..9a8fcfdc 100644 --- a/data/equipment/projectiles/gunbullet.ini +++ b/data/equipment/projectiles/gunbullet.ini @@ -6,7 +6,7 @@ speed=350.0 spinning=10.0 scale=0.6 emissiveness=0.4 -collisionFieldOfDamage=7.2 +collisionFieldOfDamage=0.8 [hitsound] name=data/sound/hit2.ogg diff --git a/src/scenarios/frozengamescenario.cpp b/src/scenarios/frozengamescenario.cpp index 997f6ac3..768c70f8 100644 --- a/src/scenarios/frozengamescenario.cpp +++ b/src/scenarios/frozengamescenario.cpp @@ -89,9 +89,9 @@ void FrozenGameScenario::populateWorld() { WorldObject *wall = new WorldObject(); wall->transform().move(glm::vec3(-30, 0, -50)); wall->transform().rotate(glm::angleAxis(-90.f, glm::vec3(0, 1, 0))); - for(int x = 0; x < 20; x++) { - for(int y = 0; y < 15; y++) { - for(int z = 0; z < 3; z++) { + for(int x = 0; x < 30; x++) { + for(int y = 0; y < 30; y++) { + for(int z = 0; z < 30; z++) { wall->addVoxel(new Voxel(glm::ivec3(z, x, y), 0xB47878)); } } diff --git a/src/utils/gridneighbourhelper.cpp b/src/utils/gridneighbourhelper.cpp new file mode 100644 index 00000000..d7c4b6c3 --- /dev/null +++ b/src/utils/gridneighbourhelper.cpp @@ -0,0 +1,58 @@ +#include "gridneighbourhelper.h" + + +namespace { + const std::vector directNeighbours { + glm::ivec3(-1, 0, 0), + glm::ivec3(1, 0, 0), + glm::ivec3(0, -1, 0), + glm::ivec3(0, 1, 0), + glm::ivec3(0, 0, -1), + glm::ivec3(0, 0, 1) + }; + + const std::vector diagonalNeighbours { + glm::ivec3(-1, -1, -1), + glm::ivec3(0, -1, -1), + glm::ivec3(1, -1, -1), + glm::ivec3(-1, 0, -1), + glm::ivec3(1, 0, -1), + glm::ivec3(-1, 1, -1), + glm::ivec3(0, 1, -1), + glm::ivec3(1, 1, -1), + glm::ivec3(-1, -1, 0), + glm::ivec3(1, -1, 0), + glm::ivec3(-1, 1, 0), + glm::ivec3(1, 1, 0), + glm::ivec3(-1, -1, 1), + glm::ivec3(0, -1, 1), + glm::ivec3(1, -1, 1), + glm::ivec3(-1, 0, 1), + glm::ivec3(1, 0, 1), + glm::ivec3(-1, 1, 1), + glm::ivec3(0, 1, 1), + glm::ivec3(1, 1, 1) + }; +} + + + + +GridNeighbourHelper::GridNeighbourHelper(const glm::ivec3& cell, bool includeDiagonals) { + m_neighbours.reserve(includeDiagonals ? 26 : 6); + + for (const glm::ivec3& neighbour : directNeighbours) { + m_neighbours.push_back(neighbour + cell); + } + + if (includeDiagonals) { + for (const glm::ivec3& neighbour : diagonalNeighbours) { + m_neighbours.push_back(neighbour + cell); + } + } +} + +const std::vector& GridNeighbourHelper::neighbours() const { + return m_neighbours; +} + diff --git a/src/utils/gridneighbourhelper.h b/src/utils/gridneighbourhelper.h new file mode 100644 index 00000000..15f9c440 --- /dev/null +++ b/src/utils/gridneighbourhelper.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +#include + + +class GridNeighbourHelper { +public: + GridNeighbourHelper(const glm::ivec3& cell, bool includeDiagonals); + + const std::vector& neighbours() const; + + +protected: + std::vector m_neighbours; +}; diff --git a/src/world/handler/damageforwarder.cpp b/src/world/handler/damageforwarder.cpp index 95f8b4a7..58fe7fea 100644 --- a/src/world/handler/damageforwarder.cpp +++ b/src/world/handler/damageforwarder.cpp @@ -2,62 +2,114 @@ #include #include + #include -#include "utils/safenormalize.h" -#include "voxel/voxelcluster.h" -#include "voxel/voxeltreenode.h" +#include "utils/gridneighbourhelper.h" +#include "utils/safenormalize.h" #include "voxel/voxelneighbourhelper.h" -#include "worldobject/worldobject.h" #include "voxel/voxel.h" +#include "voxel/voxelcluster.h" +#include "voxel/voxeltreenode.h" +#include "worldobject/worldobject.h" void DamageForwarder::forwardDamageImpacts(std::list &dampedDeadlyDamageImpacts) { m_damageImpactAccumulator.clear(); - for(DamageImpact &dampedDeadlyDamageImpact : dampedDeadlyDamageImpacts) { - Voxel *deadVoxel = dampedDeadlyDamageImpact.voxel(); + for(DamageImpact& damageImpact : dampedDeadlyDamageImpacts) { + forward(damageImpact); + } +} - m_currentWorldObject = dampedDeadlyDamageImpact.worldObject(); - VoxelNeighbourHelper nHelper(m_currentWorldObject, true); - const std::vector& neighbours = nHelper.neighbours(deadVoxel); +void DamageForwarder::dontForwardTo(std::list &deadVoxels) { + m_damageImpactAccumulator.dontAffect(deadVoxels); +} + +std::list DamageForwarder::forwardedDamageImpacts() { + return m_damageImpactAccumulator.accumulatables(); +} - for(Voxel *neighbour : neighbours) { - glm::vec3 voxelVec = glm::normalize(static_cast(neighbour->gridCell() - deadVoxel->gridCell())); - glm::vec3 damageImpactVec = glm::normalize(glm::inverse(m_currentWorldObject->transform().orientation()) * dampedDeadlyDamageImpact.damageVec()); +void DamageForwarder::forward(DamageImpact& damageImpact) { + m_currentDeadVoxel = damageImpact.voxel(); + m_currentWorldObject = damageImpact.worldObject(); + m_currentDamageVec = damageImpact.damageVec(); + m_currentFieldOfDamage = damageImpact.fieldOfDamage(); - float distanceFactor = 1.0f; - if ((voxelVec.x != 0 && voxelVec.y != 0) || (voxelVec.x != 0 && voxelVec.z != 0) || (voxelVec.y != 0 && voxelVec.z != 0)) { - // diagonals get less damage - distanceFactor = 0.5f; - } + std::vector neighbourCells = GridNeighbourHelper(m_currentDeadVoxel->gridCell(), true).neighbours(); - float dotProduct = glm::dot(damageImpactVec, voxelVec); - glm::vec3 forwardedDamage = dampedDeadlyDamageImpact.damageVec() * forwardFactor(dotProduct, dampedDeadlyDamageImpact.fieldOfDamage(), neighbours.size()); - glm::vec3 createdDamage = voxelVec * deadVoxel->damageForwardingDestructionDamage(); + std::list> forwardedPerNeighbour; + float totalForwardedDamage = 0.0f; + int affectedNeighbourCount = 0; - DamageImpact forwarded(m_currentWorldObject, - neighbour, - distanceFactor * (forwardedDamage + createdDamage), - dampedDeadlyDamageImpact.fieldOfDamage()); - m_damageImpactAccumulator.parse(forwarded); + for(glm::ivec3& neighbourCell : neighbourCells) { + glm::vec3 damageVec = calculateForwardingTo(neighbourCell); + if (damageVec == glm::vec3(0.0f)) { + continue; + } + + affectedNeighbourCount++; + + totalForwardedDamage += glm::length(damageVec); + + Voxel* neighbourVoxel = m_currentWorldObject->voxel(neighbourCell); + if (neighbourVoxel) { + forwardedPerNeighbour.push_back(std::make_pair(neighbourVoxel, damageVec)); } } + + if (forwardedPerNeighbour.empty() || totalForwardedDamage == 0.0f) { + return; + } + + /* Hacked fix to prevent damage from being lost during forwarding + The former algorithm did a nice job distributing damage relatively. That means voxels in the direction + of the damageVec received more damage, incorporated nicely with the fieldOfDamage. + HOWEVER, damage energy is lost during the distribution to the surrounding gridCells. + The calculation and application of the losslessFactor compensates this by virtually determining how much + damage was relatively lost compared to the original damage and multiplicates that to every forwarding + */ + float losslessFactor = ((damageImpact.damage() + m_currentDeadVoxel->damageForwardingDestructionDamage()) / totalForwardedDamage) * (forwardedPerNeighbour.size() / static_cast(affectedNeighbourCount)); + + for (auto& pair : forwardedPerNeighbour) { + DamageImpact forwarded( m_currentWorldObject, + pair.first, + pair.second * losslessFactor, + damageImpact.fieldOfDamage()); + m_damageImpactAccumulator.parse(forwarded); + } } -void DamageForwarder::dontForwardTo(std::list &deadVoxels) { - m_damageImpactAccumulator.dontAffect(deadVoxels); +float DamageForwarder::forwardFactor(float dotProduct, float fieldOfDamage) { + return glm::max(0.0f, (fieldOfDamage - std::acos(dotProduct)) / fieldOfDamage); } -std::list DamageForwarder::forwardedDamageImpacts() { - return m_damageImpactAccumulator.accumulatables(); +glm::vec3 DamageForwarder::calculateForwardingTo(const glm::ivec3& neighbourCell) { + glm::ivec3 gridStep = neighbourCell - m_currentDeadVoxel->gridCell(); + glm::vec3 damageImpactVec = glm::normalize(glm::inverse(m_currentWorldObject->transform().orientation()) * m_currentDamageVec); + + float distanceFactor = calculateDistanceFactor(gridStep); + float dotProduct = glm::dot(damageImpactVec, glm::normalize(glm::vec3(gridStep))); + + glm::vec3 forwardedDamage = m_currentDamageVec * forwardFactor(dotProduct, m_currentFieldOfDamage); + glm::vec3 createdDamage = glm::vec3(gridStep) * m_currentDeadVoxel->damageForwardingDestructionDamage(); + + return distanceFactor * (forwardedDamage + createdDamage); } -float DamageForwarder::forwardFactor(float dotProduct, float fieldOfDamage, int neighbours) { - return glm::max(0.0f, (fieldOfDamage - std::acos(dotProduct)) / fieldOfDamage) / neighbours; +float DamageForwarder::calculateDistanceFactor(const glm::ivec3& gridStep) const { + glm::ivec3 absStep = glm::abs(gridStep); + + int gridSteps = absStep.x + absStep.y + absStep.z; + switch (gridSteps) { + case 1: return 1.00f; + case 2: return 0.70f; + case 3: return 0.58f; + case 4: assert(false); return 0.0f; + } } diff --git a/src/world/handler/damageforwarder.h b/src/world/handler/damageforwarder.h index 225793b3..631911ed 100644 --- a/src/world/handler/damageforwarder.h +++ b/src/world/handler/damageforwarder.h @@ -16,13 +16,18 @@ class DamageForwarder std::list forwardedDamageImpacts(); -protected: - WorldObject *m_currentWorldObject; - std::list *m_currentNeighbours; - glm::ivec3 m_currentGridCell; +protected:; + WorldObject* m_currentWorldObject; + Voxel* m_currentDeadVoxel; + glm::vec3 m_currentDamageVec; + float m_currentFieldOfDamage; VoxelAccumulator m_damageImpactAccumulator; - float forwardFactor(float dotProduct, float fieldOfDamage, int neighbours); + + void forward(DamageImpact& damageImpact); + float forwardFactor(float dotProduct, float fieldOfDamage); + glm::vec3 calculateForwardingTo(const glm::ivec3& neighbourCell); + float calculateDistanceFactor(const glm::ivec3& gridStep) const; }; diff --git a/test/damageforwarder/testdamageforwarder.cpp b/test/damageforwarder/testdamageforwarder.cpp index 7666d662..7ce27032 100644 --- a/test/damageforwarder/testdamageforwarder.cpp +++ b/test/damageforwarder/testdamageforwarder.cpp @@ -50,7 +50,7 @@ go_bandit([]() { }); it("Most basic test", [&] { - DamageImpact i(a, a->voxel(glm::ivec3(0, 0, 0)), glm::vec3(1, 0, 0), glm::half_pi()); + DamageImpact i(a, a->voxel(glm::ivec3(0, 0, 0)), glm::vec3(1, 0, 0), 0.1f); std::list impulses{i}; @@ -63,7 +63,7 @@ go_bandit([]() { }); it("Negative direction test", [&] { - DamageImpact i(a, a->voxel(glm::ivec3(2, 0, 0)), glm::vec3(-2, 0, 0), glm::half_pi()); + DamageImpact i(a, a->voxel(glm::ivec3(2, 0, 0)), glm::vec3(-2, 0, 0), 0.1f); std::list impulses{i}; @@ -77,8 +77,8 @@ go_bandit([]() { }); it("Z Axis Test", [&] { - DamageImpact i1(b, b->voxel(glm::ivec3(0, 0, 0)), glm::vec3(0, 0, 5), glm::half_pi()); - DamageImpact i2(b, b->voxel(glm::ivec3(0, 0, 3)), glm::vec3(0, 0, -3), glm::half_pi()); + DamageImpact i1(b, b->voxel(glm::ivec3(0, 0, 0)), glm::vec3(0, 0, 5), 0.1f); + DamageImpact i2(b, b->voxel(glm::ivec3(0, 0, 3)), glm::vec3(0, 0, -3), 0.1f); std::list impulses{i1, i2}; @@ -101,7 +101,7 @@ go_bandit([]() { }); it("Forwarding from angle != perpendicular", [&] { - DamageImpact i(a, a->voxel(glm::ivec3(0, 0, 0)), glm::vec3(1, 1, 0), glm::half_pi()); + DamageImpact i(a, a->voxel(glm::ivec3(0, 0, 0)), glm::vec3(1, 1, 0), 1.5f); std::list impulses{i}; @@ -110,7 +110,7 @@ go_bandit([]() { DamageImpact f = df->forwardedDamageImpacts().front(); - AssertThat(glm::length(f.damageVec()), EqualsWithDelta(glm::length(i.damageVec()) / 2.0, 0.05)); + AssertThat(glm::length(f.damageVec()), IsGreaterThan(0.0f)); AssertThat(glm::normalize(f.damageVec()), EqualsWithDelta(glm::normalize(i.damageVec()), glm::vec3(0.1, 0.1, 0.1))); }); });