Basic Interaction System (PNMS 2.3)

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.

Collision Panel
Fig 1.1 Collision Panel

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”.

Change Pawn Collision
Fig 1.2 Change Pawn Collision

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.

Change Character Mesh Collision
Fig 1.3 Change Character Mesh Collision

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.

BPI Interactable Actor
Fig 2.1 Create BPI Interactable Actor

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"

BPI Interactable Actor
Fig 2.2 BPI Interactable Actor
Function Name Input/Output Type Name
Interact Input Actor InstigatingActor
  Output Boolean Success
  Call to initiatie interactions something in the world.
       
IsInteractable Output Boolean IsInteractable
  Gets flag indicating the actor or object is an interactable object
       
InteractFromLinkedActor Input Actor InstigatingActor
  Input Actor LinkdActor
  Output Boolean Success
  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

Blueprint Graphs
Fig 3.1 Blueprint Graphs

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.

Create Focused Actor
Fig 3.1.2 Create Focus Actor

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.

Controller Function Stubs
Fig 3.2.0.1 Controller Function Stubs

3.2.1 On Interaction Pressed

This function will be called by our input system to indicate that an interaction was pressed.

On Interaction Pressed
Fig 3.2.1.1 On Interaction Pressed
Input/Output Type Name
Input Actor Interactable Actor
 

 

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

Trace for Interactable
Fig 3.2.2.1 Trace for Interactable
Input/Output Type Name
Output Boolean FoundMountableActor
 

3.2.3 Interact With Focused Actor

This function is called to start interaction with the currently focused actor

[IMAGE: InteractWithFocusedActor]

Interact with focused actor
Fig 3.2.3.1 Interact with focused actor
Input/Output Type Name
Input Actor Interactable Actor
 

3.2.4 Dismount

This function will be called by our input system to indicate that an interaction was pressed.

Dismount
Fig 3.2.4.1 Dismount
Input/Output Type Name
Output Boolean Success
 

3.2.5 Change Seats

This function is called to start the character changing seats on their current mount.

Change Seats
Fig 3.2.5.1 Change SEats
Input/Output Type Name
Input integer NewSeatId
Output Boolean Success
 

3.2.6 MountToSeat

Call this funciton when you want the player to mount to a specific seat..

[IMAGE: MountToSeat]

Mount Seat
Fig 3.2.6.1 Mount To Seats
Input/Output Type Name
Input integer SeatId
 

 

3.3 Create RPC Functions

Interact RPC
Fig 3.3.1 Interact RPC

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.

Trace For Interactables
Fig 3.4.1.1 Trace For Interactables

Pastebin: Trace for Interactable

Trace For Interactables
Fig 3.4.1.2 Trace For Interactables

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. 

Trace For Interactables
Fig 3.4.1.3 Trace For Interactables

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.

Trace For Interactables
Fig 3.4.1.4 Trace For Interactables

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.

Trace For Interactables
Fig 3.4.1.5 Trace For Interactables

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.

Trace For Interactables
Fig 3.4.1.6 Trace For Interactables

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.

Pastebin: On Interaction Pressed

On Interaction Pressed
Fig 3.4.2.1 On Interaction Pressed
On Interaction Pressed
Fig 3.4.2.2 On Interaction Pressed

We’ll briefly go over how this function works.  First we determine if our character is currently mounted or not.

On Interaction Pressed
Fig 3.4.2.3 On Interaction Pressed

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.

On Interaction Pressed
Fig 3.4.2.4 On Interaction Pressed

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. 

On Interaction Pressed
Fig 3.4.2.5 On Interaction Pressed

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

Pastebin: Interact With Focused Actor

Interact with Focused Actor
Fig 3.4.3.1 Interact With Focused Actor

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.

Dismount
Fig 3.4.4.1 Dismount

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.

Change Seats
Fig 3.4.5.1 Chanage Seats

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.

Mount to Seat
Fig 3.4.6.1 Mount To 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

Trace Each Tick
Fig 3.5.1 Trace Each Tick

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.

E Key for Interaction
Fig 3.5.2 E Key for Interaction

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”.

Seat Key Input
Fig 3.5.3 Seat Key Input

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”.

Mount Class Settings
Fig 4.0.1 Mount Class Settings

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.

4.1 Interact

PasteBin: Interact Function

Interact Function
Fig 4.1.1 Interact Function

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

Is Interactable
Fig 31 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.

Finished

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.