EnergyBallComponent.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /*
  2. * 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.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0 OR MIT
  5. *
  6. */
  7. #include <Source/Components/Multiplayer/EnergyBallComponent.h>
  8. #include <Source/AutoGen/NetworkHealthComponent.AutoComponent.h>
  9. #include <Multiplayer/Components/NetworkTransformComponent.h>
  10. #include <Multiplayer/Components/NetworkRigidBodyComponent.h>
  11. #include <MultiplayerSampleTypes.h>
  12. #include <AzCore/Component/TransformBus.h>
  13. #include <AzFramework/Physics/RigidBodyBus.h>
  14. #if AZ_TRAIT_CLIENT
  15. # include <PopcornFX/PopcornFXBus.h>
  16. #endif
  17. namespace MultiplayerSample
  18. {
  19. AZ_CVAR(float, sv_EnergyBallImpulseScalar, 500.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "A fudge factor for imparting impulses on rigid bodies due to weapon hits");
  20. void EnergyBallComponent::Reflect(AZ::ReflectContext* context)
  21. {
  22. AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
  23. if (serializeContext)
  24. {
  25. serializeContext->Class<EnergyBallComponent, EnergyBallComponentBase>()
  26. ->Version(1);
  27. }
  28. EnergyBallComponentBase::Reflect(context);
  29. }
  30. void EnergyBallComponent::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  31. {
  32. m_effect = GetExplosionEffect();
  33. m_effect.Initialize();
  34. }
  35. void EnergyBallComponent::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  36. {
  37. }
  38. #if AZ_TRAIT_CLIENT
  39. void EnergyBallComponent::HandleRPC_BallLaunched([[maybe_unused]] AzNetworking::IConnection* invokingConnection, [[maybe_unused]] const AZ::Vector3& location)
  40. {
  41. PopcornFX::PopcornFXEmitterComponentRequests* emitterRequests = PopcornFX::PopcornFXEmitterComponentRequestBus::FindFirstHandler(GetEntity()->GetId());
  42. if (emitterRequests != nullptr)
  43. {
  44. emitterRequests->Start();
  45. }
  46. }
  47. void EnergyBallComponent::HandleRPC_BallExplosion([[maybe_unused]] AzNetworking::IConnection* invokingConnection, const AZ::Vector3& location)
  48. {
  49. AZ::Transform transform = AZ::Transform::CreateFromQuaternionAndTranslation(AZ::Quaternion::CreateIdentity(), location);
  50. m_effect.TriggerEffect(transform);
  51. PopcornFX::PopcornFXEmitterComponentRequests* emitterRequests = PopcornFX::PopcornFXEmitterComponentRequestBus::FindFirstHandler(GetEntity()->GetId());
  52. if (emitterRequests != nullptr)
  53. {
  54. emitterRequests->Kill();
  55. }
  56. }
  57. #endif
  58. EnergyBallComponentController::EnergyBallComponentController(EnergyBallComponent& parent)
  59. : EnergyBallComponentControllerBase(parent)
  60. {
  61. }
  62. void EnergyBallComponentController::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  63. {
  64. #if AZ_TRAIT_SERVER
  65. m_collisionCheckEvent.Enqueue(AZ::TimeMs{ 10 }, true);
  66. #endif
  67. }
  68. void EnergyBallComponentController::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  69. {
  70. #if AZ_TRAIT_SERVER
  71. m_collisionCheckEvent.RemoveFromQueue();
  72. #endif
  73. }
  74. #if AZ_TRAIT_SERVER
  75. void EnergyBallComponentController::HandleRPC_LaunchBall([[maybe_unused]] AzNetworking::IConnection* invokingConnection, const AZ::Vector3& startingPosition, const AZ::Vector3& direction, const Multiplayer::NetEntityId& owningNetEntityId)
  76. {
  77. m_shooterNetEntityId = owningNetEntityId;
  78. m_filteredNetEntityIds.clear();
  79. m_filteredNetEntityIds.insert(owningNetEntityId);
  80. m_filteredNetEntityIds.insert(GetNetEntityId());
  81. m_direction = direction;
  82. // move self and increment resetCount to prevent transform interpolation
  83. AZ::TransformBus::Event(GetEntityId(), &AZ::TransformBus::Events::SetWorldTranslation, startingPosition);
  84. GetNetworkTransformComponentController()->ModifyResetCount()++;
  85. Physics::RigidBodyRequestBus::Event(GetEntityId(), &Physics::RigidBodyRequestBus::Events::EnablePhysics);
  86. Physics::RigidBodyRequestBus::Event(GetEntityId(), &Physics::RigidBodyRequestBus::Events::SetLinearVelocity, direction * GetGatherParams().m_travelSpeed);
  87. RPC_BallLaunched(startingPosition);
  88. }
  89. void EnergyBallComponentController::HandleRPC_KillBall([[maybe_unused]] AzNetworking::IConnection* invokingConnection)
  90. {
  91. HideEnergyBall();
  92. }
  93. void EnergyBallComponentController::CheckForCollisions()
  94. {
  95. const AZ::Vector3& position = GetEntity()->GetTransform()->GetWorldTM().GetTranslation();
  96. const HitEffect& effect = GetHitEffect();
  97. IntersectResults results;
  98. const ActivateEvent activateEvent{ GetEntity()->GetTransform()->GetWorldTM(), position, m_shooterNetEntityId, GetNetEntityId() };
  99. GatherEntities(GetGatherParams(), activateEvent, m_filteredNetEntityIds, results);
  100. if (!results.empty())
  101. {
  102. bool shouldTerminate = false;
  103. for (const IntersectResult& result : results)
  104. {
  105. shouldTerminate = true;
  106. Multiplayer::ConstNetworkEntityHandle handle = Multiplayer::GetMultiplayer()->GetNetworkEntityManager()->GetEntity(result.m_netEntityId);
  107. if (handle.Exists())
  108. {
  109. // Presently set to 1 until we capture falloff range
  110. float hitDistance = 1.f;
  111. float maxDistance = 1.f;
  112. float damage = effect.m_hitMagnitude * powf((effect.m_hitFalloff * (1.0f - hitDistance / maxDistance)), effect.m_hitExponent);
  113. // Look for physics rigid body component and make impact updates
  114. if (Multiplayer::NetworkRigidBodyComponent* rigidBodyComponent = handle.GetEntity()->FindComponent<Multiplayer::NetworkRigidBodyComponent>())
  115. {
  116. const AZ::Vector3 explosionCentre = position;
  117. const AZ::Vector3 hitObject = handle.GetEntity()->GetTransform()->GetWorldTM().GetTranslation();
  118. const AZ::Vector3 impulse = (hitObject - position).GetNormalized() * damage * sv_EnergyBallImpulseScalar;
  119. rigidBodyComponent->SendApplyImpulse(impulse, position);
  120. }
  121. // Look for health component and directly update health based on hit parameters
  122. if (NetworkHealthComponent* healthComponent = handle.GetEntity()->FindComponent<NetworkHealthComponent>())
  123. {
  124. healthComponent->SendHealthDelta(damage * -1.0f);
  125. }
  126. }
  127. }
  128. if (shouldTerminate)
  129. {
  130. HideEnergyBall();
  131. }
  132. }
  133. }
  134. void EnergyBallComponentController::HideEnergyBall()
  135. {
  136. RPC_BallExplosion(GetEntity()->GetTransform()->GetWorldTM().GetTranslation());
  137. Physics::RigidBodyRequestBus::Event(GetEntityId(), &Physics::RigidBodyRequestBus::Events::DisablePhysics);
  138. Physics::RigidBodyRequestBus::Event(GetEntityId(), &Physics::RigidBodyRequestBus::Events::SetLinearVelocity, AZ::Vector3::CreateZero());
  139. // move self and increment resetCount to prevent transform interpolation
  140. AZ::TransformBus::Event(GetEntityId(), &AZ::TransformBus::Events::SetWorldTranslation, AZ::Vector3::CreateAxisZ(-1000.f));
  141. GetNetworkTransformComponentController()->ModifyResetCount()++;
  142. }
  143. #endif
  144. }