NetworkSimplePlayerCameraComponent.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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 <AzCore/Component/ComponentApplicationBus.h>
  8. #include <Source/Components/NetworkAiComponent.h>
  9. #include <Source/Components/NetworkSimplePlayerCameraComponent.h>
  10. #include <AzCore/Component/TransformBus.h>
  11. #include <AzFramework/Components/CameraBus.h>
  12. #include <AzFramework/Physics/PhysicsScene.h>
  13. #include <AzFramework/Physics/Common/PhysicsSceneQueries.h>
  14. #include <Multiplayer/IMultiplayer.h>
  15. #if AZ_TRAIT_CLIENT
  16. # include <DebugDraw/DebugDrawBus.h>
  17. #endif
  18. namespace MultiplayerSample
  19. {
  20. AZ_CVAR(AZ::Vector3, cl_cameraOffset, AZ::Vector3(0.5f, 0.f, 1.5f), nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Offset to use for the player camera");
  21. AZ_CVAR(AZ::Vector3, cl_cameraColliderSize, AZ::Vector3(0.5f, 0.1f, 0.3f), nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Temporary collider size for player camera");
  22. AZ_CVAR(bool, cl_drawCameraCollider, false, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Draw the camera collider");
  23. AZ_CVAR(bool, cl_cameraBlendingEnabled, false, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "When active, blends the camera aim angles.");
  24. AZ_CVAR(float, cl_cameraFovSprintModifier, 10.0f, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Controls how much to adjust camera FOV when sprinting");
  25. AZ_CVAR(float, cl_cameraZoomSprintModifier, -0.3f, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Controls how much to adjust camera zoom when sprinting");
  26. AZ_CVAR(float, cl_cameraSprintBlendRate, 0.25f, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The rate at which to blend into sprint camera");
  27. NetworkSimplePlayerCameraComponentController::NetworkSimplePlayerCameraComponentController(NetworkSimplePlayerCameraComponent& parent)
  28. : NetworkSimplePlayerCameraComponentControllerBase(parent)
  29. {
  30. ;
  31. }
  32. void NetworkSimplePlayerCameraComponentController::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  33. {
  34. m_physicsSceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get();
  35. if (m_physicsSceneInterface)
  36. {
  37. m_physicsSceneHandle = m_physicsSceneInterface->GetSceneHandle(AzPhysics::DefaultPhysicsSceneName);
  38. }
  39. // Synchronize aim angles with initial transform
  40. AZ::Vector3& aimAngles = ModifyAimAngles();
  41. aimAngles.SetZ(GetEntity()->GetTransform()->GetLocalRotation().GetZ());
  42. SetSyncAimImmediate(true);
  43. m_springArmDist = GetMaxFollowDistance();
  44. if (IsNetEntityRoleAutonomous())
  45. {
  46. m_aiEnabled = FindComponent<NetworkAiComponent>()->GetEnabled();
  47. if (!m_aiEnabled)
  48. {
  49. AZ::EntityId activeCameraId;
  50. Camera::CameraSystemRequestBus::BroadcastResult(activeCameraId, &Camera::CameraSystemRequestBus::Events::GetActiveCamera);
  51. m_activeCameraEntity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(activeCameraId);
  52. Camera::CameraRequestBus::EventResult(m_originalFov, m_activeCameraEntity->GetId(), &Camera::CameraRequestBus::Events::GetFovDegrees);
  53. m_currentFov = m_originalFov;
  54. }
  55. }
  56. AZ::TickBus::Handler::BusConnect();
  57. }
  58. void NetworkSimplePlayerCameraComponentController::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  59. {
  60. if(AZ::TickBus::Handler::BusIsConnected())
  61. {
  62. AZ::TickBus::Handler::BusDisconnect();
  63. }
  64. }
  65. float NetworkSimplePlayerCameraComponentController::GetCameraYaw() const
  66. {
  67. return GetAimAngles().GetZ();
  68. }
  69. float NetworkSimplePlayerCameraComponentController::GetCameraPitch() const
  70. {
  71. return GetAimAngles().GetX();
  72. }
  73. float NetworkSimplePlayerCameraComponentController::GetCameraRoll() const
  74. {
  75. return GetAimAngles().GetY();
  76. }
  77. float NetworkSimplePlayerCameraComponentController::GetCameraYawPrevious() const
  78. {
  79. return GetAimAnglesPrevious().GetZ();
  80. }
  81. float NetworkSimplePlayerCameraComponentController::GetCameraPitchPrevious() const
  82. {
  83. return GetAimAnglesPrevious().GetX();
  84. }
  85. float NetworkSimplePlayerCameraComponentController::GetCameraRollPrevious() const
  86. {
  87. return GetAimAnglesPrevious().GetY();
  88. }
  89. AZ::Transform NetworkSimplePlayerCameraComponentController::GetCameraTransform(bool collisionEnabled) const
  90. {
  91. // exclude roll from any rotation calculations
  92. const AZ::Quaternion targetYaw = AZ::Quaternion::CreateRotationZ(GetCameraYaw());
  93. const AZ::Quaternion targetRotation = targetYaw * AZ::Quaternion::CreateRotationX(GetCameraPitch());
  94. AZ::Quaternion aimRotation = targetRotation;
  95. if (IsNetEntityRoleAutonomous() && cl_cameraBlendingEnabled)
  96. {
  97. const float blendFactor = Multiplayer::GetMultiplayer()->GetCurrentBlendFactor();
  98. if (!GetSyncAimImmediate() && !AZ::IsClose(blendFactor, 1.0f))
  99. {
  100. const AZ::Quaternion prevRotation = AZ::Quaternion::CreateRotationZ(GetCameraYawPrevious()) * AZ::Quaternion::CreateRotationX(GetCameraPitchPrevious());
  101. if (!prevRotation.IsClose(targetRotation))
  102. {
  103. aimRotation = prevRotation.Slerp(targetRotation, blendFactor).GetNormalized();
  104. }
  105. }
  106. }
  107. const AZ::Vector3 targetTranslation = GetEntity()->GetTransform()->GetWorldTM().GetTranslation();
  108. const AZ::Vector3 cameraPivotOffset = targetYaw.TransformVector(cl_cameraOffset);
  109. if (collisionEnabled)
  110. {
  111. AZ::Transform cameraTransform = AZ::Transform::CreateFromQuaternionAndTranslation(aimRotation, targetTranslation + cameraPivotOffset);
  112. ApplySpringArm(cameraTransform);
  113. return cameraTransform;
  114. }
  115. else
  116. {
  117. const AZ::Vector3 cameraOffset = cameraPivotOffset + aimRotation.TransformVector(AZ::Vector3(0.f, GetMaxFollowDistance(), 0.f));
  118. return AZ::Transform::CreateFromQuaternionAndTranslation(aimRotation, targetTranslation + cameraOffset);
  119. }
  120. }
  121. void NetworkSimplePlayerCameraComponentController::SetSprintMode(bool sprintMode)
  122. {
  123. m_sprinting = sprintMode;
  124. }
  125. void NetworkSimplePlayerCameraComponentController::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
  126. {
  127. if (m_activeCameraEntity != nullptr && m_activeCameraEntity->GetState() == AZ::Entity::State::Active)
  128. {
  129. const float targetZoom = m_sprinting ? cl_cameraZoomSprintModifier : 0.0f;
  130. m_currentZoom += (targetZoom - m_currentZoom) * cl_cameraSprintBlendRate;
  131. const float targetFov = m_sprinting ? m_originalFov + cl_cameraFovSprintModifier : m_originalFov;
  132. m_currentFov += (targetFov - m_currentFov) * cl_cameraSprintBlendRate;
  133. Camera::CameraRequestBus::Event(m_activeCameraEntity->GetId(), &Camera::CameraRequestBus::Events::SetFovDegrees, m_currentFov);
  134. const AZ::Transform& transform = GetCameraTransform(GetEnableCollision());
  135. m_activeCameraEntity->GetTransform()->SetWorldTM(transform);
  136. }
  137. if (GetSyncAimImmediate())
  138. {
  139. SetSyncAimImmediate(false);
  140. if (!m_activeCameraEntity)
  141. {
  142. // the server no longer needs to tick after the initial sync
  143. AZ::TickBus::Handler::BusDisconnect();
  144. }
  145. }
  146. }
  147. void NetworkSimplePlayerCameraComponentController::ApplySpringArm(AZ::Transform& inOutTransform) const
  148. {
  149. // TODO replace cl_cameraColliderSize with dynamic box based on the camera near plane world dimensions
  150. const AZ::EntityId ignoreEntityId = GetEntityId();
  151. const AZ::Vector3 cameraPivot = inOutTransform.GetTranslation();
  152. const AZ::Vector3 direction = -inOutTransform.GetBasisY();
  153. const float maxDistance = GetMaxFollowDistance();
  154. float distance = maxDistance + m_currentZoom;
  155. // trace from the target to the camera position
  156. auto request = AzPhysics::ShapeCastRequestHelpers::CreateBoxCastRequest(
  157. cl_cameraColliderSize, inOutTransform, direction, maxDistance,
  158. AzPhysics::SceneQuery::QueryType::StaticAndDynamic,
  159. AzPhysics::CollisionGroup::All,
  160. [ignoreEntityId](const AzPhysics::SimulatedBody* body, [[maybe_unused]] const Physics::Shape* shape)
  161. {
  162. return body->GetEntityId() != ignoreEntityId ? AzPhysics::SceneQuery::QueryHitType::Block
  163. : AzPhysics::SceneQuery::QueryHitType::None;
  164. });
  165. AzPhysics::SceneQueryHits result = m_physicsSceneInterface->QueryScene(m_physicsSceneHandle, &request);
  166. if (result && !result.m_hits.empty())
  167. {
  168. // include the collision offset so we are not intersecting the surface
  169. distance = result.m_hits[0].m_distance - GetCollisionOffset();
  170. distance = AZ::GetClamp(distance, GetMinFollowDistance(), maxDistance);
  171. }
  172. m_springArmDist = (m_springArmDist + distance) * 0.5f;
  173. inOutTransform.SetTranslation(cameraPivot + direction * m_springArmDist);
  174. #if AZ_TRAIT_CLIENT
  175. if (cl_drawCameraCollider && distance < maxDistance)
  176. {
  177. if (auto debugDraw = DebugDraw::DebugDrawRequestBus::FindFirstHandler(); debugDraw != nullptr)
  178. {
  179. const AZ::Vector3 colliderSize = cl_cameraColliderSize;
  180. debugDraw->DrawObb(
  181. AZ::Obb::CreateFromPositionRotationAndHalfLengths(
  182. inOutTransform.GetTranslation(),
  183. inOutTransform.GetRotation(),
  184. colliderSize * 0.5f),
  185. AZ::Color(1.f,0.f,0.f,0.1f),
  186. 1.f);
  187. }
  188. inOutTransform.SetTranslation(cameraPivot + direction * maxDistance);
  189. }
  190. #endif
  191. }
  192. int NetworkSimplePlayerCameraComponentController::GetTickOrder()
  193. {
  194. return AZ::TICK_PRE_RENDER;
  195. }
  196. }