Files
o3de/Gems/Blast/Code/Source/Components/BlastFamilyComponent.cpp
T
Aaron Ruiz Mora 00e860f326 Physics material system for spectra launch
- Invalidate 'Physics Materials From Mesh' boolean from collider component
- Removed material library from material selector. Default material library will always be used instead.
- Marking failing automated test as xfail
- Added default material to physics configuration.
- Moved material library asset from physx configuration to physics configuration, as it doesn't need to be physx specific.
- Refactor physics material system having into account that there is only one material library in the project.
- Renaming code from DefaultMaterialLibrary to MaterialLibrary.
- All queries about physics materials unified under PhysicsMaterialRequests bus.
- PhysXSystem only manages the material library asset.
- Saving and reloading the same physics material asset with different content didn't trigger a events that the material library has changed.
- Changing Physics Material Request interface to use shared_ptr instead of weak_ptr to be simpler to handle the returned materials and having a more consistent code.
- Refactored Material Manager to improve its implementation. Still following the same approach of "creating materials on the fly as they are requested", but now it's doing it consistently across the interface, with private helpers functions FindOrCreateMaterial that simplify vastly the implementation.
- Material Manager now listens to change event of material library asset and default material configuration so it updates its materials accordingly.
- Complete Material move constructor and operator.
2021-05-28 20:16:25 +01:00

593 lines
26 KiB
C++

