/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #pragma once #include #include #include #include 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 using DamagePair = AZStd::pair, AZStd::unique_ptr>; DamageManager(const BlastMaterial& blastMaterial, ActorTracker& actorTracker) : m_blastMaterial(blastMaterial) , m_actorTracker(actorTracker) { } template void Damage(T damageType, float damage, const Args&... args); template void Damage(T damageType, BlastActor& actor, float damage, const Args&... args); private: template auto CalculateDamage(T damageType, BlastActor& actor, float damage, const Args&... args); template static void DelegateToSystem( AZStd::unique_ptr desc, AZStd::unique_ptr programParams); [[nodiscard]] DamagePair RadialDamageInternal( BlastActor& actor, float damage, const AZ::Vector3& localPosition, float minRadius, float maxRadius); [[nodiscard]] DamagePair ShearDamageInternal( BlastActor& actor, float damage, const AZ::Vector3& localPosition, float minRadius, float maxRadius, const AZ::Vector3& normal); [[nodiscard]] DamagePair ImpactSpreadDamageInternal( BlastActor& actor, float damage, const AZ::Vector3& localPosition, float minRadius, float maxRadius); [[nodiscard]] DamagePair CapsuleDamageInternal( BlastActor& actor, float damage, const AZ::Vector3& localPosition0, const AZ::Vector3& localPosition1, float minRadius, float maxRadius); [[nodiscard]] DamagePair TriangleDamageInternal( BlastActor& actor, float damage, const AZ::Vector3& localPosition0, const AZ::Vector3& localPosition1, const AZ::Vector3& localPosition2); static AZStd::vector OverlapSphere( ActorTracker& actorTracker, float radius, const AZ::Transform& pose); static AZStd::vector 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; ActorTracker& m_actorTracker; }; template void DamageManager::Damage(T damageType, float damage, const Args&... args) { const float normalizedDamage = m_blastMaterial.GetNormalizedDamage(damage); if (normalizedDamage <= 0.f) { return; } std::tuple tuple(args...); AZStd::vector actors; if constexpr ( std::is_same::value || std::is_same::value || std::is_same::value) { actors = OverlapSphere(m_actorTracker, std::get<2>(tuple), AZ::Transform::CreateTranslation(std::get<0>(tuple))); } else if constexpr (std::is_same::value) { actors = OverlapCapsule(m_actorTracker, std::get<0>(tuple), std::get<1>(tuple), std::get<3>(tuple)); } else if constexpr (std::is_same::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 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 auto DamageManager::CalculateDamage(T damageType, BlastActor& actor, float damage, const Args&... args) { if constexpr (std::is_same::value) { std::tuple 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::value) { std::tuple 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::value) { std::tuple 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::value) { std::tuple 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::value) { std::tuple 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 void DamageManager::DelegateToSystem( AZStd::unique_ptr desc, AZStd::unique_ptr programParams) { AZ::Interface::Get()->AddDamageDesc(AZStd::move(desc)); AZ::Interface::Get()->AddProgramParams(AZStd::move(programParams)); } } // namespace Blast