Bladeren bron

Fixes for energy ball tunneling and impact damage decal effects

Signed-off-by: kberg-amzn <[email protected]>
kberg-amzn 2 jaren geleden
bovenliggende
commit
16faa56066

+ 1 - 1
Gem/Code/Source/AutoGen/EnergyBallComponent.AutoComponent.xml

@@ -30,6 +30,6 @@
     </RemoteProcedure>
     </RemoteProcedure>
 
 
     <RemoteProcedure Name="RPC_BallExplosion" InvokeFrom="Authority" HandleOn="Client" IsPublic="true" IsReliable="true" GenerateEventBindings="true" Description="Triggered on clients whenever an energy ball explodes.">
     <RemoteProcedure Name="RPC_BallExplosion" InvokeFrom="Authority" HandleOn="Client" IsPublic="true" IsReliable="true" GenerateEventBindings="true" Description="Triggered on clients whenever an energy ball explodes.">
-        <Param Type="AZ::Vector3" Name="Location"/>
+        <Param Type="HitEvent" Name="HitEvent"/>
     </RemoteProcedure>
     </RemoteProcedure>
 </Component>
 </Component>

+ 30 - 16
Gem/Code/Source/Components/Multiplayer/EnergyBallComponent.cpp

@@ -53,11 +53,19 @@ namespace MultiplayerSample
         }
         }
     }
     }
 
 
