On part1 of this series, we got our character moving based on the keyboard input. This tutorial will be focused on getting it to work with mouse interaction.
Mouse requires more work because we need to rotate the player entity for left right, and the camera entity on up and down. If you image you are standing, you can rotate your body to turn different directions, but you just rotate your head to look up and down.
Capturing the Mouse Rotation
First lets add some stuff to our class definition’s private section (naughty?)
TutCharacterComp.h
void PerformRotation(const AzFramework::InputChannel& inputChannel); void TrackMouseMovement(const AzFramework::InputChannel::PositionData2D* position_data); AZ::Vector2 m_lastMousePosition{.5f, .5f}; AZ::Vector2 m_mouseChangeAggregate{0, 0}; float RotationSpeed = 5.f;
PerformRotation
and TrackMouseMovements
are helper functions which will be explained later.
m_lastMousePosition
is the last position of the mouse normalized (from 0 to 1).
m_mouseChangeAggregate
is the hard one to understand. It’s basically the aggregated amount of change that you have moved your mouse. It’s used to derive rotation.
RotationSpeed
will be another value that we can define in the editor but will default to 5.
In the source file, we first need to update our reflection to include the RotationSpeed
.
TutCharacterComp.cpp
serializationContext->Class<TutorialSeriesCharacterComponent>() ->Version(1) ->Field("Movement scale", &TutorialSeriesCharacterComponent::MovementScale) ->Field("Rotation Speed", &TutorialSeriesCharacterComponent::RotationSpeed); if (auto editContext = serializationContext->GetEditContext()) { editContext->Class<TutorialSeriesCharacterComponent>("TutorialSeriesCharacterComponent", "Main controller component") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "TutorialSeries") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game")) ->DataElement(nullptr, &TutorialSeriesCharacterComponent::MovementScale, "Movement scale", "How fast the character moves") ->DataElement(nullptr, &TutorialSeriesCharacterComponent::RotationSpeed, "Rotation Speed", "The speed multiplier to apply to mouse rotation"); }
Next we need to add the handling of the input to track their mouse movements to use for rotation later.
TutCharacterComp.cpp
void TutorialSeriesCharacterComponent::OnMouseEvent(const InputChannel &inputChannel) { auto input_type = inputChannel.GetInputChannelId(); if (input_type == InputDeviceMouse::SystemCursorPosition) { PerformRotation(inputChannel); } } void TutorialSeriesCharacterComponent::PerformRotation(const InputChannel &inputChannel) { auto position_data = inputChannel.GetCustomData<InputChannel::PositionData2D>(); TrackMouseMovement(position_data); } void TutorialSeriesCharacterComponent::TrackMouseMovement(const InputChannel::PositionData2D *position_data) { auto deltaMousePosition = m_lastMousePosition - position_data->m_normalizedPosition; m_lastMousePosition = position_data->m_normalizedPosition; m_mouseChangeAggregate += deltaMousePosition; }
Lets discuss the line, auto position_data = inputChannel.GetCustomData();
The derived type of this InputChannel for mouse position is InputChannelDeltaWithSharedPosition2D
. The main special thing about this derived type is that it keeps track of the delta in movement, and it has a Position vector that comes with it. To access that position vector, it uses the GetCustomData
function provided on the InputChannel interface.
TrackMouseMovement
gets the delta of mouse movement, and adds it to our aggregate which will determine our total rotation later.
So now we are tracking the total aggregate amount they have moved their mouse around. Compile and run it to make sure nothing breaks. Nothing new will happen of course until we actually rotate some entities.
Rotating the Player (and Therefore the Camera)
Since we made the Player entity the parent of the Camera entity, if we rotate the Player, it will rotate the camera automagically.
To do this, we have to do some magic in the OnTick
.
TutCharacterComp.cpp
void TutorialSeriesCharacterComponent::OnTick(float deltaTime, AZ::ScriptTimePoint time) { AZ::Transform entityTransform; EBUS_EVENT_ID_RESULT(entityTransform, GetEntityId(), AZ::TransformBus, GetWorldTM); entityTransform.SetRotationPartFromQuaternion(GetCurrentOrientation()); EBUS_EVENT_ID(GetEntityId(), AZ::TransformBus, SetWorldTM, entityTransform); auto desiredVelocity = AZ::Vector3::CreateZero(); if (movingForward || movingBack || strafingLeft || strafingRight) { HandleForwardBackwardMovement(desiredVelocity); HandleStrafing(desiredVelocity); } // Apply relative translation to the character via physics. EBUS_EVENT_ID(GetEntityId(), LmbrCentral::CryCharacterPhysicsRequestBus, RequestVelocity, desiredVelocity, 0); } const AZ::Quaternion TutorialSeriesCharacterComponent::GetCurrentOrientation() { auto z_rotation = AZ::Quaternion::CreateRotationZ(m_mouseChangeAggregate.GetX() * RotationSpeed); return z_rotation; }
We added line 5 and 6 and the new GetCurrentOrientation
function (be sure to add it to the header.)
For now we are only using the left/right value (x value) of the mouse position. We simply grab this entity’s transform, apply the rotation, and set the entity’s transform.
Compile and run! You should now be able to rotate your character with your mouse.
Unfortunately there are a slew of problems.
* You can’t determine which direction you move.
* The mouse eventually hits the edge of the window and you can’t rotate anymore.
* Obviously, no looking up and down
Check out the next part of this series where we start to fix these issues.
3 thoughts on “Starting with Lumberyard Input – Part 2”