You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/Blast/Code/Source/Family/DamageManager.h

185 lines
7.5 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include "AzCore/Interface/Interface.h"
#include <Blast/BlastMaterial.h>
#include <Family/ActorTracker.h>
#include <Blast/BlastSystemBus.h>
#include <AzCore/Interface/Interface.h>
namespace Blast
{
class BlastActor;
// Class responsible to handling damage and how it applies in the Blast family.
class DamageManager
{
public:
struct RadialDamage
{
};
struct CapsuleDamage
{
};
struct ShearDamage
{
};
struct TriangleDamage
{
};
struct ImpactSpreadDamage
{
};
template<typename T>
using DamagePair = AZStd::pair<AZStd::unique_ptr<T>, AZStd::unique_ptr<NvBlastExtProgramParams>>;
DamageManager(const BlastMaterial& blastMaterial, ActorTracker& actorTracker)
: m_blastMaterial(blastMaterial)
, m_actorTracker(actorTracker)
{
}
template<class T, class... Args>
void Damage(T damageType, float damage, const Args&... args);
template<class T, class... Args>
void Damage(T damageType, BlastActor& actor, float damage, const Args&... args);
private:
template<class T, class... Args>
auto CalculateDamage(T damageType, BlastActor& actor, float damage, const Args&... args);
template<typename T>
static void DelegateToSystem(
AZStd::unique_ptr<T> desc, AZStd::unique_ptr<NvBlastExtProgramParams> programParams);
[[nodiscard]] DamagePair<NvBlastExtRadialDamageDesc> RadialDamageInternal(
BlastActor& actor, float damage, const AZ::Vector3& localPosition, float minRadius, float maxRadius);
[[nodiscard]] DamagePair<NvBlastExtShearDamageDesc> ShearDamageInternal(
BlastActor& actor, float damage, const AZ::Vector3& localPosition, float minRadius, float maxRadius,
const AZ::Vector3& normal);
[[nodiscard]] DamagePair<NvBlastExtImpactSpreadDamageDesc> ImpactSpreadDamageInternal(
BlastActor& actor, float damage, const AZ::Vector3& localPosition, float minRadius, float maxRadius);
[[nodiscard]] DamagePair<NvBlastExtCapsuleRadialDamageDesc> CapsuleDamageInternal(
BlastActor& actor, float damage, const AZ::Vector3& localPosition0, const AZ::Vector3& localPosition1,
float minRadius, float maxRadius);
[[nodiscard]] DamagePair<NvBlastExtTriangleIntersectionDamageDesc> TriangleDamageInternal(
BlastActor& actor, float damage, const AZ::Vector3& localPosition0, const AZ::Vector3& localPosition1,
const AZ::Vector3& localPosition2);
static AZStd::vector<BlastActor*> OverlapSphere(
ActorTracker& actorTracker, float radius, const AZ::Transform& pose);
static AZStd::vector<BlastActor*> OverlapCapsule(
ActorTracker& actorTracker, const AZ::Vector3& position0, const AZ::Vector3& position1, float maxRadius);
static AZ::Vector3 TransformToLocal(BlastActor& actor, const AZ::Vector3& globalPosition);
BlastMaterial m_blastMaterial;
[[maybe_unused]] ActorTracker& m_actorTracker;
};
template<class T, class... Args>
void DamageManager::Damage(T damageType, float damage, const Args&... args)
{
const float normalizedDamage = m_blastMaterial.GetNormalizedDamage(damage);
if (normalizedDamage <= 0.f)
{
return;
}
std::tuple<const Args&...> tuple(args...);
AZStd::vector<BlastActor*> actors;
if constexpr (
std::is_same<T, struct RadialDamage>::value || std::is_same<T, struct ImpactSpreadDamage>::value ||
std::is_same<T, struct ShearDamage>::value)
{
actors =
OverlapSphere(m_actorTracker, std::get<2>(tuple), AZ::Transform::CreateTranslation(std::get<0>(tuple)));
}
else if constexpr (std::is_same<T, struct CapsuleDamage>::value)
{
actors = OverlapCapsule(m_actorTracker, std::get<0>(tuple), std::get<1>(tuple), std::get<3>(tuple));
}
else if constexpr (std::is_same<T, struct TriangleDamage>::value)
{
AZStd::copy(
m_actorTracker.GetActors().begin(), m_actorTracker.GetActors().end(), AZStd::back_inserter(actors));
}
for (auto* actor : actors)
{
auto [desc, programParams] = CalculateDamage(damageType, *actor, normalizedDamage, args...);
DelegateToSystem(AZStd::move(desc), AZStd::move(programParams));
}
}
template<class T, class... Args>
void DamageManager::Damage(T damageType, BlastActor& actor, float damage, const Args&... args)
{
const float normalizedDamage = m_blastMaterial.GetNormalizedDamage(damage);
if (normalizedDamage <= 0.f)
{
return;
}
auto [desc, programParams] = CalculateDamage(damageType, actor, normalizedDamage, args...);
DelegateToSystem(AZStd::move(desc), AZStd::move(programParams));
}
template<class T, class... Args>
auto DamageManager::CalculateDamage([[maybe_unused]] T damageType, BlastActor& actor, float damage, const Args&... args)
{
if constexpr (std::is_same<T, struct RadialDamage>::value)
{
std::tuple<const Args&...> tuple(args...);
return RadialDamageInternal(
actor, damage, TransformToLocal(actor, std::get<0>(tuple)), std::get<1>(tuple), std::get<2>(tuple));
}
else if constexpr (std::is_same<T, struct ShearDamage>::value)
{
std::tuple<const Args&...> tuple(args...);
AZ::Vector3 position = TransformToLocal(actor, std::get<0>(tuple));
AZ::Vector3 normal = TransformToLocal(actor, std::get<3>(tuple));
return ShearDamageInternal(actor, damage, position, std::get<1>(tuple), std::get<2>(tuple), normal);
}
else if constexpr (std::is_same<T, struct ImpactSpreadDamage>::value)
{
std::tuple<const Args&...> tuple(args...);
return ImpactSpreadDamageInternal(
actor, damage, TransformToLocal(actor, std::get<0>(tuple)), std::get<1>(tuple), std::get<2>(tuple));
}
else if constexpr (std::is_same<T, struct CapsuleDamage>::value)
{
std::tuple<const Args&...> tuple(args...);
return CapsuleDamageInternal(
actor, damage, TransformToLocal(actor, std::get<0>(tuple)), TransformToLocal(actor, std::get<1>(tuple)),
std::get<2>(tuple), std::get<3>(tuple));
}
else if constexpr (std::is_same<T, struct TriangleDamage>::value)
{
std::tuple<const Args&...> tuple(args...);
return TriangleDamageInternal(
actor, damage, TransformToLocal(actor, std::get<0>(tuple)), TransformToLocal(actor, std::get<1>(tuple)),
TransformToLocal(actor, std::get<2>(tuple)));
}
}
template<typename T>
void DamageManager::DelegateToSystem(
AZStd::unique_ptr<T> desc, AZStd::unique_ptr<NvBlastExtProgramParams> programParams)
{
AZ::Interface<Blast::BlastSystemRequests>::Get()->AddDamageDesc(AZStd::move(desc));
AZ::Interface<Blast::BlastSystemRequests>::Get()->AddProgramParams(AZStd::move(programParams));
}
} // namespace Blast