Introduction
This article is meant to help you add some basic movement and animations to the previous basic mounting tutorials. This tutorial's goal is to show you where the movement and animation logic goes. The methods used by this tutorial are simple and basic meaning they will not be ideal for an actual game. However the finished project contains an advanced animation demo you can look at to see how better systems can be created.
In this tutorial we will be cheating a bit because we will only be dealing with the horse as a mount so our system will always assume that seat ID 0 is the driver seat and seat id 1 is the passenger. Your game may have very different types of mounts, some with several seats and some with a few seats. The finished project demonstrates how to handle mounts with various different numbers of seats as well as different mounting, dismounting, and seat changing animations.
Table of Contents
1.0 Project Tour
Lets begin by taking a brief look at where the demo for this project will be within the Finished Demo Project so you can take a look at it and see what has been changed.
1.1 Demo Location
In the full Demo you can find all the files associated with this tutorial in the "AnimationDemo" directory under the "MountingExamples" folder
You can simply follow along where you left off during the previous setup tutorial. The "AnimationDemo" has subclassed the Mounting Character and the Horse so that all new additions and changes are easy to identify.
1.2 Animations
I highly suggest you download and use the starting project for these tutorials because it comes with the animations already setup and ready to use. In the "Mannequin/Animations" folder I have added several new animations and montages.
For this tutorial we will be leveraging the following Animations.
- AM_Horse_MountLeftSide
- AM_Horse_MountRightSide
- AM_Horse_DismountLeftSide
- AM_Horse_DismountRightSide
- AM_Horse_MoveToFrontSeat
- AM_Horse_MoveToBackSeat
These animations where hand made, so they are not production level animations that should be used in your game, they are programmer art. Having a decent animator will greatly improve the fidelity of the mounting, dismounting, and seat changing process. However, these animations are simply a proof of concept to show that they work and the mounting system is capable of handling such a setup.
1.2.1 Mounting Montage
Open up one of the Mounting Montages so you can take a peek inside. The image below shows the "AM_Horse_MountLeftSide"
The most important thing here is the use of the "MountingFinished" Anim Notify. This is used in animations to call the interface function "On Mounting Pawn Finished" on the character which finalizes the mounting of the vehicle or other Pawn. This function is required to be called somehow by your system if you are using animations. The PNMS plugin comes with this Anim Notify already, so it is advised to leverage it.
1.2.2 Dismounting Montage
Open up one of the Dismounting Montages so you can take a peek inside. The image below shows the "AM_Horse_DismountLeftSide"
The most important thing here is the use of the "DismountFinished" Anim Notify. This is used in animations to call the interface function "On Dismounting Pawn Finished" on the character which finalizes the dismounting of the vehicle or other Pawn. This function is required to be called somehow by your system if you are using animations. The PNMS plugin comes with this Anim Notify already, so it is advised to leverage it.
1.2.3 Change Seat Montage
Finally open up one of the Move To Seat Montages so you can take a peek inside. The image below shows "AM_Horse_MoveToBackSeat"
The most important thing here is the use of the "ChangeSeatsFinished" Anim Notify. This is used in animations to call the interface function "On Change To New Seat Completed" on the character which finalizes the seat changing Rider. This function is required to be called somehow by your system if you are using animations. The PNMS plugin comes with this Anim Notify already, so it is advised to leverage it.
2.0 Rider
First we will focus on our rider character who is responsible for much of the animation systems that will be used
2.1 Setup
To facilitate the demonstration of movement we need to setup a few things first. This is where I am going to give a big warning, the technique I am about to show is in no way the best or even an ideal method of performing movement with your character. Ideally you should try to use the function "SimpleMove" but in a networked game that requries a few things to be turned off and on. In due time I plan to have a demonstration of using "SimpleMove" but for now we will use the "Move Component To" to perform the move.
2.1.1 Perform Move Component To Location
We will create a custom event on our event graph to handle moving our character into position. The reason we need to use the event graph is because "Move Component To" is a function that fires over time and that requires the use of the event graph to achieve.
Right click on the event graph and add a new "Custom Event".
Name the new event "PerformMoveComponentToLocation"
Add Two input parameters "Target Relative Location" which should be a Vector and "Target Relative Rotation" which should be a Rotator.
Place a get node for the "Capsule Component" on the graph
Draw a line from the "Capsule Component" and look for the function "Move Component To".
Connect the input variable "Target Relative Location" to the "Target Relative Location" input variable of the "Move Component To" function.
Connect the input variable "Target Relative Rotation" to the "Target Relative Rotation" input variable of the "Move Component To" function.
You could perform a speed based calculation of how quickly based on the distance the pawn can move to determine the length of time it will take for your character to arrive at the desired location, but for demonstration purposes I am simply going to put in 2 seconds. This means that no matter how close or far away the character is, it will always take 2 seconds to move into position.
From the "Completed" execution line draw a line and search for the function "On Move To Mounting Location Completed". This function MUST always be called if you are going to add movement to your mounting, this tells the mounting system that movement has finished.
That is all for our hack-tastic move to location function.
2.2 Play Mounting Animation
Now we are going to go into the Mounting animation.
In the Interfaces section expand the "IMountRider | Animation" category and find the function "PlayMountingAnimation". This function is called during the mounting process to try to play a mounting animation, if it returns false then that tells the mounting system that no animations could be played and to proceed with mounting without using animations.
We implement this function by first dragging a line from the "Position" input property and searching for "Switch On EMountingDirection". This provides an easy control structure determining what animations will play. Currently our horse has two seats and both of those seats can be mounted from the left and the right. From the previous demo our horse returns the value of "Any" in the "Get Relative Mount Direction" which is a catch all telling the system to mount to any seat. For debugging we do not want to break that so we will include "Invalid Side" and "Any Side" as part of our system for now but these values will simply always perform mounting to the left.
Right click on the graph and search for "Play Anim Montage".
Connect "Invalid Side", "Any Side", and "Left Side" to this first "Play Anim Montage" node.
for the Anim Montage property click the list and search for "AM_Horse_MountLeftSide".
Now place a second "Play Anim Montage" node on the graph.
Connect "Right Side" execution line to it.
in the "Anim Montage" property use the drop down to select "AM_Horse_MountRightSide".
Connect both "Play Anim Montage" nodes to the return node.
Make sure the return node returns true.
2.3 Play Dismounting Animation
Next we will look at the Dismounting Animation
In the Interfaces section expand the "IMountRider | Animation" category and find the function "PlayDismountingAnimation". This function is called during the dismounting process to try to play a dismounting animation, if it returns false then that tells the system that no animations could be played and to proceed with dismounting without using animations.
We implement this function by first dragging a line from the "Position" input property and searching for "Switch On EMountingDirection". This provides an easy control structure determining what animations will play. Currently our horse has two seats and both of those seats can be dismounted from the left and the right side. From the previous demo our horse returns the value of "Any" in the "Get Relative Mount Direction" which is a catch all telling the system to mount to any seat. For debugging we do not want to break that so we will include "Invalid Side" and "Any Side" as part of our system for now but these values will simply always perform mounting to the left.
Right click on the graph and search for "Play Anim Montage".
Connect "Invalid Side", "Any Side", and "Left Side" to this first "Play Anim Montage" node.
for the Anim Montage property click the list and search for "AM_Horse_DismountLeftSide".
Now place a second "Play Anim Montage" node on the graph.
Connect "Right Side" execution line to it.
in the "Anim Montage" property use the drop down to select "AM_Horse_DismountRightSide".
Connect both "Play Anim Montage" nodes to the return node.
Make sure the return node returns true.
2.4 Play Move To Seat Animation
The last animation function we will look at allows us to move between seats.
In the Interfaces section expand the "IMountRider | Animation" category and find the function "PlayMoveToSeatAnimation". This function is called during the seat change process to try to play a change seat animation, if it returns false then that tells the system that no animations could be played and to proceed with seat changing without using animations.
We use the "Current Seat ID" to know what seat the rider wants to move to while the "Old Seat Id" indicates the seat they are moving from. The "Current Seat ID" is the seat that that rider is moving to while the "Old Seat Id" is the seat the rider is moving from.
To implement this function we first draw a line from "Current Seat Id" and look for "Switch on Int".
Because our horse has two seats we will add two entries to the "Switch on Int" by pressing the "Add pin +" button twice.
Right click on the graph and search for "Play Anim Montage".
Connect "0" and "Default" to this first "Play Anim Montage" node. This will be the montage to play when the rider is moving into the driver seat.
For the Anim Montage property click the list and search for "AM_Horse_MoveToFrontSeat".
Now place a second "Play Anim Montage" node on the graph.
Connect "Right Side" execution line to it.
in the "Anim Montage" property use the drop down to select "AM_Horse_MoveToBackSeat".
Connect both "Play Anim Montage" nodes to the return node.
Make sure the return node returns true.
2.5 Move To Mounting Location
Next we will implement our move to location function which moves our character toward a preferred location to mount before playing a mounting animation.
In the Interfaces section expand the "IMountRider" category and find the function "MoveToMountingLocation". This function is called during the mounting process to allow developers to inject movement functionality into the system, if it returns false then that tells the system that no movement could be played and to proceed with the mounting process.
This is a fairly easy implementation. Right click on the graph and search for the function "PerformMoveComponentToLocation".
Connect the input variable "Location" to the input variable "Target Relative Location" on the "PerformMoveComponentToLocation" function node.
Connect the input variable "Orientation" to the input variable "Target Relative Rotation" on the "PerformMoveComponentToLocation" function node.
Check true the "Return Value" on the return node to tell the mounting system that we are moving the character.
3.0 Mount
We will keep the mount very simple, there are two functions we will override that deal with selecting an appropriate direction to mount from. When mounting to a seat the desired direction must match a seat within the mount itself, which is why mounts have two functions used to fetch valid directions based on the riders standing location.
3.1 Get Relative Mount Direction
In the Interfaces section expand the "IMountable Pawn" category and find the function "Get Relative Mount Direction".
This function is mostly used by the Position based mounting to detect the relative direction between the player. The PNMS plugin supplies several functions capable of performing a rather fast calculation to determine where the player is standing relative to the mount. Then you also have the ability to dicate the what valid directions the mount is capable of mounting to. For instance a horse can be mounted form a single seat on the left or right side, but a dune buggy can only be mounted from one side on each seat, and a space ship may be mountable from any direciton when outside of it, or any way you want to setup your system.
We will use special Mounting Library function “GetAngleFromRightBetweenActors”. Pass a reference of “self” as the “Main Actor” parameter and the “Rider” as the “TargetActor” parameter. If the Value returned is greater than or equal to zero we will return that we want mounting to occur on the right side of the mount, if it is false than we want mounting to occur on the left side of the mount.
The available options include, Front, Back, Left, Right, Top, Bottom, Any. When the system searches for seats it will prioritize the 6 directional options first, then if none of those options are found it will attempt to find an Any option if one exists.
There are three general functions you can call to determine the rider’s general location relative to the mount's current forward direction.
GetAngleFromRightBetweenActors will tell you if the potential rider is currently relatively on the right side of the mount if it returns a value between 0 and 1 and left side of the mount if it’s value is between -1 and 0. If the value is equal to 0 then it is directly in front or directly behind the mount. In this demonstration we do not care about front and back and assume 0 to be right side mounting.
GetAngleFromFrontBetweenActors will tell you if the potential rider is currently relatively at the front side of the mount if it returns a value between 0 and 1; and on the back side if the value is between -1 and 0; If the value is equal to 0 then it is directly on the right or left side of the mount.
GetAngleFromUpBetweenActors will tell you if the potential rider is currently relatively above the mount if its value is between 0 and 1; and below it if it’s value is between -1 and 0. If it’s value returns 0 than it could be anywhere along the horizon of the mount (Front, Back, Left, or Right).
3.2 Get Relative Dismount Direction
We will not be overriding this function in this tutorial as it requires quite a bit of explanation. Instead we will leave its default behavior which means our character will always dismount on the left side of the mount.
In short if you want to implement this you will need to determine if the rider that is dismounting is the driver or a passenger.
if they are the driver then you can use the "Control Rotation" of the Mount (which will be your player controller) and the Actor Rotation of the Mount to determine where the rider is currently looking to dismount.
If the rider is the passenger than you will need to get the Control Rotation of the rider instead (using the GetCharacterController interface function) and then use the Mounts Actor Rotation to determine the difference between where the rider and the mount are looking.
The finished project has a full demo of how that works.