A Basic Interaction System
Welcome to the somewhat final leg of the Mounting System Tutorial. Here I will show you how to setup a very basic interaction system just so you can get started using the mounting system in your game, should you not have an interaction system of your own designed and developed.
1.0 Collision Setup
For our mounting system and our Interaction system we will be changing some of the UE4 default collision presets. This will solve two problems. The first is in its default state a mounted passenger’s camera will be blocked by the mount’s capsule and mesh components causing it to be trapped usually inside the mesh or center of the mount. The Second is it will allow our visibility trace to hit the mesh component of our mount.
So there are other ways of doing this but for demonstration purposes this is the easiest way to do it. You could create a whole new Preset just for your mounts, you could create a new Object Channel or Trace Channel. But getting into the details of setting that up is beyond the scope of this tutorial and this plugin. It is very dependent upon the type of game you want to make.
Go to Edit / Project Settings.
Then go to Engine / Collision Settings.
Open the “Preset” tab. The ones we will be most interested in are “Pawn” and “Character Mesh”.
Double click on the “Pawn” Preset and and change the Visibility and Camera settings to ignore. That’s it, Now all objects with this collision preset will now ignore the Camera and Visibility trace types. Why? Because this preset is used for the capsule component and we want our whole character mesh to be what is interactable. It will also prevent the camera for passengers from being stuck inside the mount capsule and allow it to freely rotate as normal.
Double click on “Character Mesh” preset. We want to set it up as the image by setting the camera trace value to ignore. This preset is used by the Character’s Mesh Component and will prevent the mount's mesh from interfering with passenger cameras.
2.0 Interface Setup
First we need to setup our blueprint interface that will be used for interactions.
2.1 Create the Interface
First we need to create the interface which will be a Blueprint Interface.
In the MountingContent/Blueprints folder create a new Blueprint Interface and call it “BPI_InteractableActor”.
This interface will be implemented by any actor in the game that can be interacted with.
2.2 Setup Functions
Now we will setup each of the functions this interface will supply. All functions will have the category "BPI Interactable Actor"
|Call to initiatie interactions something in the world.|
|Gets flag indicating the actor or object is an interactable object|
|Called when a linked actor passes the interaction through to it's master actor|
3.0 Controller Setup
The primary functions of our interaction system will be held in our PlayerController. I prefer to put such systems in the player controller because that allows us to customize the interaction systems differently for Players and AI. Players tend to interact with things they are immediately focused on while the AI tends to need to collect data around them and then decide on what to interact with.
3.1 Setup Variables
Open up the “BP_MountingPlayerController”.
First thing I always do is create an InputGraph. I like to keep my graphs separate because they can become very cluttered very quickly. If you separate the graphs into different purposes it makes things easier when working with a team.
Create a new Graph called “InputGraph” there should already be an “EventGraph” by default. If it is not already there I highly suggest you create a third called “RpcGraph” that will hold our RPC events we will need to send to the server or client.
Now Create a new Variable of type Actor and name it “FocusedActor”. This variable will be used to hold the current actor that our pawn is looking at.
3.2 Create Function Stubs
Now we will create a few function stubs we will implement later because many of them are dependent on other functions we will need to define.
3.2.1 On Interaction Pressed
This function will be called by our input system to indicate that an interaction was pressed.
3.2.2 Trace For Interactable
This function will be used on tick or a set interval to perform a trace to see if anything is in front of the player to interact with
3.2.3 Interact With Focused Actor
This function is called to start interaction with the currently focused actor
This function will be called by our input system to indicate that an interaction was pressed.
3.2.5 Change Seats
This function is called to start the character changing seats on their current mount.
Call this funciton when you want the player to mount to a specific seat..
3.3 Create RPC Functions
Double click on the RpcGraph and open it. We will create three custom Events to support the mounting system. In order to execute mounting, dismounting, and seat changing commands we need to send our functions to the server to start the process.
Create the first custom event and name it SERVER_InteractWithFocusedActor.
Add a parameter of the Actor type and call it “InteractableActor”.
Now Drag the “InteractWithFocusedActor” function we created under the “Interaction” category and connect the execution line to it. Then connect the parameter.
3.4 Implement Functions
Now we will implement the stub functions we created earlier
3.4.1 Implement Trace For Interactable
We will now implement the TraceForInteractable function. For Sanity sake I’m simply going to link the code from BlueprintUE rather than attempt to create a picture for it all.
We want to return true or false if we succeed in hitting something or fail in hitting something. So we’ll create an output variable for the “TraceForInteractable” function.
In brevity this function checks if the character is currently mounted.
If it is not mounted it performs a line trace by the visibility channel. It first gets the current pawns location and adds 90 units on the Z axis to simulate the location of the eyes of the character. As the blueprint explains this can be different from pawn to pawn but adjusting this is outside the scope of this tutorial. This value gets set as the Starting point of the line trace. Then we get the rotation of the controller and transform that into a forward unit vector. It multiplies that unit vector by 300 units giving it a length of 300. Finally we add that to the start position of the trace to get the end point of the line.
We then check if the line trace hit something. If it did we retrieve the hit actor and call the BPI_InteractableActor function “IsInteractable”. If this is an interactable actor than it will return true, so long as we implement this function to do so.
If we have detected an interactable actor than we set it to the “FocusedActor” variable we setup earlier. If we do not detect an actor then we clear the “FocusedActor” variable.
Going back to the test for if the current pawn is mounted. On the True Execution line we we want to make sure that we currently have no FocusActor Referenced. So we use a Validated Get to test if it has a reference to something and if it does we clear that reference, other wise we return false.
3.4.2 Implement On Interaction Pressed
We will now implement the OnInteractionPressed function. A link to copy and paste the code from BlueprintUE is available.
We’ll briefly go over how this function works. First we determine if our character is currently mounted or not.
If we are not currently mounted than the false execution branch tests if we currently have a “focused actor”. If we do have a focused actor than we simply pass it through to the “InteractWithFocusedActor” function and return success. If we do not have a focused actor than we return false.
If we are currently mounted than the true execution branch gets the Current Character Pawn and tests if it is fully seated on the mount.
If we are not seated on the mount than we invalidate the input and ignore it. If we are seated on the mount than we call the “Dismount” function we created under the Mounting category and return true.
3.4.3 Implement Interact With Focused Actor
Now we implement the InteractWithFocusedActor function. A link to copy and paste the content of this function is available via Blueprint UE
Start checking that the supplied parameter “InteractableActor” is valid. Then use the build in UE4 BP macro “Switch Has Authority”. If this is the Authority Than we want to call the BPI_InteractableActor function “Interact” which will have the (Message) text text to it. We want the “target” of that function to be the “InteractableActor” which should be our potential mount. Then we want the “Instigating Actor” to be our controller, which we’ll pass a reference to “self” in.
If this is not the Authority then we want to call our Server function “SERVER_InteractWithFocusedActor” and we’ll pass our desired focused actor into it as a parameter up to the server. When “SERVER_InteractWithFocusedActor” is called on the server it will simply call this function but because it is already on the authority it will pass through to the Interact logic in the Authority execution line.
3.4.4 Implement Dismount
We will call this funciton when we need to perform a dismount action.
With the Rider Controller's property "Enable Action Rpcs" enabled all we have to do is find the interface function "Begin Dismounting Actor" and add it to the graph.
Connect the output value of the "BeginDismountingActor" function to the return value of this functon.
3.4.5 Implement Change Seats
We will call this function to make our character change seats while mounted.
To implement we search for the function "Begin Changing Seat By Id" and add it to our graph.
Connect the input variable "New Seat Id" to the input variable "Seat Id" of the "Being Changing Seat by Id" function.
Connect the output variable "Return Value" to the return node.
3.4.6 Mount To Seat
We will call this function when we want our player to mount directly to a desired seat.
To implement this function we place a get node for the "RiderControllerComponent" on the graph.
Draw a line from the "RiderControllerComponent" and look for the function "IsMounted".
Place a Branch on the graph and connect it ot starting node execution line.
Connect the output of "Is Mounted" to the "Condition" parameter of the "Branch" node.
We will ignore the True execution line of the branch since we do not want players to mount while already mounted, they should change seats.
Plae a get node on the graph for the "Focused Actor" variable and convert it to a "validated get".
Connect the False execution line of the Branch to the Validated Get Node.
Right click on the graph and search for the function "Begin Mounting Actor To Seat" and select it.
Connect the output of the validated get node "Focused Actor" to the input "New Mount".
Ignore the "Linked Actor" node.
Palce a get node for "Seat Id" which is the input parameter supplied by this function and connect it to "Seat Id" input parameter of the "Begin Mounting Actor To Seat" function.
3.5 Execute Interactions
In the Event Graph we will call our TraceForInteractable on tick as shown in the image. For demonstration purposes I’m not going to bother adding any optimizations such as not doing this on the server.
Go to the input graph and in there right click and search for the “E Key”. If you already have an Input Setup for this by all means use that but again for demonstration i’m going to hard wire this to E. From the “Pressed” execution line drag it out and call “OnInteractionPressed”.
We will bind the number 1 and 2 keys to our seat changing functions. We will set the 1 key to be our driver seat change and the 2 key to be our passenger seat change. This setup is easily expanded to more seats.
4.0 Setup the Mount
Now we must set up our Mount for interaction. Open up your mount, in this tutorial I am using the “BP_Horse”.
We want to add our “BPI_InteractableActor” interface to our mount.
Press the “Add” button in the Interfaces list on the details panel and find our “BPI_InteractableActor” interface.
Now under the Interfaces list in the Blueprint Panel expand “BPI Interactable Actor”. Double click on “Interact” function.
We will implement this very simply. For our interaction system the Instigating actor is our controller. But since this is an generic interaction system we do not know this for sure so we’ll call “GetCharacterControlller” from the instigating actor. Now that we know we have a controller we’ll check that it is a Valid object. Finally we will call “PrepareToMount” as a function message with the target set to the Controller and the “Mount or Rider” parameter set to “self” which is our mount. Then we return true for success.
4.2 Is Interactable
Now implement the IsInteractable function. We are simply going to return true for this function. Though you could set up any bit of logic you want such as setting this to false if the mount is full.
Well that is it, our interaction system for mounting is setup and ready to go. You can now run the game and interact with your mount and ride it around.