WeaponGathers.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  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/Weapons/WeaponGathers.h>
  8. #include <Multiplayer/NetworkTime/INetworkTime.h>
  9. #include <AzFramework/Physics/PhysicsScene.h>
  10. #include <AzCore/Component/Component.h>
  11. #include <AzCore/Console/ILogger.h>
  12. #include <Source/Weapons/SceneQuery.h>
  13. #if AZ_TRAIT_CLIENT
  14. #include <DebugDraw/DebugDrawBus.h>
  15. #endif
  16. namespace ${SanitizedCppName}
  17. {
  18. AZ_CVAR(uint32_t, bg_MultitraceNumTraceSegments, 3, nullptr, AZ::ConsoleFunctorFlags::Null, "The number of segments to use when performing multitrace casts");
  19. AZ_CVAR(bool, bg_DrawPhysicsRaycasts, true, nullptr, AZ::ConsoleFunctorFlags::Null, "If enabled, will debug draw physics raycasts");
  20. IntersectFilter::IntersectFilter
  21. (
  22. const AZ::Transform& initialPose,
  23. const AZ::Vector3& sweep,
  24. AzPhysics::SceneQuery::QueryType queryType,
  25. HitMultiple intersectMultiple,
  26. const AzPhysics::CollisionGroup& collisionGroup,
  27. const NetEntityIdSet& filteredNetEntityIds,
  28. const Physics::ShapeConfiguration* shapeConfiguration
  29. )
  30. : m_initialPose(initialPose)
  31. , m_sweep(sweep)
  32. , m_queryType(queryType)
  33. , m_intersectMultiple(intersectMultiple)
  34. , m_collisionGroup(collisionGroup)
  35. , m_filteredNetEntityIds(filteredNetEntityIds)
  36. , m_shapeConfiguration(shapeConfiguration)
  37. {
  38. Multiplayer::INetworkTime* networkTime = Multiplayer::GetNetworkTime();
  39. if (networkTime->IsTimeRewound())
  40. {
  41. m_rewindFrameId = networkTime->GetHostFrameId();
  42. }
  43. }
  44. bool GatherEntities
  45. (
  46. const GatherParams& gatherParams,
  47. const ActivateEvent& eventData,
  48. const NetEntityIdSet& filteredNetEntityIds,
  49. IntersectResults& outResults
  50. )
  51. {
  52. const AZ::Transform& startTransform = eventData.m_initialTransform;
  53. const AZ::Vector3 sweep = eventData.m_targetPosition - startTransform.GetTranslation();
  54. const HitMultiple hitMultiple = gatherParams.m_multiHit ? HitMultiple::Yes : HitMultiple::No;
  55. const GatherShape& intersectShape = gatherParams.m_gatherShape;
  56. AzPhysics::CollisionGroup collisionGroup = AzPhysics::GetCollisionGroupById(gatherParams.m_collisionGroupId);
  57. IntersectFilter filter(startTransform, sweep, AzPhysics::SceneQuery::QueryType::StaticAndDynamic, hitMultiple,
  58. collisionGroup, filteredNetEntityIds, gatherParams.GetCurrentShapeConfiguration());
  59. SceneQuery::WorldIntersect(intersectShape, filter, outResults);
  60. #if AZ_TRAIT_CLIENT
  61. if (bg_DrawPhysicsRaycasts)
  62. {
  63. DebugDraw::DebugDrawRequestBus::Broadcast
  64. (
  65. &DebugDraw::DebugDrawRequests::DrawLineLocationToLocation,
  66. eventData.m_initialTransform.GetTranslation(),
  67. eventData.m_targetPosition,
  68. AZ::Colors::Red,
  69. 10.0f
  70. );
  71. }
  72. #endif
  73. return true;
  74. }
  75. ShotResult GatherEntitiesMultisegment
  76. (
  77. const GatherParams& gatherParams,
  78. const NetEntityIdSet& filteredNetEntityIds,
  79. float deltaTime,
  80. ActiveShot& inOutActiveShot,
  81. IntersectResults& outResults
  82. )
  83. {
  84. // This only works when our cast is not instantaneous (it requires some positive, non-zero travel speed)
  85. AZ_Assert(gatherParams.m_travelSpeed > 0.0f, "GatherEntitiesMultiSegment called with an invalid travel speed! This will fail, use the non-segmented gather path instead.");
  86. ShotResult result = ShotResult::DoNotTerminate;
  87. const AZ::Transform& startTransform = inOutActiveShot.m_initialTransform;
  88. const AZ::Vector3 sweep = (inOutActiveShot.m_targetPosition - startTransform.GetTranslation()).GetNormalized();
  89. // World gravity for our current location (making the currently safe assumption that it's constant over the duration of our trace)
  90. AzPhysics::SceneInterface* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get();
  91. AzPhysics::SceneHandle sceneHandle = sceneInterface->GetSceneHandle(AzPhysics::DefaultPhysicsSceneName);
  92. const AZ::Vector3& gravity = gatherParams.m_bulletDrop ? sceneInterface->GetGravity(sceneHandle) : AZ::Vector3::CreateZero();
  93. const float segmentTickSize = deltaTime / bg_MultitraceNumTraceSegments; // Duration in seconds of each cast segment
  94. const AZ::Vector3 segmentStepOffset = sweep * gatherParams.m_travelSpeed; // Displacement (disregarding gravity) of our bullet over one second
  95. const float maxTravelDistanceSq = gatherParams.m_castDistance * gatherParams.m_castDistance;
  96. // We're not doing any lift or drift computations due to the magnus effects a bullet is subject to
  97. // Any such adjustments, estimates for how fast the bullet is spinning due to muzzle exit velocity and the rifling of the gun, air density, temperature, etc...
  98. const HitMultiple hitMultiple = gatherParams.m_multiHit ? HitMultiple::Yes : HitMultiple::No;
  99. const AzPhysics::CollisionGroup collisionGroup = AzPhysics::GetCollisionGroupById(gatherParams.m_collisionGroupId);
  100. float currSegmentStartTime = inOutActiveShot.m_lifetimeSeconds;
  101. AZ::Vector3 currSegmentPosition = inOutActiveShot.m_initialTransform.GetTranslation() + (segmentStepOffset * currSegmentStartTime) + (gravity * 0.5f * currSegmentStartTime * currSegmentStartTime);
  102. for (uint32_t segment = 0; segment < bg_MultitraceNumTraceSegments; ++segment)
  103. {
  104. float nextSegmentStartTime = currSegmentStartTime + segmentTickSize;
  105. AZ::Vector3 travelDistance = (segmentStepOffset * nextSegmentStartTime); // Total distance our shot has traveled as of this cast, ignoring arc-length due to gravity
  106. AZ::Vector3 nextSegmentPosition = inOutActiveShot.m_initialTransform.GetTranslation() + travelDistance + (gravity * 0.5f * nextSegmentStartTime * nextSegmentStartTime);
  107. const AZ::Transform currSegTransform = AZ::Transform::CreateFromQuaternionAndTranslation(inOutActiveShot.m_initialTransform.GetRotation(), currSegmentPosition);
  108. const AZ::Vector3 segSweep = nextSegmentPosition - currSegmentPosition;
  109. IntersectFilter filter(currSegTransform, segSweep, AzPhysics::SceneQuery::QueryType::StaticAndDynamic,
  110. hitMultiple, collisionGroup, filteredNetEntityIds, gatherParams.GetCurrentShapeConfiguration());
  111. SceneQuery::WorldIntersect(gatherParams.m_gatherShape, filter, outResults);
  112. #if AZ_TRAIT_CLIENT
  113. if (bg_DrawPhysicsRaycasts)
  114. {
  115. DebugDraw::DebugDrawRequestBus::Broadcast
  116. (
  117. &DebugDraw::DebugDrawRequests::DrawLineLocationToLocation,
  118. currSegmentPosition,
  119. nextSegmentPosition,
  120. segment % 2 == 0 ? AZ::Colors::Red : AZ::Colors::Yellow,
  121. 10.0f
  122. );
  123. }
  124. #endif
  125. // Terminate the loop if we hit something
  126. if (((outResults.size() > 0) && !gatherParams.m_multiHit) || (travelDistance.GetLengthSq() > maxTravelDistanceSq))
  127. {
  128. result = ShotResult::ShouldTerminate;
  129. break;
  130. }
  131. currSegmentStartTime = nextSegmentStartTime;
  132. currSegmentPosition = nextSegmentPosition;
  133. }
  134. inOutActiveShot.m_lifetimeSeconds = LifetimeSec(inOutActiveShot.m_lifetimeSeconds + deltaTime);
  135. return result;
  136. }
  137. }