-    void EnergyBallComponent::HandleRPC_BallExplosion([[maybe_unused]] AzNetworking::IConnection* invokingConnection, const AZ::Vector3& location)
+    void EnergyBallComponent::HandleRPC_BallExplosion([[maybe_unused]] AzNetworking::IConnection* invokingConnection, const HitEvent& hitEvent)
     {
     {
-        AZ::Transform transform = AZ::Transform::CreateFromQuaternionAndTranslation(AZ::Quaternion::CreateIdentity(), location);
+        AZ::Transform transform = AZ::Transform::CreateFromQuaternionAndTranslation(AZ::Quaternion::CreateIdentity(), hitEvent.m_target);
         m_effect.TriggerEffect(transform);
         m_effect.TriggerEffect(transform);
 
 
+        for (const HitEntity& hitEntity : hitEvent.m_hitEntities)
+        {
+            const AZ::Transform hitTransform = AZ::Transform::CreateLookAt(hitEntity.m_hitPosition, hitEntity.m_hitPosition + hitEntity.m_hitNormal, AZ::Transform::Axis::ZPositive);
+            const Multiplayer::ConstNetworkEntityHandle handle = Multiplayer::GetNetworkEntityManager()->GetEntity(hitEntity.m_hitNetEntityId);
+            const AZ::EntityId hitEntityId = handle.Exists() ? handle.GetEntity()->GetId() : AZ::EntityId();
+            WeaponNotificationBus::Broadcast(&WeaponNotificationBus::Events::OnWeaponImpact, GetEntity()->GetId(), hitTransform, hitEntityId);
+        }
+
         PopcornFX::PopcornFXEmitterComponentRequests* emitterRequests = PopcornFX::PopcornFXEmitterComponentRequestBus::FindFirstHandler(GetEntity()->GetId());
         PopcornFX::PopcornFXEmitterComponentRequests* emitterRequests = PopcornFX::PopcornFXEmitterComponentRequestBus::FindFirstHandler(GetEntity()->GetId());
         if (emitterRequests != nullptr)
         if (emitterRequests != nullptr)
         {
         {
@@ -90,6 +98,7 @@ namespace MultiplayerSample
     void EnergyBallComponentController::HandleRPC_LaunchBall([[maybe_unused]] AzNetworking::IConnection* invokingConnection, const AZ::Vector3& startingPosition, const AZ::Vector3& direction, const Multiplayer::NetEntityId& owningNetEntityId)
     void EnergyBallComponentController::HandleRPC_LaunchBall([[maybe_unused]] AzNetworking::IConnection* invokingConnection, const AZ::Vector3& startingPosition, const AZ::Vector3& direction, const Multiplayer::NetEntityId& owningNetEntityId)
     {
     {
         m_shooterNetEntityId = owningNetEntityId;
         m_shooterNetEntityId = owningNetEntityId;
+        m_hitEvent.m_hitEntities.clear();
 
 
         m_filteredNetEntityIds.clear();
         m_filteredNetEntityIds.clear();
         m_filteredNetEntityIds.insert(owningNetEntityId);
         m_filteredNetEntityIds.insert(owningNetEntityId);
@@ -99,6 +108,9 @@ namespace MultiplayerSample
         // Move the entity to the start position
         // Move the entity to the start position
         GetEntity()->GetTransform()->SetWorldTranslation(startingPosition);
         GetEntity()->GetTransform()->SetWorldTranslation(startingPosition);
 
 
+        // We want to sweep our transform during intersect tests to avoid the ball tunneling through targets
+        m_lastSweepTransform = GetEntity()->GetTransform()->GetWorldTM();
+
         Physics::RigidBodyRequestBus::Event(GetEntityId(), &Physics::RigidBodyRequestBus::Events::EnablePhysics);
         Physics::RigidBodyRequestBus::Event(GetEntityId(), &Physics::RigidBodyRequestBus::Events::EnablePhysics);
         Physics::RigidBodyRequestBus::Event(GetEntityId(), &Physics::RigidBodyRequestBus::Events::SetLinearVelocity, direction * GetGatherParams().m_travelSpeed);
         Physics::RigidBodyRequestBus::Event(GetEntityId(), &Physics::RigidBodyRequestBus::Events::SetLinearVelocity, direction * GetGatherParams().m_travelSpeed);
 
 
@@ -115,23 +127,22 @@ namespace MultiplayerSample
         const AZ::Vector3& position = GetEntity()->GetTransform()->GetWorldTM().GetTranslation();
         const AZ::Vector3& position = GetEntity()->GetTransform()->GetWorldTM().GetTranslation();
         const HitEffect& effect = GetHitEffect();
         const HitEffect& effect = GetHitEffect();
 
 
+        // Sweep from our last checked transform to our current position to avoid tunneling
+        const ActivateEvent activateEvent{ m_lastSweepTransform, position, m_shooterNetEntityId, GetNetEntityId() };
+
         IntersectResults results;
         IntersectResults results;
-        const ActivateEvent activateEvent{ GetEntity()->GetTransform()->GetWorldTM(), position, m_shooterNetEntityId, GetNetEntityId() };
         GatherEntities(GetGatherParams(), activateEvent, m_filteredNetEntityIds, results);
         GatherEntities(GetGatherParams(), activateEvent, m_filteredNetEntityIds, results);
+
         if (!results.empty())
         if (!results.empty())
         {
         {
-            bool shouldTerminate = false;
             for (const IntersectResult& result : results)
             for (const IntersectResult& result : results)
             {
             {
-                shouldTerminate = true;
+                // The hit position and normal coming out of swept overlap checks appear to be all zero vectors
+                // For now we'll use the final entity position and direction of travel as placeholders for our visual effects
+                const HitEntity hitEntity{ position, -m_direction, result.m_netEntityId };
+                m_hitEvent.m_hitEntities.emplace_back(hitEntity);
 
 
-                // The hit normal appears to be invalid (0, 0, 0) coming out of overlaps like we use in our gather
-                // Default to using the travel direction
-                const AZ::Transform hitTransform = AZ::Transform::CreateLookAt(result.m_position, result.m_position - m_direction, AZ::Transform::Axis::ZPositive);
                 const Multiplayer::ConstNetworkEntityHandle handle = Multiplayer::GetNetworkEntityManager()->GetEntity(result.m_netEntityId);
                 const Multiplayer::ConstNetworkEntityHandle handle = Multiplayer::GetNetworkEntityManager()->GetEntity(result.m_netEntityId);
-                const AZ::EntityId hitEntityId = handle.Exists() ? handle.GetEntity()->GetId() : AZ::EntityId();
-                WeaponNotificationBus::Broadcast(&WeaponNotificationBus::Events::OnWeaponImpact, GetEntity()->GetId(), hitTransform, hitEntityId);
-
                 if (handle.Exists())
                 if (handle.Exists())
                 {
                 {
                     // Presently set to 1 until we capture falloff range
                     // Presently set to 1 until we capture falloff range
@@ -156,16 +167,19 @@ namespace MultiplayerSample
                 }
                 }
             }
             }
 
 
-            if (shouldTerminate)
-            {
-                HideEnergyBall();
-            }
+            HideEnergyBall();
         }
         }
+
+        // Update our last sweep transform for the next time we check collision
+        m_lastSweepTransform = GetEntity()->GetTransform()->GetWorldTM();
     }
     }
 
 
     void EnergyBallComponentController::HideEnergyBall()
     void EnergyBallComponentController::HideEnergyBall()
     {
     {
-        RPC_BallExplosion(GetEntity()->GetTransform()->GetWorldTM().GetTranslation());
+        m_hitEvent.m_target = GetEntity()->GetTransform()->GetWorldTM().GetTranslation();
+        m_hitEvent.m_shooterNetEntityId = m_shooterNetEntityId;
+        m_hitEvent.m_projectileNetEntityId = GetNetEntityId();
+        RPC_BallExplosion(m_hitEvent);
 
 
         Physics::RigidBodyRequestBus::Event(GetEntityId(), &Physics::RigidBodyRequestBus::Events::DisablePhysics);
         Physics::RigidBodyRequestBus::Event(GetEntityId(), &Physics::RigidBodyRequestBus::Events::DisablePhysics);
         Physics::RigidBodyRequestBus::Event(GetEntityId(), &Physics::RigidBodyRequestBus::Events::SetLinearVelocity, AZ::Vector3::CreateZero());
         Physics::RigidBodyRequestBus::Event(GetEntityId(), &Physics::RigidBodyRequestBus::Events::SetLinearVelocity, AZ::Vector3::CreateZero());

+ 4 - 1
Gem/Code/Source/Components/Multiplayer/EnergyBallComponent.h

@@ -25,7 +25,7 @@ namespace MultiplayerSample
 
 
 #if AZ_TRAIT_CLIENT
 #if AZ_TRAIT_CLIENT
         void HandleRPC_BallLaunched(AzNetworking::IConnection* invokingConnection, const AZ::Vector3& location) override;
         void HandleRPC_BallLaunched(AzNetworking::IConnection* invokingConnection, const AZ::Vector3& location) override;
-        void HandleRPC_BallExplosion(AzNetworking::IConnection* invokingConnection, const AZ::Vector3& location) override;
+        void HandleRPC_BallExplosion(AzNetworking::IConnection* invokingConnection, const HitEvent& hitEvent) override;
 #endif
 #endif
 
 
     private:
     private:
@@ -54,8 +54,11 @@ namespace MultiplayerSample
         }, AZ::Name("EnergyBallCheckForCollisions") };
         }, AZ::Name("EnergyBallCheckForCollisions") };
 
 
         AZ::Vector3 m_direction = AZ::Vector3::CreateZero();
         AZ::Vector3 m_direction = AZ::Vector3::CreateZero();
+        AZ::Transform m_lastSweepTransform = AZ::Transform::CreateIdentity();
         Multiplayer::NetEntityId m_shooterNetEntityId = Multiplayer::InvalidNetEntityId;
         Multiplayer::NetEntityId m_shooterNetEntityId = Multiplayer::InvalidNetEntityId;
         NetEntityIdSet m_filteredNetEntityIds;
         NetEntityIdSet m_filteredNetEntityIds;
+
+        HitEvent m_hitEvent;
 #endif
 #endif
     };
     };
 }
 }