WasdPlayerMovementComponent.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  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/WasdPlayerMovementComponent.h>
  8. #include <Source/Components/CharacterComponent.h>
  9. #include <Source/Components/NetworkAnimationComponent.h>
  10. #include <Source/Components/SimplePlayerCameraComponent.h>
  11. #include <Multiplayer/Components/NetworkTransformComponent.h>
  12. #include <AzFramework/Visibility/EntityBoundsUnionBus.h>
  13. #include <AzFramework/Components/CameraBus.h>
  14. namespace MultiplayerSample
  15. {
  16. AZ_CVAR(float, cl_WasdStickAccel, 5.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "The linear acceleration to apply to WASD inputs to simulate analog stick controls");
  17. AZ_CVAR(float, cl_AimStickScaleZ, 0.1f, nullptr, AZ::ConsoleFunctorFlags::Null, "The scaling to apply to aim and view adjustments");
  18. AZ_CVAR(float, cl_AimStickScaleX, 0.05f, nullptr, AZ::ConsoleFunctorFlags::Null, "The scaling to apply to aim and view adjustments");
  19. WasdPlayerMovementComponentController::WasdPlayerMovementComponentController(WasdPlayerMovementComponent& parent)
  20. : WasdPlayerMovementComponentControllerBase(parent)
  21. {
  22. ;
  23. }
  24. void WasdPlayerMovementComponentController::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  25. {
  26. if (IsAutonomous())
  27. {
  28. StartingPointInput::InputEventNotificationBus::MultiHandler::BusConnect(MoveFwdEventId);
  29. StartingPointInput::InputEventNotificationBus::MultiHandler::BusConnect(MoveBackEventId);
  30. StartingPointInput::InputEventNotificationBus::MultiHandler::BusConnect(MoveLeftEventId);
  31. StartingPointInput::InputEventNotificationBus::MultiHandler::BusConnect(MoveRightEventId);
  32. StartingPointInput::InputEventNotificationBus::MultiHandler::BusConnect(SprintEventId);
  33. StartingPointInput::InputEventNotificationBus::MultiHandler::BusConnect(JumpEventId);
  34. StartingPointInput::InputEventNotificationBus::MultiHandler::BusConnect(CrouchEventId);
  35. StartingPointInput::InputEventNotificationBus::MultiHandler::BusConnect(LookLeftRightEventId);
  36. StartingPointInput::InputEventNotificationBus::MultiHandler::BusConnect(LookUpDownEventId);
  37. }
  38. }
  39. void WasdPlayerMovementComponentController::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  40. {
  41. if (IsAutonomous())
  42. {
  43. StartingPointInput::InputEventNotificationBus::MultiHandler::BusDisconnect(MoveFwdEventId);
  44. StartingPointInput::InputEventNotificationBus::MultiHandler::BusDisconnect(MoveBackEventId);
  45. StartingPointInput::InputEventNotificationBus::MultiHandler::BusDisconnect(MoveLeftEventId);
  46. StartingPointInput::InputEventNotificationBus::MultiHandler::BusDisconnect(MoveRightEventId);
  47. StartingPointInput::InputEventNotificationBus::MultiHandler::BusDisconnect(SprintEventId);
  48. StartingPointInput::InputEventNotificationBus::MultiHandler::BusDisconnect(JumpEventId);
  49. StartingPointInput::InputEventNotificationBus::MultiHandler::BusDisconnect(CrouchEventId);
  50. StartingPointInput::InputEventNotificationBus::MultiHandler::BusDisconnect(LookLeftRightEventId);
  51. StartingPointInput::InputEventNotificationBus::MultiHandler::BusDisconnect(LookUpDownEventId);
  52. }
  53. }
  54. void WasdPlayerMovementComponentController::CreateInput(Multiplayer::NetworkInput& input, float deltaTime)
  55. {
  56. // Movement axis
  57. // Since we're on a keyboard, this adds a touch of an acceleration curve to the keyboard inputs
  58. // This is so that tapping the keyboard moves the virtual stick less than just holding it down
  59. m_forwardWeight = std::min<float>(m_forwardDown ? m_forwardWeight + cl_WasdStickAccel * deltaTime : 0.0f, 1.0f);
  60. m_leftWeight = std::min<float>(m_leftDown ? m_leftWeight + cl_WasdStickAccel * deltaTime : 0.0f, 1.0f);
  61. m_backwardWeight = std::min<float>(m_backwardDown ? m_backwardWeight + cl_WasdStickAccel * deltaTime : 0.0f, 1.0f);
  62. m_rightWeight = std::min<float>(m_rightDown ? m_rightWeight + cl_WasdStickAccel * deltaTime : 0.0f, 1.0f);
  63. // inputs for your own component always exist
  64. WasdPlayerMovementComponentNetworkInput* wasdInput = input.FindComponentInput<WasdPlayerMovementComponentNetworkInput>();
  65. wasdInput->m_forwardAxis = StickAxis(m_forwardWeight - m_backwardWeight);
  66. wasdInput->m_strafeAxis = StickAxis(m_leftWeight - m_rightWeight);
  67. // View Axis
  68. wasdInput->m_viewYaw = MouseAxis(m_viewYaw);
  69. wasdInput->m_viewPitch = MouseAxis(m_viewPitch);
  70. // Strafe input
  71. wasdInput->m_sprint = m_sprinting;
  72. wasdInput->m_jump = m_jumping;
  73. wasdInput->m_crouch = m_crouching;
  74. // Just a note for anyone who is super confused by this, ResetCount is a predictable network property, it gets set on the client through correction packets
  75. wasdInput->m_resetCount = GetNetworkTransformComponentController()->GetResetCount();
  76. }
  77. void WasdPlayerMovementComponentController::ProcessInput(Multiplayer::NetworkInput& input, float deltaTime)
  78. {
  79. // If the input reset count doesn't match the state's reset count it can mean two things:
  80. // 1) On the server: we were reset and we are now receiving inputs from the client for an old reset count
  81. // 2) On the client: we were reset and we are replaying old inputs after being corrected
  82. // In both cases we don't want to process these inputs
  83. WasdPlayerMovementComponentNetworkInput* wasdInput = input.FindComponentInput<WasdPlayerMovementComponentNetworkInput>();
  84. if (wasdInput->m_resetCount != GetNetworkTransformComponentController()->GetResetCount())
  85. {
  86. return;
  87. }
  88. GetNetworkAnimationComponentController()->ModifyActiveAnimStates().SetBit(aznumeric_cast<AZStd::size_t>(CharacterAnimState::Sprinting), wasdInput->m_sprint);
  89. GetNetworkAnimationComponentController()->ModifyActiveAnimStates().SetBit(aznumeric_cast<AZStd::size_t>(CharacterAnimState::Jumping), wasdInput->m_jump);
  90. GetNetworkAnimationComponentController()->ModifyActiveAnimStates().SetBit(aznumeric_cast<AZStd::size_t>(CharacterAnimState::Crouching), wasdInput->m_crouch);
  91. // Update orientation
  92. AZ::Vector3 aimAngles = GetSimplePlayerCameraComponentController()->GetAimAngles();
  93. aimAngles.SetZ(NormalizeHeading(aimAngles.GetZ() - wasdInput->m_viewYaw * cl_AimStickScaleZ));
  94. aimAngles.SetX(NormalizeHeading(aimAngles.GetX() - wasdInput->m_viewPitch * cl_AimStickScaleX));
  95. aimAngles.SetX(NormalizeHeading(AZ::GetClamp(aimAngles.GetX(), -AZ::Constants::QuarterPi * 0.5f, AZ::Constants::QuarterPi * 0.5f)));
  96. GetSimplePlayerCameraComponentController()->SetAimAngles(aimAngles);
  97. const AZ::Quaternion newOrientation = AZ::Quaternion::CreateRotationZ(aimAngles.GetZ());
  98. GetEntity()->GetTransform()->SetLocalRotationQuaternion(newOrientation);
  99. // Update velocity
  100. UpdateVelocity(*wasdInput);
  101. // Ensure any entities that we might interact with are properly synchronized to their rewind state
  102. if (IsAuthority())
  103. {
  104. const AZ::Aabb entityStartBounds = AZ::Interface<AzFramework::IEntityBoundsUnion>::Get()->GetEntityLocalBoundsUnion(GetEntity()->GetId());
  105. const AZ::Aabb entityFinalBounds = entityStartBounds.GetTranslated(GetVelocity());
  106. AZ::Aabb entitySweptBounds = entityStartBounds;
  107. entitySweptBounds.AddAabb(entityFinalBounds);
  108. Multiplayer::GetNetworkTime()->SyncEntitiesToRewindState(entitySweptBounds);
  109. }
  110. GetCharacterComponentController()->TryMoveWithVelocity(GetVelocity(), deltaTime);
  111. }
  112. void WasdPlayerMovementComponentController::UpdateVelocity(const WasdPlayerMovementComponentNetworkInput& wasdInput)
  113. {
  114. const float fwdBack = wasdInput.m_forwardAxis;
  115. const float leftRight = wasdInput.m_strafeAxis;
  116. float speed = 0.0f;
  117. if (wasdInput.m_crouch)
  118. {
  119. speed = GetCharacterComponentController()->GetCrouchSpeed();
  120. }
  121. else if (fwdBack < 0.0f)
  122. {
  123. speed = GetCharacterComponentController()->GetReverseSpeed();
  124. }
  125. else
  126. {
  127. if (wasdInput.m_sprint)
  128. {
  129. speed = GetCharacterComponentController()->GetSprintSpeed();
  130. }
  131. else
  132. {
  133. speed = GetCharacterComponentController()->GetWalkSpeed();
  134. }
  135. }
  136. // Not moving?
  137. if (fwdBack == 0.0f && leftRight == 0.0f)
  138. {
  139. SetVelocity(AZ::Vector3::CreateZero());
  140. }
  141. else
  142. {
  143. const float stickInputAngle = AZ::Atan2(leftRight, fwdBack);
  144. const float currentHeading = GetNetworkTransformComponentController()->GetRotation().GetEulerRadians().GetZ();
  145. const float targetHeading = NormalizeHeading(currentHeading + stickInputAngle); // Update current heading with stick input angles
  146. const AZ::Vector3 fwd = AZ::Vector3::CreateAxisY();
  147. SetVelocity(AZ::Quaternion::CreateRotationZ(targetHeading).TransformVector(fwd) * speed);
  148. }
  149. }
  150. float WasdPlayerMovementComponentController::NormalizeHeading(float heading) const
  151. {
  152. // Ensure a_Heading in range [-pi, +pi]
  153. if (heading > AZ::Constants::Pi)
  154. {
  155. return static_cast<float>(heading - AZ::Constants::TwoPi);
  156. }
  157. else if (heading < -AZ::Constants::Pi)
  158. {
  159. return static_cast<float>(heading + AZ::Constants::TwoPi);
  160. }
  161. return heading;
  162. }
  163. void WasdPlayerMovementComponentController::OnPressed(float value)
  164. {
  165. const StartingPointInput::InputEventNotificationId* inputId = StartingPointInput::InputEventNotificationBus::GetCurrentBusId();
  166. if (inputId == nullptr)
  167. {
  168. return;
  169. }
  170. else if (*inputId == MoveFwdEventId)
  171. {
  172. m_forwardDown = true;
  173. }
  174. else if (*inputId == MoveBackEventId)
  175. {
  176. m_backwardDown = true;
  177. }
  178. else if (*inputId == MoveLeftEventId)
  179. {
  180. m_leftDown = true;
  181. }
  182. else if (*inputId == MoveRightEventId)
  183. {
  184. m_rightDown = true;
  185. }
  186. else if (*inputId == SprintEventId)
  187. {
  188. m_sprinting = true;
  189. }
  190. else if (*inputId == JumpEventId)
  191. {
  192. m_jumping = true;
  193. }
  194. else if (*inputId == CrouchEventId)
  195. {
  196. m_crouching = true;
  197. }
  198. else if (*inputId == LookLeftRightEventId)
  199. {
  200. m_viewYaw = value;
  201. }
  202. else if (*inputId == LookUpDownEventId)
  203. {
  204. m_viewPitch = value;
  205. }
  206. }
  207. void WasdPlayerMovementComponentController::OnReleased(float value)
  208. {
  209. const StartingPointInput::InputEventNotificationId* inputId = StartingPointInput::InputEventNotificationBus::GetCurrentBusId();
  210. if (inputId == nullptr)
  211. {
  212. return;
  213. }
  214. else if (*inputId == MoveFwdEventId)
  215. {
  216. m_forwardDown = false;
  217. }
  218. else if (*inputId == MoveBackEventId)
  219. {
  220. m_backwardDown = false;
  221. }
  222. else if (*inputId == MoveLeftEventId)
  223. {
  224. m_leftDown = false;
  225. }
  226. else if (*inputId == MoveRightEventId)
  227. {
  228. m_rightDown = false;
  229. }
  230. else if (*inputId == SprintEventId)
  231. {
  232. m_sprinting = false;
  233. }
  234. else if (*inputId == JumpEventId)
  235. {
  236. m_jumping = false;
  237. }
  238. else if (*inputId == CrouchEventId)
  239. {
  240. m_crouching = false;
  241. }
  242. else if (*inputId == LookLeftRightEventId)
  243. {
  244. m_viewYaw = value;
  245. }
  246. else if (*inputId == LookUpDownEventId)
  247. {
  248. m_viewPitch = value;
  249. }
  250. }
  251. void WasdPlayerMovementComponentController::OnHeld(float value)
  252. {
  253. const StartingPointInput::InputEventNotificationId* inputId = StartingPointInput::InputEventNotificationBus::GetCurrentBusId();
  254. if (inputId == nullptr)
  255. {
  256. return;
  257. }
  258. else if (*inputId == LookLeftRightEventId)
  259. {
  260. m_viewYaw = value;
  261. }
  262. else if (*inputId == LookUpDownEventId)
  263. {
  264. m_viewPitch = value;
  265. }
  266. }
  267. }