Introduction
Welcome to the guided tutorial for the Pro Mounting System version 1.6 for Unreal Engine 4.23 and 4.24. In this tutorial we will go over the bare bone setups for getting up and running with the plugin. To follow along you will need to have purchased the plugin from the Unreal Marketplace. You can then create a new project or download my starting project from the link below. There will also be a guide on setting up a project independent of the starting project.
Market Place: Pro Networked Mounting System
Download Starting and Finished Projects
The mounting system was built using SOLID principles of programming with the primary mechanisms being Dependency Inversion and Dependency Injection. This is what allows the Mounting system to be implemented across any game system without having to relying on any special Actors and Characters other than the base UE4 classes.
Table of Contents
Becaue this is a fairly lenghty tutorial to get everything setup. Here is a Table of Contents for easy jumping around.
5.0 Player Controller
5.1 Implement the Player Controller
5.2 Controller Unified Interface
5.3 Rider Controller Interface
6.0 Player Character
6.2 Character Unified Interface
The Finished Project
I want to take a moment to talk about the finished project and some of the advanced techniques it demonstrates. This tutorial is geared only towards a very basic setup to get you up and running, but things like Advanced animation techniques are not covered here. However the downloadable Finished project demo demonstrates a fairly advanced animation system used to fetch animation data needed for a specific mounts dynamically and cleanly with no need to replicate montages or animation sequence assets. This is an important technique to learn and know for UE4 in general as it allows you to scale up the mounting system beyond a single mount to an unlimited number of mounts and vehicles all capable of having their own unique ( mounting / dismounting / mounted ) animations and with little performance penalties, reduce animation blueprint complexity, and little to no network bandwidth for animations.
Another thing the Finished Project provides is a demonstration on how to handle blocking input to keep the player from rotating in their seat while mounted.
But most importantly the finished project offers several Blueprint Tutorials that guide you through what each completed system does including the animation system that has been added to it.
The Finished Project also includes other completed demonstrations:
- A fully functional 4 passenger Buggy.
- A 5 Passenger Buggy with added 5th seat Turret linked actor
- Demo on how to setup Player Mounting
- A two seat horse and player mount setup
While these do not have a BP Tutorial YET, a foundational knowledge of how the plugin works will get you far in figuring out these systems.
1.0 Project Tour
The Finished project starts with a built in Blueprint Tutorials to get you familiar with the project. I highly suggest you click on them to get an idea of where everything is and what it does.
For the Starting project itself it is much more stripped down and bare bones. But some of the key things that you will need to know about follows
Mannequin Animations
I have built and provided a series of mounting, dismounting, and sitting animations for you to use which include direction based mounting and dismounting for getting (in / on), (off / out) of your mount or vehicle.
Check out these animations at “Content/Mannequin/Animations”. They include the following:
- AM_Horse_MountLeftSide
- AM_Horse_MountRightSide
- AM_Horse_DismountLeftSide
- AM_Horse_DismountRightSide
- AM_Horse_MoveToFrontSeat
- AM_Horse_MoveToBackSeat
- A_Idle_HorseDriving
- A_Idle_HorseRiding
- AM_Buggy_MountLeft
- AM_Buggy_MountRight
- AM_Buggy_DismountLeft
- AM_Buggy_DismountRight
- A_Idle_BuggyDriving
- A_Idle_BuggySeated
The “A” stand for normal Animation Sequences you can plugin to your anim graph while the AM stand for AnimMontages that can be played over your current Animations if setup properly.
All of these AnimMontages are setup to play from the Default Slot, nothing really special has been set up for them beyond that. You will see anim notifies if you are looking at the Finished project and we will cover that later.
Robot Horse
Prepare to count yourself among the luckiest people in the world. For the low low cost of this plugin you also receive my legendary Robot Horse! It has no animations, and a body built of highly detailed reflective spheres and cubes, but it does the job of a stand in horse mount with a skeleton of its own. Maybe one day I’ll add animations to it but right now I got bigger projects to build.
2.0 Create the Basic Assets
Return to Table of Contents
This section will cover creating the basic foundations we will need for this tutorial. This includes the Folder Structure as well as the Blueprint Assets we will be using.
If it is not already created start by Creating the MountingContent folder. Then create the Blueprints Folder, and the Maps Folder under it.
If you do not have a MountingMap already create it by opening the ThirdPersonExampleMap found under “Content/ThirdPersonBP/Maps” and then select SaveAs. Save the map under “Content/MountingContent/Maps” as “MountingDemoMap”
Next go to “MountingContent/Blueprints” and create a new Blueprint Class from the ThirdPersonCharacter and name it “BP_MountingCharacter”. We’ll use the ThirdPersonCharacter as a starting point for our own character because it is already setup for basic movement and a camera.
Next Duplicate “PB_MountingCharacter” or create another Blueprint Class from the ThirdPersonCharacter and name it “BP_Horse”. This will be our horse to mount. Alternatively you can use the Buggy from the Advanced Vehicle Content Package.
Open up the “BP_Horse” and select the Mesh Component. Set the Mesh of the Mesh component to be “RobotHorse_01”. Then Set the “Anim Class” to “ABP_RobotHorse_C”. This AnimBlueprint currently does nothing interesting but is a placeholder for the future when I decide to add a bit more to the Robot Horse.
Next Create a new Blueprint Class from the “PlayerController” base class and call it “BP_MountingPlayerController”.
Finally Create the GameMode we will be using for playing the game. Call it “BP_MountingGameMode”.
Open up the newly created game mode and set “BP_MountingPlayerController” for the “Player Controller Class”. Then “BP_MountingCharacter” for the “Default Pawn Class”.
Finally with the “MountingDemoMap” open go to World Settings. You may need to activate this pane by going to “Window->WorldSettings”. In the GameMode section choose “BP_MountingGameMode” from the dropdown menu.
3.0 Interface and Component Setup
Return to Table of Contents
In this section we will be adding the required Interfaces and Components to each of the assets we have created.
Click on Class Settings at the top of the Blueprint. Under the Interface Section in the Details Panel click the “Add” Drop down. Add the “ADMUnifiedControllerPawn” interface. Then Add the “MountRiderInterface”. The propernames of these Interfaces are “IADMUnifiedControllerPawn” and “IMountRiderInterface” for those C++ devs. We will go over what each of these interfaces do in the next section.
Next add the “MountRiderComponent to the component’s window of the BP_MountingCharacter class. That is all we will do for now, the next sections will cover implementing the interfaces with the components.
Open up the “BP_Horse” blueprint. Select “Class Setting” from the Top Menu and then in the “Details” Panel under the Interfaces panel click the “Add” drop down. Add the “ADMUnifiedControllerPawn”. Then Add the “MountablePawnInterface”. For you C++ programmers the proper names is “IMountablePawnInterface” and “IADMUnifiedControllerPawn”
Next add the “MountablePawnComponent” to the component’s window of the BP_Horse. Again this is all we will do for now as the next sections cover implementing these interfaces with the components.
Open the “BP_MountingPlayerController” blueprint.
Select “Class Settings” from the top menu and then in the “Details” Panel under “Interfaces” click the “Add” Drop down. Add the “ADMUnifiedControllerPawn” interface. Then add the “RiderControllerInterface” interface.
Next add the “RiderControllerComponent” to the component’s window of the BP_MountingPlayerController”. The next sections will cover implementing the interfaces with these components.
4.0 Brief Interface Overview
Return to Table of Contents
This section will quickly go over the different interfaces and components and what they do. For a more detailed explanation see the Documentation in the Documentation Link of the Plugin.
In general the three components of this system do not directly call each other, instead they call interface functions that then call other component functions. This allows the entire mounting system to function without using any direct casts to specific objects other than the UE4 standard Actor, Pawn, and Object base classes. With this flexibility it allows any Pawn to be a Rider or possessable mount and any Actor to be a non-possessable Mount.
IADMUnifiedControllerPawn
Put simply this interface unifies the Pawn and the Controller so that we can retrieve either one no matter which of these objects we get. Naturally they follow the standard replication rules meaning that on multiplayer games only the Server will have all Controllers but client machines will be able to access their own controller and the pawns of other riders. Basically follow standard UE4 client server rules when creating your gameplay logic and don’t assume pointers will point to things (check for null).
This interface is most useful when dealing with unknown systems such as interaction systems. You may have written your own interaction system or be using someone else's code to build your game. Another example is leveraging UI where you want to get the Health of the Player instead of the Mount the player controller is controlling. In the event that you are using some unknown code that needs to account for the mounting system you can use this interface to ensure you are playing with the Rider, the Controller, or the Mount regardless of which of these three objects is sent to that system as a parameter.
IRiderControllerInterface
This interface simply provides the basic function definitions needed for the Player Controller or even AIController to work properly.
IMountRiderInterface
This interface provides the basic function definitions needed for the Player Character or an AI character to work properly with the mounting system.
IMountablePawnInterface
This interface provides the basic function definitions needed for a Mountable Pawn.
Depreciated Functions
You may notice that within the interface side panel a special category called “Depreciated”. These are older functions that where implemented on a previous version of the Unreal Engine. Rather than removing these functions from the interfaces I have opted to do a stepped depreciation. Usually these will be followed by a number indicating the version of UE4 that the functions will stop being called from the internal system.
The First Step is a Soft Depreciation, these functions are simply placed within a depreciated category but all logic that calls them from within the components is not changed. They will still be called and if they have been replaced by any new functions the new functions will also be called checking if the return of the depreciated value is invalid first.
The Second Step is hard depreciation. All logic that originally called that function is removed and if there are newer functions they will completely take over.
The third step is removal of the function from the interface.
Each step represents an entire Engine version. So if a function is depreciated in UE 4.24 it is put into the deprecated category immediately. In Version UE 4.25 any logic within the components that once called that function is then removed. In UE 4.26 that function is then removed from the interface completely.
This is designed to allow developers time to properly upgrade from one version of the engine to another without completely losing functionality and having to reimplement logic.
5.0 Implement the BP_MountingPlayerController
Return to Table of Contents
This section we will go over the easiest system to implement, the controller. In a later section or tutorial we will go over developing a basic interaction system for you to use with the controller. The mounting system does not implement an interaction system natively and relies on your own expertise and project requirements to do this. However triggering the mounting and dismounting system is easy with a single function you can call for each of these operations.
5.1 General Setup
Setup the Owned Pawn
One of the first things we need to do is tell the RiderControllerComponent what the main pawn it controls should be. In the Functions hover over it until you see the “Override” option appear. Click the “Override” option and search for “OnPossess”. This function is fired every time the controller takes possession of a pawn.
Get the RiderControllerComponent and call it’s function “SetControlledPawn”. Pass in the “PossessedPawn” parameter to the “newControlledPawn” function parameter.
This is very important for ensuring the mounting system works properly. There are Three properties to be aware of; the OwnedPawn, the MountPawn, and the ControlledPawn. The owned pawn is the original character that the component always keeps a reference to. The mount pawn is of course the mount the owned pawn is currently sitting on. The controlled pawn is the pawn that the controller is currently controlling.
The special feature of the “SetControlledPawn” function is that if the component does not currently have a reference to the owned pawn, than the first pawn passed into it will be set as the owned pawn and all subsequent pawns passed into it will be treated as mount pawns.
You can override this by calling “SetOwnedPawn” or “SetMountPawn” but generally you do not need to do this.
Setup the RpcGraph
For online games we need to prepare for input and RPC calls to the server. I personally create separate event graphs for this work to keep my code organized. Create an InputGraph and an RpcGraph. We will not go over input just yet but will setup the RpcGraph. Again later I will show you how to build a rudimentary interaction system where we set this up.
Create a new “CustomEvent” called “SERVER_PossessPawn”. Drag out the PossessCharacter Interface function and then drag the CharacterToPosses line from the “PossessCharacter” function to the “SERVER_PossessPawn” function creating an input variable.
Make sure the Replicates property is set to “Run on Server” and the Reliable flag is checked.
5.2 IADMUnifiedControlerPawn for the PlayerController
Return to Table of Contents
Prepare to Mount
Implement prepare to mount by getting the RiderControllerComponent and calling “PerformMountPawn”, passing the “MountOrRider” and “LinkedActor” parameter through to it. Then connect the output as shown in the image.
You don’t actually have to implement this function this way. You can simply return true. However To start the mounting process you need some object to call PerformMountPawn from the RiderControllerComponent. That function is the function that starts the mounting process and you must provide it the Mount you want to start mounting onto. I simply use this function as an easy method to trigger the system.
The second Parameter “LinkedActor” is optional and is not required for the linked actor mounting to work. Say you have a mount with several seats and one is a turret, you can setup your turret to be interactable and supply itself as the Linked Actor Parameter to this function allowing you to directly mount the turret seat.
The PreformMountPawn function calls PrepareToDismount for the Pawn and the Mount as well, if any of those two return a false for those functions then the entire mounting procedure is canceled. These prepare functions are specifically designated to allow you to configure any custom properties you want to set up and/or stop the mounting process early.
Prepare to Dismount
Implement by calling “PerformDismountPawn” function of the RiderControllerComponent. Connect the dots as shown in the image. Just like “PrepareToMount” you do not need to use this function to start the dismounting process, simply return true. But like PrepareToMount you need a way for your system to call “PerformDismountPawn” from the RiderControllerComponent and supply it the old mount.
Is Mounted
Implement Is Mounted by calling the “IsMounted” function from the “RiderControllerComponent”
Get Character Pawn
Implement “GetCharacterPawn” by calling “GetOwnedPawn” from the RiderControllerComponent.
Get Character Mount
Implement “GetCharacterMount” by calling “GetMountPawn” from the RiderControllerComponent
Get Character Controller
Implement “GetCharacterController” by supplying Self. As noted one of the purposes of this interface is in situations where you do not fully know the implementation of a system are using or have designed your system to leverage a different type of object.
5.3 Implement IRiderControllerInterface
Return to Table of Contents
PossessCharacter
Begin with the “SwitchHasAuthority” Macro which determines if we are the authority (on the server) or if we are the remote (on the client).
From the “Authority” Arrow call “Possess” and supply the “CharacterToPosses” parameter to the “InPawn”. Connect the line from the “Possess” function to the return node and return true.
From the remote line of “SwitchHasAuthority” call “SERVER_PossessPawn” and supply the “CharacterToPossess” parameter.
Now the Mounting Process calls this function to take possession of a given character or mount depending on what context this call is being fired.
OnRiderAdded
The Implementation of this function is completely optional and is used by the Mounted Actor to notify other riders that a new rider has been added effectively taking up a seat on the mount.
There are two methods to implementing this function and provide two levels of dealing with this notification. The first is to directly within the interface function itself.
If you decide to implement this with the RiderControllerComponent and call RiderAdded function, passing the properties in, you can then also implement the delegate function of the RiderControllerComponent OnRiderAdded
OnRiderRemoved
The implementation of this function is completely optional and is used by the Mounted Pawn to notify other riders that a rider has left the mount or vehicle. Effectively indicating that another seat is available and can be moved to.
There are two methods to implementing this function and provide two levels of dealing with this notification. The first is directly on this interface function itself.
If you decide to implement this with RiderControllerComponent and call RiderRemoved, passing the properties in, you can then also implement a delegate function of the RiderControllerComponent OnRiderRemoved.
OnOtherRiderChangedSeat
The implementation of this function is completely optional and is used by the Mounted Pawn to notify other riders that a rider has changed from one seat to another within the mount or vehicle. Effectively indicating that another seat is available and can be moved to.
There are two methods to implementing this function and provide two levels of dealing with this notification. The first is directly on this interface function itself.
OnMountActionFailed
As of 4.25 this function is called whenever an attempt to mount fails. A log will also accompany this failure and you can use the FMountActionResponse structure to find out what caused the failure. All Prepare and Start interface functions return the response structure so you can customize reasons for why you failed the mounting in your game to send the player messages appropriately.
OnDismountActionFailed
As of 4.25 this function is called whenever an attempt to dismount fails. A Log will also accompany this failure and you can use the FMountActionResposne structure to find out what caused the failure. All Prepare and Start interface functions return a response structure so you can customize the reasons for why you failed the dismounting in your game to send the player messages appropriately. This could be they are in the middle of a cutscene or a special event.
OnChangeSeatActionFailed
As of 4.25 this function is called whenever an attempt to change seats fails. A Log will also accompany this failure and you can use the FMountActionResponse structure to find out what caused the change seat failure. All ChangeSeat Functions return this response structure so you can customize the reasons why you failed the change seat in your game as well as handle the standard failures by the system.
GetRiderControllerComponent
Simply return the RiderControllerComponent. This function allows you to retrieve the RiderControllerComponent without executing a specific cast.
6.0 Implement the MountingCharacter
Return to Table of Contents
This section we will get to the important details of implementing the MountingCharacter so it can perform the Mounting.
6.1 General Setup
One of the major things you need to do is set the “RelativeMeshLocation” and “RelativeMeshRotation” properties for the component. These properties are used to reset the client side mesh component that gets offset from the capsule due to attachment and detachment replication. For the Standard mannequin this is simply setting the Z values of both Location and Rotation to -90 (maybe give or take a few points if you are a perfectionist). \
These are the exact same values found in the Mesh Component’s transform properties of any ACharacter. Simply copy and paste.
You can Automate these by having them automatically updated in the Pawn’s ConstructorScript function
The other thing to be aware of are the two properties “PossessMountAfterAnimation” and “PossessCharacterAfterAnimation” these properties tell the mounting system when to take possession of the mount or the player during the mounting and dismounting processes.
PossessMountAfterAnimation is used for mounting. It means that the character will take control of the mount once the mounting animation finishes and the character is firmly on the seat, if this is false than they will take possession of the mount immediately after moving into position to start mounting.
PossessCharacterAfterAnimation is used for dismounting. It means that the system will retake possession of the character once the dismounting animation has completed. If this is false then repossession occurs immediately after starting dismounting.
Move to Location
I am going to preface this with; this by no means is the best way to move your character into place for mounting and there are way way way better means to do this. But for demonstration purposes I am simply interested with ensuring the logic works.
Start with creating a custom Event and calling it “PerformMoveToLocation” Then right click and search for a function called “MoveComponentTo”. Grab the Capsule Component and drag it into the “component” parameter.
Then take the “TargetRelativeLocation” and “TargetRelativeRotation” and drag a line from the “MoveComponentTo” function to the space just below the execution Line of your new “PerformMoveToLocation” function to create two new inputs for it. Now set the “OverTime” parameter to 2 seconds.
Drag the completed line out and call “OnMoveToMountingLocationComplete”
I’m going to say this again, this is a terrible way to do this but getting into Cinematics or AI is not part of this tutorial. While I may find time one day to implement a more sophisticated method of doing this, for now it gets the job done.
6.2 Implement ADMUnifiedControllerPawn for Character
Return to Table of Contents
Prepare to Mount
For this tutorial this function will simply return true, signaling to the mounting system that the character is prepared to start the mounting process. However this is one of the key locations where you can inject your own logic. This function supplies the “Mount or Rider” parameter, in the context of the character it is always going to be the mount you are attempting to get on. If a Linked actor has been passed to the controller it will also have a value here.
Returning false for this function will abort the mounting process and prevent mounting from starting. There could be many reasons you would not want the player to start mounting, from them being in a special interactive scene to them not having the proper progress requirement for your game (such as a key, license, quest, achievement, etc). Here you can also customize the response object to return any error you want using a “Custom” code of your own.
Prepare to Dismount
For this tutorial this function will simply return true, signaling to the mounting system that the character is prepared to start the dismounting process. This is one of the key locations where you can inject your own logic. This function supplies a “Mount Or Rider” parameter, in the context of the character it is always going to be the mount you are attempting to get off.
Returning false for this function will abort the dismounting process and prevent the dismounting from starting. Like mounting, there could be many reasons why you would not want the player to start the dismounting process in your game. It could be they cannot dismount because of a cutscene or are on a special vehicle that must reach its destination first. Here you can also customize the response object to return any error you want using a “Custom” code of your own.
Is Mounted
Implement the characters “IsMounted” function by using a validated get to retrieve the MountRiderComponent. For the IsValid execution line call the IsMounted function from the MountRiderComponent and supply it into the return. For the “Is Not Valid” execution line simply return false.
Because this function could be called from the AnimBlueprint of your character you want to ensure that the MountRiderComponent has not been destroyed while the Animation Graph is updating. This typically occurs during game shutdown where the AnimBP is still running but the components have been cleaned up and destroyed on the player.
Get Character Pawn
For GetCharacterPawn simply return self.
Get Character Mount
For GetCharacterMount use a Validated Get for the “MountRiderComponent” For the IsValid execution line call the MountRiderComponent’s “GetCurrentMount” function and return it. For the “Is Not Valid” execution line simply return nothing.
Again the Validated Get is useful for functions that will be called by your Animation Blueprints and could be called during the game shutdown when these components may be destroyed.
Get Character Controller
This is where some of the magic of the UnifiedControllerPawn interface begins to become apparent. Calling the MountRiderComponent’s function “GetRiderController” will always return the controller that actually owns the pawn. In cases where you are now controlling a horse or vehicle rather than your pawn this will always retrieve the Controller this character is supposed to be controlled by.
Naturally for AI Characters this will be an AI Controller but for Player Characters this will be their Player Controller.
6.3 Implement MountRiderInterface
Return to Table of Contents
This section will go over the important details of setting up a Mount or Vehicle so that it can be ridden or controlled.
StartPawnMounting
Implement this function by grabbing the MountRiderComponent then call it’s “MountPawn” function. Supplying the “newPawnMount” as a parameter and returning the response and bool value. The NewPawnMount parameter is the new pawn or actor you wish to mount. Similar to PrepareToMount if a linked actor was supplied by the Controller it will pass it along into this function and the MountRiderComponent will skip most of the mounting logic provided the linked actor is not already occupied.
This function is called as part of the RiderControllerComponent’s “PerformMountPawn” process, if all Prepare functions return true than the last thing it calls is StartPawnMounting and the MountRiderComponent’s “MountPawn” function begins the mounting process for the character.
As a sort of special note, The RiderControllerComponent’s “PerformMountPawn” is the start of the whole mounting process and must be called first. It is how the Controller itself obtains and maintains a reference to the mount and your character.
StartPawnDismounting
Implement this function by grabbing the MountRiderComponent and calling it’s “DismountPawn” function. Supply the “OldPawnMount” as a parameter to the function and return the output.
Note that this function does not have an optional Linked actor input. The mounting system is designed to treat linked actors as an intrinsic part of the overall mount itself and internally manage the connections between mount and linked actors. That does not, however, prevent you from injecting logic into the various interface functions and obtain the linked pawn from the RiderControllerComponent or the MountRiderComponent which both have a reference to the linked actor.
SetRiderCollisionEnabled
OnMountingPawnFinished
This is the final step to mounting that needs to be called in order to finish the mounting process. Several properties are finalized when this function is called, among them the flag indicating your character is officially “seated” on the mount.
If you have no animations to play for mounting than this function is called automatically. However if “PlayMountingAnimation” function implements an animation to play then that animation needs to use an AnimNotify to call this interface function.
You can do this manually or use the “MountFinished” AnimNotify that this plugin comes with.
OnDismountPawnFinished
This is the final step to dismounting that needs to be called in order to finalize the dismounting process. Like mounting, several properties are cleared with this function and detaches from the mount.
If you have no animations to play for mounting than this function is called automatically. However if “PlayDismountingAnimation” implements an animation and returns true instead of false then the playing animation needs to use an AnimNotify to call this interface function.
You can manually implement your own anim notify or you can use the “DismountFnished” anim Notify that comes with the plugin.
There are also a few considerations to take into account with dismounting. Many of them the Mounting System handles itself such as mesh offset caused by dismounting for characters. Other issues such as stopping the play of AnimMontages or having an AI controller repossess the mount if you are the driver are not covered. Dismounting a mount you are currently driving while moving will preserve its current movement vector on the client without having an AI controller retake control. These are all quarks of UE4 itself.
OnChangeToNewSeatCompleted
This is the final step of the changing seats procedure and needs to be called in order to finalize the change seats process. Several properties are cleared with this function and finishes attaching the pawn to the proper new seat location.
If you have no animation that plays for seat changing this function is called automatically. However if “PlayMoveToSeatAnimation” plays an animation and returns true instead of false then the Playing Animation needs to use an AnimNotify to call this interface function
You can manually implement your own AnimNotify or you can use the “ChangeSeatsFinished” Notify that comes with this plugin.
MoveToMountingLocation
This function is called to start your pawn toward moving to its desired location before mounting. There are many many ways to implement this and I am currently using the most wonkiest one of them all.
Call the function we set up earlier [Anchor]PerformMOveToLocation[Anchor]. Passing in the Location and Orientation. Then return true.
You can also simply leave this function as it is with it simply returning false. The mounting system will pick this up, jump immediately to the character in the desired location and start the mounting animation (if you have any).
OnMoveToMountingLocationCompleted
This is one of those functions that can be called from many different sources and depends on if you have logic for moving the character into a specific location. To implement it you simply get the “MountRiderComponent” and call “MoveToMountingLocationComplete”.
Here you can also do some additional checks, maybe the mount has moved away from you and is now too far than the original mounting location. Of course there are methods to this but when another player is controller your mount or you are not updating the mounting location dynamically through AI or other means it could happen.
In the event you need to “bail out” of a mount due to the above cases you’ll need to add some Bail out logic to clear the seat on the mount and call the Reset function on the Controller and Character.
If the [anchor]“MoveToMountingLocation”[anchor] function simply returns false than this function is automatically called by the mounting system and assumes you have no logic in place to move the player to the desired location.
IsSeatedOnMount
To implement this function we will simply grab the MountRiderComponent as a Get, then convert it to a Validated Get. From “MountRiderComponent” call the function “IsSeated” and return it in the IsValid state. For the IsNotValided execution line simply return false.
We use a Validated Get here because this function will most likely be used by the Animation Graph. When your game shuts down the components are destroyed first on your actor and the Animation Graph continues to update animations. Without the validated git it will cause annoying error messages.
IsDriver
Get the MountRiderComponent and convert it to a Validated Get. From the IsValid Execution line call MountRiderComponent’s “IsDriver” function and return it. From the IsNotValid execution line simply return false.
This function uses the Validated Get because it may be used for Animation Graphs which continue to update animation during shutdown and after components have been destroyed and garbage collected.
GetRiderMesh
This function simply returns the master mesh component of the player.
GetMountRiderComponent
This function simply returns the MountRiderComponent itself.
PlayMountingAnimation
I will not be explaining the intricacies of a fully dynamic animation system in this tutorial. In the final project I have a fully working demonstration of how you can supply animations per mount for your character that you are free to steal and use for your own games. For this tutorial however simply return false. This will cause the mounting system to automatically proceed with the mounting system.
PlayDismountingAnimation
I will not be explaining the intricacies of a fully dynamic animation system in this tutorial. In the final project I have a fully working demonstration of how you can supply animations per mount for your character that you are free to steal and use for your own games. For this tutorial however simply return false. This will cause the mounting system to automatically proceed with the mounting system.
PlayMoveToSeatAnimation
I will not be explaining the intricacies of a fully dynamic animation system in this tutorial. In the final project I have a fully working demonstration of how you can supply animations per mount for your character that you are free to steal and use for your own games. For this tutorial however simply return false. This will cause the mounting system to automatically proceed with the mounting system.
SetRiderCollisionEnabled
This function allows you to control how collision is disabled and enabled on the player while mounted. The primary requirement for ACharacter objects is that the Capsule Component collision be disabled to prevent the Character logic from colliding with the mount collision components and doing crazy physics things. This function is an optional function in Unreal 4.23 and 4.24 where it falls back to the default behavior of setting collision if this function returns false. Using it however allows you to setup more robust collision settings than simply turning off and on capsule collision. For instance you could have collisions imply ignore "vehicle" collision objects instead.
The “ShouldEnable” parameter simply tells you if you need to enable collision or disable collision because this is the same function called for dismounting as well as mounting. How and in what way that collision is disabled or enabled is up to you.
I have chosen to Disable to Collision on the Capsule Component and use a Select Node with “No Collision” when false and “Collision Enabled (Query and Physics)” when true. In general individual mesh collision does not need to be disabled. I simply return true if successful.
7.0 Implement the Mount Character
Return to Table of Contents
This section we will get to the important details of implementing the Mount Character or Vehicle so it can perform the Mounting.
Because we are dealing with a character type for this horse we will need to make a few small additions to it so that the movement component gets cleared when you dismount while the horse is moving. Not doing this will result in your mount continuing to move forward on clients even though they are staying still on the server. This appears to be only an issue with the UCharcterMovementComponent found on ACharacter base classes. APawns with no movement component or AVehicle based classes do not appear to have the issue.
First thing we will do is create a custom variable to hold our AI Controller. Any AIController will work including the default one which does nothing. We'll call it "AIControllerRef" and it will be of the "Controller" type. This will not be a replicated value as all controllers only exist on the servers.
Go to the Functions section on the right side of your blueprint and hover over until you see the "Override" drop down appear. Click on that and type "Possess" to find the Possessed Event function and click on it.
The Possess function passes in a "New Controller" variable. We are indeed making an assumption that for this pawn it will always first be possessed by an AIController and that will be the first controller that we set to our parameter. I've not had any issues with this funciton not having an Authority switch as I do not believe it is executed on the client, but I still put a HasAuthority switch just in case. We first test if our AIControllerRef variable is valid, if it is we leave it alone, if it is not than we set the controller to it.
That's all for our general setup here. We'll come back to this AI controller later as we setup the MountablePawnInterface.
7.1 Implement IADMUnifiedControllerPawn for Mount
Return to Table of Contents
Prepare to Mount
For this tutorial this function will simply return true, signaling to the mounting system that the mount or vehicle is prepared to be mounted. This is one of the key locations where you can inject your own logic. This function supplies the “Mount or Rider” parameter, in the context of a mount or vehicle it is always going to be the potential rider attempting to get on. If the rider has tried to interact directly with a linked actor it will be passed along into the “Linked Actor” parameter.
Returning false for this function will abort the mounting process and prevent mounting from starting. There could be many reasons you would not want the player to start mounting, for example the animal may not be tame or you may require that only the owner of the animal or vehicle can take control or get on it, or the vehicle may be broken or the animal may have been killed.
Prepare to Dismount
For this tutorial this function will simply return true, signaling to the mounting system that the mount is prepared for dismounting. This is one of the key locations where you can inject your own logic. This function supplies a “Mount Or Rider” parameter, in the context of the mount it is always going to be the character attempting to get off.
Returning false for this function will abort the dismounting process and prevent the dismounting from starting. Like mounting, there could be many reasons why you would not want the player to start the dismounting process in your game. It could be that they are in a cutscene or traveling too fast to get off or that the mount has not reached its destination yet.
Is Mounted
Grab the MountablePawnComponent and return the value of “IsMounted”.
Get Character Pawn
For Mounts we return their driver for this function. Get the MountablePawnComponent and return the value of its “GetDriver” function.
Get Character Mount
For characters that are mounts themselves we simply return itself since it is the mount. Simply right click and return “Self”.
Get Character Controller
For mounts we always simply return the Controller that is currently controlling them. Simply right click and search for “GetController” and return it.
7.2 Implement MountablePawnInterface
Return to Table of Contents
This section covers the implementation of the MountablePawnInterface on your mount character.
MustHaveDriver
Get the MountablePawnComponent and use it to call “MustHaveDriver” and return its value.
IsMountablePawn
Get the MountablePawnComponent and call “CanMount” and return it’s value.
IsMountableByPawn
For demonstration purposes this function will simply return true. This is a special function to test if the specified pawn is capable of mounting the vehicle. Often used in conjunction with “PrepareToMount” you can setup specific logic to determine if the pawn can or cannot mount due to some conditions that need to be meet.
IsDriverSeat
Get the MountablePawnComponent and call “IsDriverSeat”. Pass in the “Seat Data” parameter and return the function’s value.
HasDriver
Get the MountablePawnComponent and call its “HasDriver” function, returning the bool value.
GetRelativePositionToMount
For this demonstration we will be assuming that our horse mount can only be mounted from the left or right side. This function allows each individual mount to specify the different possible directions it could be mounted from. The purpose of this function is to find the relative location of the player from the mount and that will aid in choosing an appropriate seat to mount to.
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).
GetRelativeDismountDirection
For Demonstration purposes we are simply going to return “Left Side” for dismounting. However there is a much more comprehensive way to set up the dismount direction based on the direction the player controller is currently looking relative to the mount. You can find a fully working example of this in the Finished Project.
GetMountBody
Get mount body is used to determine what mesh the player should attach themselves to. For demonstration purposes our mount only has one mesh and so we will be returning that. The Mesh can be any Mesh including a static Mesh, the system does not care if you are using skeletal meshes or static meshes.
However if you have linked actors this is where you would set up logic to retrieve the mesh based on the seat ID indicating the linked actor you want to get the mesh for.
GetMountablePawnComponent
This simply returns the MountablePawnComponent
GetMaxRiders
Get the MountablePawnComponent and call “GetNumSeats” and return the value.
GetDriver
Get the MountablePawnComponent and call “GetDriver” and return the value.
GetCurrentRiderCount
Get the MountablePawnComponent and call “GetNumRiders” and return the value
FindAvailableMountingPosition
Get the MountablePawnComponent and call “FindAvailableMountingPosition”. Pass in the “Position” enum retrieved from the “GetRelativeMountDirection” and the “RiderLocation” parameters. Then return the outputs.
This function's main purpose is to find the best seat available according to your current distance from the mount and relative direction from the mount. It also performs a distance validation check so you cannot mount too far way from the mount itself.
IsSeatOccupiedById
Get the MountablePawnComponent and call it’s “IsSeatOccupiedById” function. Pass the “Seat Id” parameter into it and return it’s value.
IsSeatOccupiedAtIndex
Get the MountablePawnComponent and call it’s “IsSeatOccupiedAtIndex” function. Pass the “Seat Index” parameter into it and return it’s value.
SetSeatOccupiedById
Get the MountablePawnComponent and call its SetSeatOccupiedById. Pass “SeatId” and “Rider” parameters into the function and return the output
SetSeatOccupiedAtIndex
Get the MountablePawnComponent and call its SetSeatOccupiedAtIndex. Pass “Seat Index” and “Rider” parameters into the function and return the output
ClearSeatById
Get the MountablePawnComponent and call its “ClearSeatById” function. Pass in the “Seat Id” parameter and return the functions value.
ClearSeatByIndex
Get the MountablePawnComponent and call its “ClearSeatByIndex” function. Pass in the “Seat Index” parameter and return the functions value. (Unfortunately this function does not follow the normal naming convention of GetById and GetAtIndex).
GetSeatDataById
Get the MountablePawnComponent and call is “GetSeatDataById”. Pass in the “Seat Id” parameter and return the output.
GetSeatDataAtIndex
Get the MountablePawnComponent and call is “GetSeatDataAtIndex”. Pass in the “Seat Index” parameter and return the output.
CanMountActor
This is a crucial function that must return true for mounting to proceed. It can be implemented in any way you deem fit but I implement it in the following way. Get the “GetMaxRiders” interface function, the “GetCurrentRiderCount” interface function, and “IsMountableActor” interface function. Extend the return value of “GetMaxRiders” and choose a “GreaterThan” boolean operation. Connect “GetCurrentRiderCount” to the second input. Then Drag off the bool pin from the “greater than” sign and connect it to an “Boolean And” operation. Connect the IsMountableActor interface function to that.
CanMountAtPosition
Though this function is never used by the internal system itself you could use it for validate seating operations. To implement this I simply grab the “Find Available Mounting Position” function we implemented earlier and pass in the “Rider Location” and “Desired Mounting Position” parameters to it. Then simply return the return value.
OnRiderFinishedMounting
This function is mainly used when you want to provide signaling to other riders or players that someone has gotten onto the mount.
Get the MountablePawnComponent and call “RiderFinishedMounting”. Pass the “Mounted Actor” and “Seat Id” into the function and return true. The return value holds no significance in this function, only to ensure that it is implemented as a function and not an event.
This function will loop through all the current riders and send them an update indicating that a rider has been added.
OnRiderFinishedDismounting
This function is mainly used when you want to provide signaling to other riders or players that someone has gotten off the mount. But we will also use it to signal to the mount’s AI Controller that it needs to retake possession of mount.
We will start with getting the MountablePawnComponent and call “RiderFinishedDismounting”. Pass the “Dismounted Actor” and “Seat Id” parameters into the function. The return value of this function is to simply ensure it is implemented as a function in blueprints and not as an event.
The RiderFinishedDismounting function will loop through all the current riders and send them an update that one of the passengers has been removed. How this signal is handled is dependent on how you implemented the IMountRider Interface function “OnDismountingPawnFinished”.
The second half of this function we will return to the AIController we setup earlier. If the seat we just dismounted from is the driver seat than we want to return control of the mount back over to the AI Controller to prevent “funny client side movement”
First we check if the sent in set ID is 0 (our driver seat because we declared seat 0 to be the driver seat). If it is than we check if the AI Controller is valid. If it is Than we possess the mount.
OnRiderFinishedChangingSeats
This function is mainly used when you want to provide signaling to other riders or players that a fellow passenger has taken a different seat. We will also leverage it to have the AI Controller retake possession of it just like we did in OnRiderFinishedDismounting.
Get the MountablePawnComponent and call “RiderFinishedChangingSeats”. Pass the “Rider”, “NewSeatId”, and “OldSeatId” into the function.
The “RiderFinishedChangingSeats” function will loop through all the current riders and send them an update that the specified rider has changed positions. How this signal is handled depends on how you implemented the IMountRider Interface function “OnChangedToNewSeatCompleted” function.
The second half of this function we will return to the AIController we setup earlier. If the seat we just moved from is the driver seat than we want to return control of the mount back over to the AI Controller to prevent “funny client side movement”. I use a sequence so that if any condition fails it will execute the next part of the sequence and return true no matter what.
First we check if the “Old Seat Id” sent is is 0 (our driver seat). If it is than we check if the AI Controller is valid. If it is Than we possess the mount. Because the AIControllerRef should not have any value on the client side we should not need to put a HasAuthority here, but I would still suggest doing so.
8.0 Setup Mount Seats
Return to Table of Contents
Now it is time to set up the Seats to your mount. The first thing we will do is make sure we have an appropriate socket that will act as the attachment point to our mount.
8.1 Setup Sockets
Open up the mesh that will represent your vehicle or mount. For both Skeletal Meshes or Static Meshes you will want to create a socket.
For the robot horse I have defined two sockets “s_DriverSeat” and “s_PassangerSeat” I have configured their rotation and position so that if I attach a character to them they will automatically be facing in the correct location.
The “s_DriverSeat” is attached to the “b_spline_03” bone. It has a Relative location of <0.0, -11.0, -20> and a relative rotation of <0.0, -34.0, -90>.
The “s_PassangerSeat” is attached to the “b_spine_02” bone. It has a relative location of <0.0, 2.0, 18.0> and a relative rotation of <0.0, 0.0, -90.0>.
Be aware that attempting to use the mannequin Mesh itself to orient your rider will not work for any mount because the rotation of the mannequin is -90 degrees around the Z axis (or Yaw). So while you can set up the socket preview using the mannequin Mesh you’ll need to rotate it -90 Degrees around the Z axis (Yaw) for it to be correct.
Honestly the socket locations and rotations I have setup were all 100% trial and Error. Because the Skeleton is an Asset type in UE4 you can actually change the socket positions and rotations and save the skeleton. Then get off and back on the mount and it will have updated the socket attachment so you can see the changes live without continuously starting and stopping Play in Editor (PIE).
8.2 Setup Seats
With the sockets defined we will now setup the available seats on the mount. Open up the mount you want to define seats for.
Select the “MountablePawnComponent” under the Component’s window. This should show you the details panel of the component. Look for the “Mounting” category and expand the “Seat Manager” property.
Within the Seat Manager this is an array called “Seats”. Add two seats by pressing the plus sign. We will be designating seat 0 as the driver seat and seat 1 as the passenger seat.
In the seat manager we want to ensure a few values are set for our Mount. The “Force Driver Seat” should be checked. This value enforces that the first seat taken should always be the driver seat. You can disable this if you want the closest seat to the player to take priority.
Then make sure “IsPossessableMount” is enabled. This must be set to true if you want your players to be able to drive the mount or vehicle. You can disable this if you just want your players to take a specific seat on the mount.
“Max Valid Mounting Distance Squared” represents the maximum distance that this mount can be from the mount for it to be considered valid for attempting to start the mounting process. Remember that this is the Squared distance. So by default it is set to 90000 which is 300 cm or 3 meters from the mount in any direction.
Now ensure that the “Driver Seat Id” property to 0. You should see the Driver Seat Index update as well.
Setup Driver Seat
Now expand element 0 of the Seats Array. It should have a “Seat Id” of 0. Set the “Seat Socket Name” to “s_DriverSeat”. The MountingData property is an array that describes how the seat can be attached to. Add Two elements to the Array and Expand it.
Set Driver Seat Position Data
Expand Element 0 of the Mounting Data array. Set the “Mount Position” to “Left Side”. Then set the “Relative Mounting Offset” to <30, -50, 0.0>. This should translate to 30 units of the mounts forward direction and 50 units to the left side of the mount.
The “Relative Mounting Offset” is a vector offset from the center location of the mount. It tells the mounting system a relative position from the center of the mount that a rider needs to be located at to start mounting. Generally this is the location provided to “MoveToMountingLocation” translated into world coordinates.
By enabling “Use Separate Offset for Dismounting” you can set a different offset for the position to detach the character onto and place the capsule at. Like “Relative Mounting Offset” the “Relative Dismounting Offset” is a relative location from the center of the mount actor.
On the horse we are allowing mounting to occur on both the right and left side of each seat. So now we need to setup the Right Side mounting. Expand the index 1 of the Mounting Data. Set the “Mount Position” to “Right Side” and set the “Relative Mounting Offset” to <30.0, 50.0, 0.0>. This should translate to 30 minutes toward the front of the mount and 50 units to the right of the mount.
Notice the “Any Side” value for the options. This is sort of an Omni mounting position, if there are no specific mounting points within a seat with one of the 6 relative directions than the system will attempt to retrieve an “Any” point as a last resort. You can use the “any” point for quick debugging if you don’t care about the relative direction the player is at to move toward a seat.
Setup the Passenger Seat
The seat at index 1 should have the “Seat Id” of 1 automatically. Set the “Seat Socket Name” to “s_PassangerSeat”.
Add two elements to the mounting data and expand them. The first element will be the left side so set the “Mount Position” to “Left Side”. Enter <-30, -50, 0> for the “Relative Mounting Offset. This should translate to 30 units behind the mount origin, and 50 units to the left of the mount origin.
The Second element should be the right side so set the “Mount Position” to “Right Side”. Enter <-30, 50, 0> which should translate to 30 units behind the mount origin and 50 units to the right of the mount origin.
9.0 Setup the Animation System
Return to Table of Contents
The final step we need is to setup our Animation System to support mounting our horse. Since this tutorial is not using any Anim Montages for getting on or off we only need to worry about the actual mounted pose. For a much more robust animation system where each mount has support for different mounting and dismounting animations for each seat as well as different mounted animations depending on the vehicle see the Final Project.
9.1 Event Graph
First thing I am going to do is duplicate the “ThirdPerson_AnimBP” and call it “ABP_MountingCharacter”.
Now Open up the APB_MountingCharacter. And double click on the EventGraph.
Create a new Bool variable and call it “IsSeated”.
For the most part we will simply be adding to the event animation graph. From the “TryGetPawnOwner” Drag a line off of it.
Search for the IsSeatedOnMount(Message) function.
Connect the execution line from the last node of the event graph to the IsSeatedOnMount function. Then Grab the IsSeated variable and set it to the value returned from the interface function.
That is all we have to do for the Event Graph
9.2 Anim Graph
Next we’ll setup the AnimGraph while this tutorial does not leverage the AnimMontages I thought It would be nice to at least prepare our AnimBP for the use of them.
Next you will need to go to the AnimGraph. I have renamed the State Machine to LocomotionStates. I suggest you do the same as I reference it later on.
Drag a line from the outline of the figure and in the search box select “New Saved Cached Pose…”
Name it “Locomotion”
Next right click and choose “Use cached pose ‘Locomotion’”
Now Drag the pose line out and search for the “Slot ‘DefaultSlot’” node.
This is the node you will always select in a search regardless of the actual animation slot you are using.
Then Drag the Defaut slot pose line to the OutputPose node.
That is all for setting up the Anim Graph.
9.3 Locomotion States
Now we will setup the Animation States for our Mount. I have a particular method I like to leverage but feel free to setup the Animation States however you see fit.
First thing to do is go into the Locomotion States State Machine graph. And move the Four nodes already in there up, we will keep these for later.
From the “Entry” node draw out the execution line and create a new State called “OnGroundStates” Then Create a second transition and State called “OnMountedStates”. Finally create a transition from the “OnMountedStates” to the “OnGroundStates” states.
This should have the original 4 states and transitions disconnected from the entry. You can leave them here for now or “Cut” or “Copy” them into your computer’s copy buffer.
[Image of OnGroundStates]
Inside the OnGroundStates State right click and create a new State Machine and call it “GroundStates”. Connect the GroundStates pose pin to the Output Animation Pose node.
First go back to the top level of “LocomotionStates” and Cut the four disconnected states of “Idle/Run”, “JumpStart”, “JumpLoop”, and “JumpEnd”.
Then Go back to “OnGroundStates” and into the “GroundStates” State Machine.
Paste the Four copied States into this state machine.
Now our basic movement state machine should work perfectly fine while we are on the ground.
Now to back to the “LocomotionStates” and select the “OnMountedStates” State. We will simply play the “A_Mounted” state while mounted.
Now our States are finished and we need to setup the transitions.
[Image of GroundToSeatedTransition]
Double click on the Transition that is pointing from the “OnGroundStates” toward the “OnMountedSeats” States. We want our animation system to transition to this state if we are seated on a mount.
Grab the IsSeated variable we created and connect it directly into the “Can Enter Transiton” node.
[Image of SeatedToGroundTransition]
Now go back to the “LocomotionStates” and double click on the transition that is pointing from the “OnMountedSeats” toward the “OnGroundStates” states. We want our animation system to transition back to the default ground movement when our character is no longer seated.
Grab the IsSeated variable we created and then drag it out. Search for “NOT boolean” to get the “NOT” node. Then drag that into the “Can Enter Transition” node.
Congratulations our Aniation System is setup and ready to go.
10.0 Setup Completed
Return to Table of Contents
And that completes the basic setup for the seats and the entire mounting system. At this point you are finished with the setup. But running your game right now without an interaction system to start the mounting, dismounting, and seat changing procedures will not get you very far. If you already have your own interaction system then you can simply hook up the mounting system into that and be sure to call the appropriate functions.
If you followed this tutorial to the letter then that means your interaction system will need to call the Controller’s IADMUnifiedPawnController Interface function PrepareToMount passing the desired mount into it as a parameter. To Dismount you’ll need to call the IADMUnifiedPawnController interface function PrepareToDismount and pass the current mount to it as a parameter.
If you didn’t follow the tutorial exactly than do not worry, the real magic of the system actually starts with the Controller’s RiderControllerComponent’s function “PerformMountPawn” for starting the mounting procedure, you just need to supply the mount you want to mount to it as a parameter. For dismounting the real magic lies in the Controller’s RiderControllerComponent’s function “PerformDismountPawn”, again passing the current mount into it for dismounting.
You can continue to set up a basic interaction system by following the next link below.
10.1 Documentation
I would like to thank you for purchasing and using this product that I have spent an extraordinary amount of time building, perfecting, and enhancing over the last year. If you have any questions feel free to use my contact page to direct questions to me.
For those who have purchased the server you can access additional documentation from the “Documentation” link found in the Plugin Description. There you will also gain access to a link to my Discord Server where you can directly message me and talk to others who are using the Mounting System.