/*
* 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.
*
*/
#include "StdAfx.h"
#include <Components/BlastFamilyComponent.h>
#include <Atom/RPI.Public/Scene.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Math/Transform.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzFramework/Physics/PhysicsSystem.h>
#include <AzFramework/Physics/SystemBus.h>
#include <AzFramework/Physics/MaterialBus.h>
#include <AzFramework/Physics/Collision/CollisionEvents.h>
#include <AzFramework/Physics/Common/PhysicsTypes.h>
#include <Blast/BlastActor.h>
#include <Blast/BlastSystemBus.h>
#include <Common/Utils.h>
#include <Components/BlastFamilyComponentNotificationBusHandler.h>
#include <Components/BlastMeshDataComponent.h>
#include <Family/ActorTracker.h>
#include <Family/BlastFamily.h>
#include <NvBlastExtPxActor.h>
#include <NvBlastTkActor.h>
#include <NvBlastTkFamily.h>
namespace Blast
{
BlastFamilyComponent::BlastFamilyComponent(
const AZ::Data::Asset<BlastAsset> blastAsset, const BlastMaterialId materialId,
Physics::MaterialId physicsMaterialId, const BlastActorConfiguration actorConfiguration)
: m_blastAsset(blastAsset)
, m_materialId(materialId)
, m_physicsMaterialId(physicsMaterialId)
, m_actorConfiguration(actorConfiguration)
, m_debugRenderMode(DebugRenderDisabled)
{
}
void BlastFamilyComponent::Reflect(AZ::ReflectContext* context)
{
BlastFamilyComponentNotificationBusHandler::Reflect(context);
BlastActorConfiguration::Reflect(context);
BlastActorData::Reflect(context);
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
{
serialize->Class<BlastFamilyComponent, AZ::Component>()
->Version(1)
->Field("BlastAsset", &BlastFamilyComponent::m_blastAsset)
->Field("BlastMaterial", &BlastFamilyComponent::m_materialId)
->Field("PhysicsMaterial", &BlastFamilyComponent::m_physicsMaterialId)
->Field("ActorConfiguration", &BlastFamilyComponent::m_actorConfiguration);
}
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->EBus<BlastFamilyDamageRequestBus>("BlastFamilyDamageRequestBus")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "destruction")
->Attribute(AZ::Script::Attributes::Category, "Blast")
->Event(
"Radial Damage", &BlastFamilyDamageRequests::RadialDamage,
{{{"position", "The global position of the damage's hit."},
{"minRadius", "Damages all chunks/bonds that are in the range [0, minRadius] with full damage.",
AZ::BehaviorDefaultValuePtr(aznew AZ::BehaviorDefaultValue(static_cast<float>(0.0)))},
{"maxRadius",
"Damages all chunks/bonds that are in the range [minRadius, maxRadius] with linearly decreasing "
"damage.",
AZ::BehaviorDefaultValuePtr(aznew AZ::BehaviorDefaultValue(static_cast<float>(1.0)))},
{"damage", "How much damage to deal."}}})
->Event(
"Capsule Damage", &BlastFamilyDamageRequests::CapsuleDamage,
{{{"position0", "The global position of one of the capsule's ends."},
{"position1", "The global position of another of the capsule's ends."},
{"minRadius", "Damages all chunks/bonds that are in the range [0, minRadius] with full damage.",
AZ::BehaviorDefaultValuePtr(aznew AZ::BehaviorDefaultValue(static_cast<float>(0.0)))},
{"maxRadius",
"Damages all chunks/bonds that are in the range [minRadius, maxRadius] with linearly decreasing "
"damage.",
AZ::BehaviorDefaultValuePtr(aznew AZ::BehaviorDefaultValue(static_cast<float>(1.0)))},
{"damage", "How much damage to deal."}}})
->Event(
"Shear Damage", &BlastFamilyDamageRequests::ShearDamage,
{{{"position", "The global position of the damage's hit."},
{"normal", "The normal of the damage's hit."},
{"minRadius", "Damages all chunks/bonds that are in the range [0, minRadius] with full damage.",
AZ::BehaviorDefaultValuePtr(aznew AZ::BehaviorDefaultValue(static_cast<float>(0.0)))},
{"maxRadius",
"Damages all chunks/bonds that are in the range [minRadius, maxRadius] with linearly decreasing "
"damage.",
AZ::BehaviorDefaultValuePtr(aznew AZ::BehaviorDefaultValue(static_cast<float>(1.0)))},
{"damage", "How much damage to deal."}}})
->Event(
"Triangle Damage", &BlastFamilyDamageRequests::TriangleDamage,
{{{"position0", "Vertex of the triangle."},
{"position1", "Vertex of the triangle."},
{"position2", "Vertex of the triangle."},
{"damage", "How much damage to deal."}}})
->Event(
"Impact Spread Damage", &BlastFamilyDamageRequests::ImpactSpreadDamage,
{{{"position", "The global position of the damage's hit."},
{"minRadius", "Damages all chunks/bonds that are in the range [0, minRadius] with full damage",
AZ::BehaviorDefaultValuePtr(aznew AZ::BehaviorDefaultValue(static_cast<float>(0.0)))},
{"maxRadius",
"Damages all chunks/bonds that are in the range [minRadius, maxRadius] with linearly decreasing "
"damage.",
AZ::BehaviorDefaultValuePtr(aznew AZ::BehaviorDefaultValue(static_cast<float>(1.0)))},
{"damage", "How much damage to deal."}}})
->Event(
"Stress Damage",
static_cast<void (BlastFamilyDamageRequests::*)(const AZ::Vector3&, const AZ::Vector3&)>(
&BlastFamilyDamageRequests::StressDamage),
{{{"position", "The global position of the damage's hit."},
{"force", "The force applied at the position."}}})
->Event("Get Family Id", &BlastFamilyDamageRequests::GetFamilyId)
->Event("Destroy actor", &BlastFamilyDamageRequests::DestroyActor);
behaviorContext->EBus<BlastFamilyComponentRequestBus>("BlastFamilyComponentRequestBus")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "destruction")
->Attribute(AZ::Script::Attributes::Category, "Blast")
->Event("Get Actors Data", &BlastFamilyComponentRequests::GetActorsData);
behaviorContext->Class<BlastFamilyComponent>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->RequestBus("BlastFamilyDamageRequestBus")
->RequestBus("BlastFamilyComponentRequestBus");
}
}
void BlastFamilyComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("BlastFamilyService"));
}
void BlastFamilyComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("BlastFamilyService"));
incompatible.push_back(AZ_CRC_CE("NonUniformScaleService"));
}
void BlastFamilyComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
required.push_back(AZ_CRC("TransformService", 0x8ee22c50));
}
void BlastFamilyComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
{
dependent.push_back(AZ_CRC("BlastMeshDataService"));
}
AZStd::vector<const BlastActor*> BlastFamilyComponent::GetActors()
{
AZStd::vector<const BlastActor*> actors(
m_family->GetActorTracker().GetActors().begin(), m_family->GetActorTracker().GetActors().end());
return actors;
}
AZStd::vector<BlastActorData> BlastFamilyComponent::GetActorsData()
{
if (!m_family)
{
AZ_Warning("Blast", false, "The family is not active.");
return {};
}
AZStd::vector<BlastActorData> actors;
for (auto actor : m_family->GetActorTracker().GetActors())
{
actors.emplace_back(*actor);
}
return actors;
}
void BlastFamilyComponent::Init()
{
m_meshDataComponent = GetEntity()->FindComponent<BlastMeshDataComponent>();
}
void BlastFamilyComponent::Activate()
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::System);
AZ_Assert(m_blastAsset.GetId().IsValid(), "BlastFamilyComponent created with invalid blast asset.");
Spawn();
BlastFamilyDamageRequestBus::MultiHandler::BusConnect(GetEntityId());
BlastFamilyComponentRequestBus::Handler::BusConnect(GetEntityId());
}
void BlastFamilyComponent::Deactivate()
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::System);
// cleanup collision handlers
for (auto& itr : m_collisionHandlers)
{
itr.second.Disconnect();
}
m_collisionHandlers.clear();
BlastFamilyDamageRequestBus::MultiHandler::BusDisconnect();
BlastFamilyComponentRequestBus::Handler::BusDisconnect();
Despawn();
}
void BlastFamilyComponent::Spawn()
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Physics);
if (!m_blastAsset.IsReady())
{
m_shouldSpawnOnAssetLoad = true;
return;
}
auto blastSystem = AZ::Interface<BlastSystemRequests>::Get();
// Get transform
AZ::Transform transform = AZ::Transform::Identity();
AZ::TransformBus::EventResult(transform, GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
// Get blast material
BlastMaterialFromAssetConfiguration blastMaterialConfiguration;
auto materialLibrary = blastSystem->GetGlobalConfiguration().m_materialLibrary.Get();
if (materialLibrary)
{
materialLibrary->GetDataForMaterialId(m_materialId, blastMaterialConfiguration);
}
auto blastMaterial = BlastMaterial(blastMaterialConfiguration.m_configuration);
AZStd::shared_ptr<EntityProvider> entityProvider = EntityProvider::Create();
// Create family
const BlastFamilyDesc familyDesc
{*m_blastAsset.Get(),
this,
blastSystem->GetTkGroup(),
m_physicsMaterialId,
blastMaterial,
AZStd::make_shared<BlastActorFactoryImpl>(),
entityProvider,
m_actorConfiguration};
m_family = BlastFamily::Create(familyDesc);
// Create stress solver
auto stressSolverSettings =
blastMaterial.GetStressSolverSettings(blastSystem->GetGlobalConfiguration().m_stressSolverIterations);
// Have to do const cast here, because TkFamily does not give non-const family
auto solverPtr = Nv::Blast::ExtStressSolver::create(
const_cast<NvBlastFamily&>(*m_family->GetTkFamily()->getFamilyLL()), stressSolverSettings);
m_solver = physx::unique_ptr<Nv::Blast::ExtStressSolver>(solverPtr);
AZStd::shared_ptr<Physics::Material> physicsMaterial;
Physics::PhysicsMaterialRequestBus::BroadcastResult(
physicsMaterial,
&Physics::PhysicsMaterialRequestBus::Events::GetMaterialById,
m_physicsMaterialId);
if (!physicsMaterial)
{
AZ_Warning("BlastFamilyComponent", false, "Material Id %s was not found, using default material instead.",
m_physicsMaterialId.GetUuid().ToString<AZStd::string>().c_str());
Physics::PhysicsMaterialRequestBus::BroadcastResult(
physicsMaterial,
&Physics::PhysicsMaterialRequestBus::Events::GetGenericDefaultMaterial);
AZ_Assert(physicsMaterial, "BlastFamilyComponent: Invalid default physics material");
}
m_solver->setAllNodesInfoFromLL(physicsMaterial->GetDensity());
// Create damage and actor render managers
m_damageManager = AZStd::make_unique<DamageManager>(blastMaterial, m_family->GetActorTracker());
m_actorRenderManager = AZStd::make_unique<ActorRenderManager>(
AZ::RPI::Scene::GetFeatureProcessorForEntity<AZ::Render::MeshFeatureProcessorInterface>(GetEntityId()),
m_meshDataComponent, GetEntityId(), m_blastAsset->GetPxAsset()->getChunkCount(), transform.GetScale());
// Spawn the family
m_family->Spawn(transform);
m_isSpawned = true;
}
void BlastFamilyComponent::Despawn()
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Physics);
m_isSpawned = false;
m_family = nullptr;
m_actorRenderManager = nullptr;
m_damageManager = nullptr;
m_solver = nullptr;
}
AZ::EntityId BlastFamilyComponent::GetFamilyId()
{
return GetEntityId();
}
void BlastFamilyComponent::RadialDamage(
const AZ::Vector3& position, const float minRadius, const float maxRadius, const float damage)
{
if (const auto* entityIdPtr = BlastFamilyDamageRequestBus::GetCurrentBusId();
!entityIdPtr || *entityIdPtr == GetEntityId())
{
m_damageManager->Damage(DamageManager::RadialDamage{}, damage, position, minRadius, maxRadius);
}
else if (auto* actor = m_family->GetActorTracker().GetActorById(*entityIdPtr); actor != nullptr)
{
m_damageManager->Damage(DamageManager::RadialDamage{}, *actor, damage, position, minRadius, maxRadius);
}
}
void BlastFamilyComponent::CapsuleDamage(
const AZ::Vector3& position0, const AZ::Vector3& position1, float minRadius, float maxRadius, float damage)
{
if (const auto* entityIdPtr = BlastFamilyDamageRequestBus::GetCurrentBusId();
!entityIdPtr || *entityIdPtr == GetEntityId())
{
m_damageManager->Damage(DamageManager::CapsuleDamage{}, damage, position0, position1, minRadius, maxRadius);
}
else if (auto* actor = m_family->GetActorTracker().GetActorById(*entityIdPtr); actor != nullptr)
{
m_damageManager->Damage(
DamageManager::CapsuleDamage{}, *actor, damage, position0, position1, minRadius, maxRadius);
}
}
void BlastFamilyComponent::ShearDamage(
const AZ::Vector3& position, const AZ::Vector3& normal, float minRadius, float maxRadius, float damage)
{
if (const auto* entityIdPtr = BlastFamilyDamageRequestBus::GetCurrentBusId();
!entityIdPtr || *entityIdPtr == GetEntityId())
{
m_damageManager->Damage(DamageManager::ShearDamage{}, damage, position, minRadius, maxRadius, normal);
}
else if (auto* actor = m_family->GetActorTracker().GetActorById(*entityIdPtr); actor != nullptr)
{
m_damageManager->Damage(
DamageManager::ShearDamage{}, *actor, damage, position, minRadius, maxRadius, normal);
}
}
void BlastFamilyComponent::TriangleDamage(
const AZ::Vector3& position0, const AZ::Vector3& position1, const AZ::Vector3& position2, float damage)
{
if (const auto* entityIdPtr = BlastFamilyDamageRequestBus::GetCurrentBusId();
!entityIdPtr || *entityIdPtr == GetEntityId())
{
m_damageManager->Damage(DamageManager::TriangleDamage{}, damage, position0, position1, position2);
}
else if (auto* actor = m_family->GetActorTracker().GetActorById(*entityIdPtr); actor != nullptr)
{
m_damageManager->Damage(DamageManager::TriangleDamage{}, *actor, damage, position0, position1, position2);
}
}
void BlastFamilyComponent::ImpactSpreadDamage(
const AZ::Vector3& position, float minRadius, float maxRadius, float damage)
{
if (const auto* entityIdPtr = BlastFamilyDamageRequestBus::GetCurrentBusId();
!entityIdPtr || *entityIdPtr == GetEntityId())
{
m_damageManager->Damage(DamageManager::ImpactSpreadDamage{}, damage, position, minRadius, maxRadius);
}
else if (auto* actor = m_family->GetActorTracker().GetActorById(*entityIdPtr); actor != nullptr)
{
m_damageManager->Damage(
DamageManager::ImpactSpreadDamage{}, *actor, damage, position, minRadius, maxRadius);
}
}
void BlastFamilyComponent::StressDamage(const AZ::Vector3& position, const AZ::Vector3& force)
{
if (const auto* closestActor = m_family->GetActorTracker().FindClosestActor(position))
{
StressDamage(*closestActor, position, force);
}
}
void BlastFamilyComponent::StressDamage(
const BlastActor& blastActor, const AZ::Vector3& position, const AZ::Vector3& force)
{
m_solver->addForce(*blastActor.GetTkActor().getActorLL(), Convert(position), Convert(force));
}
void BlastFamilyComponent::DestroyActor()
{
if (auto entityIdPtr = BlastFamilyDamageRequestBus::GetCurrentBusId();
!entityIdPtr || *entityIdPtr == GetEntityId())
{
Despawn();
}
else
{
m_family->DestroyActor(m_family->GetActorTracker().GetActorById(*entityIdPtr));
}
}
void BlastFamilyComponent::OnCollisionBegin(const AzPhysics::CollisionEvent& collisionEvent)
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Physics);
for (const auto* body : {collisionEvent.m_body1, collisionEvent.m_body2})
{
auto blastActor = m_family->GetActorTracker().GetActorByBody(body);
if (!blastActor)
{
continue;
}
for (auto& contact : collisionEvent.m_contacts)
{
auto hitpos = body->GetTransform().GetInverse().TransformPoint(contact.m_position);
StressDamage(*blastActor, hitpos, contact.m_impulse);
}
}
}
void BlastFamilyComponent::FillDebugRenderBuffer(
DebugRenderBuffer& debugRenderBuffer, DebugRenderMode debugRenderMode)
{
if (m_family)
{
m_family->FillDebugRender(debugRenderBuffer, debugRenderMode, 1.0);
}
if (!(DebugRenderStressGraph <= debugRenderMode && debugRenderMode <= DebugRenderStressGraphBondsImpulses))
{
return;
}
for (const BlastActor* blastActor : m_family->GetActorTracker().GetActors())
{
Nv::Blast::TkActor& actor = blastActor->GetTkActor();
auto lineStartIndex = aznumeric_cast<uint32_t>(debugRenderBuffer.m_lines.size());
uint32_t nodeCount = actor.getGraphNodeCount();
if (nodeCount == 0)
{
// subsupport chunks don't have graph nodes
continue;
}
std::vector<uint32_t> nodes(nodeCount);
actor.getGraphNodeIndices(nodes.data(), aznumeric_cast<uint32_t>(nodes.size()));
if (m_solver)
{
const auto buffer = m_solver->fillDebugRender(
nodes.data(), aznumeric_cast<uint32_t>(nodes.size()),
static_cast<Nv::Blast::ExtStressSolver::DebugRenderMode>(debugRenderMode - DebugRenderStressGraph),
1.0);
if (buffer.lineCount)
{
for (auto i = 0u; i < buffer.lineCount; ++i)
{
auto& line = buffer.lines[i];
AZ::Color color;
color.FromU32(line.color0);
debugRenderBuffer.m_lines.emplace_back(
AZ::Vector3(line.pos0.x, line.pos0.y, line.pos0.z),
AZ::Vector3(line.pos1.x, line.pos1.y, line.pos1.z), color);
}
}
}
// transform all added lines from local to global
const AZ::Transform& localToGlobal = blastActor->GetSimulatedBody()->GetTransform();
for (uint32_t i = lineStartIndex; i < debugRenderBuffer.m_lines.size(); i++)
{
DebugLine& line = debugRenderBuffer.m_lines[i];
line.m_p0 = localToGlobal.TransformPoint(line.m_p0);
line.m_p1 = localToGlobal.TransformPoint(line.m_p1);
}
}
}
void BlastFamilyComponent::ApplyStressDamage()
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Physics);
if (m_solver)
{
for (auto actor : m_family->GetActorTracker().GetActors())
{
auto worldBody = actor->GetSimulatedBody();
if (actor->IsStatic())
{
AZ::Vector3 gravity = AzPhysics::DefaultGravity;
if (auto* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get())
{
gravity = sceneInterface->GetGravity(worldBody->m_sceneOwner);
}
auto localGravity =
worldBody->GetTransform().GetRotation().GetInverseFull().TransformVector(gravity);
m_solver->addGravityForce(*actor->GetTkActor().getActorLL(), Convert(localGravity));
}
else
{
auto* rigidBody = static_cast<AzPhysics::RigidBody*>(worldBody);
auto localCenterMass = rigidBody->GetCenterOfMassLocal();
auto localAngularVelocity =
worldBody->GetTransform().GetRotation().GetInverseFull().TransformVector(
rigidBody->GetAngularVelocity());
m_solver->addAngularVelocity(
*actor->GetTkActor().getActorLL(), Convert(localCenterMass), Convert(localAngularVelocity));
}
}
m_solver->update();
if (m_solver->getOverstressedBondCount() > 0)
{
NvBlastFractureBuffers commands;
m_solver->generateFractureCommands(commands);
if (commands.bondFractureCount > 0)
{
m_family->GetTkFamily()->applyFracture(&commands);
}
}
}
}
void BlastFamilyComponent::OnActorCreated([[maybe_unused]] const BlastFamily& family, const BlastActor& actor)
{
m_actorRenderManager->OnActorCreated(actor);
m_solver->notifyActorCreated(*actor.GetTkActor().getActorLL());
if (auto* physicsSystem = AZ::Interface<AzPhysics::SystemInterface>::Get())
{
AZStd::pair<AzPhysics::SceneHandle, AzPhysics::SimulatedBodyHandle> foundBody = physicsSystem->FindAttachedBodyHandleFromEntityId(actor.GetEntity()->GetId());
if (foundBody.first != AzPhysics::InvalidSceneHandle)
{
AzPhysics::SimulatedBodyEvents::OnCollisionBegin::Handler collisionHandler = AzPhysics::SimulatedBodyEvents::OnCollisionBegin::Handler(
[this]([[maybe_unused]] AzPhysics::SimulatedBodyHandle bodyHandle, const AzPhysics::CollisionEvent& event)
{
OnCollisionBegin(event);
});
CollisionHandlersMap::pair_iter_bool newHandlerItr = m_collisionHandlers.emplace(actor.GetEntity()->GetId(), collisionHandler);
AzPhysics::SimulatedBodyEvents::RegisterOnCollisionBeginHandler(foundBody.first, foundBody.second, newHandlerItr.first->second);
}
}
BlastFamilyDamageRequestBus::MultiHandler::BusConnect(actor.GetEntity()->GetId());
BlastFamilyComponentNotificationBus::Event(
GetEntityId(), &BlastFamilyComponentNotifications::OnActorCreated, actor);
}
void BlastFamilyComponent::OnActorDestroyed([[maybe_unused]] const BlastFamily& family, const BlastActor& actor)
{
BlastFamilyComponentNotificationBus::Event(
GetEntityId(), &BlastFamilyComponentNotifications::OnActorDestroyed, actor);
BlastFamilyDamageRequestBus::MultiHandler::BusDisconnect(actor.GetEntity()->GetId());
if (CollisionHandlersMapItr foundHandler = m_collisionHandlers.find(actor.GetEntity()->GetId());
foundHandler != m_collisionHandlers.end())
{
foundHandler->second.Disconnect();
m_collisionHandlers.erase(foundHandler);
}
m_solver->notifyActorDestroyed(*actor.GetTkActor().getActorLL());
m_actorRenderManager->OnActorDestroyed(actor);
}
// Update positions of entities with render meshes corresponding to their right dynamic bodies.
void BlastFamilyComponent::SyncMeshes()
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Physics);
if (m_actorRenderManager)
{
m_actorRenderManager->SyncMeshes();
}
}
} // namespace Blast