Being able to interact in a world gives
to the game another level of perspective. Interaction system lets the player use
things such as door, pick up items, talk to NPCs or receive quests from them, loot
and much more… Essentially, it brings life into the game. So, let’s create an interaction system. We have freshly created project out of the Third Person Template with Starter Content.
First thing – let’s create widely used function (which you might already know) called Raycast.
And because I might use it later in other different classes, let’s
create it in function library, which let us call functions in it from any class.
Create new folder and name it Libraries, because I will probably create
more than one function library. Right-click, and under Blueprint, select blueprint
function library which I name Tracing and open it. Name automatically created function Raycast.
Add “Line Trace By Channel” which will execute right after calling this function
and leave space for calculation. Now we add Input parameters.
First one is StartPoint which is Vector type. This represents point from which the line is traced.
Second one is Rotation of Rotator type, which tells the direction of tracing.
And the last one is TraceDistance of Float type, which indicates how long the line will be.
Connect StartPoint to Start and create Reroute Node by double-click. Drag out Rotation and search
for Get Forward Vector which magnitude is 1, so out of it search for Multiply and multiply
it with Trace Distance. Multiplied vector would currently start at world origine which is 0,
so we move it by Adding to it Start Point vector. We can also add some input parameters of line
trace as input parameters of Raycast function, but this is up to you.
I might use Actors to Ignore, but I definitely use Draw Debug Type and Draw Time.
Move to the end of line trace and add Return node. Drag into it Out Hit and
Return Value and hit compile. I also sometimes forget to setup values, so I set
default values for Draw Time and Trace Distance. Now let’s implement it to the
blueprint of player character. Go to ThirdPerson -> Blueprints
and open BP_ThirdPersonCharacter. First, I just change two things in the viewport.
I want to have clear view on the object I am looking at,
so move Camera Boom to 100 units on the Z-axis and set Target Arm Length to 200.
Switch to Event Graph and move down under default events. Here, create Custom Event which I
name “LoopForInfo” and add Raycast function. Drag in Camera Boom and out of it search for Get
World Location and connect it into Start Point. Now drag in Follow Camera, search for Get
World Rotation and connect it into Rotation. Trace Distance is up to you, I go with 500.
I change Draw Debug Type to “For Duration” and leave Draw Time at 1,
so we can see that it works. After Raycast add Delay with duration of 0,1
and create infinite loop…at last for now. Function is done for now, but we also need to make
the initial call. Go up to Event BeginPlay and to the end add call to LoopForInfo.
Hit Compile and test it. You can see that line starts above the head and
it takes rotation of camera and not the character, just as we wanted.
Now, let’s create some UI. Go to Content folder and create new folder Widgets.
I always go with Azure color for Widgets. In it create new widget.
First, I'll create a bordered box that I'll use across multiple UI elements,
so the early design is consistent. I name it A_BorderedBox. I will show
you later, why I used prefix A. Open it and dock it. First, add Border – this
size doesn’t matter, so we don’t need to adjust scale. Under “Draw As” select Rounded Box.
Rounding Type change to Fixed Radius and all Corner Radiuses set to 25.
Set width to 5. Set the colors which suit your game best. I
set outline to black color and alpha to 1. I set Tint to slightly above black (you
can see exact number on the screen) and set alpha to 0,6 so it’s slightly
transparent, but not too much. If we want to use this widget in another one, now
it can’t have any child component…which we want. For this usage add Named Slot. Name of it is text
which will appear when this component has no child and you can use it to remember what you want to
do with it later, without opening this blueprint, so we can rename it to something like
Add Item. Set Padding to 0 for now. As you can see padding is value which have
both components the same. Now hit compile. Create new widget WBP_HUD and open it. Add
canvas which represents player’s screen. First, I want to add small middle point, so
players could aim exact object to which they want to interact with. Add Image, rename it to
IMG_CenterPoint and change anchor to center. Set both positions to 0 and alignments to 0.5, so
the center of image is in the center of screen. Size is up to you; I go with 4. Set “Draw
As” to “Rounded Box” and add Width a bit, so you can see we got a little circle. Later, for
example, you could change its color when aiming to interactable object or enemy, if you want.
When you scroll down your Palette, under User Created you can see why I used
prefix “A_”- so widgets made by me are the first ones. So, drag our Bordered Box in.
Set anchor to middle and set X alignment to 0.5, so when both positions are 0,
it touches center point with its top line. Size doesn’t matter. Change Position Y, so there
is a space between Center Point and our Box. I go with 150, but this can change later on in
development process with adding more UI elements. Add to the slot “Add Item” “Text Block”. We
could set size of the box to fixed value, but I don’t know how much text I
will be showing in it in the future, so click to Bordered Box and check “Size To
Content”. Also don’t forget to rename text block. I name it TB_InteractableText and check Is
Variable, so we can add to it some logic later. You can see that text is out of the box
because we removed padding. If you have more than one monitor drag Default Bordered
Box there or just undock it so you can see text in HUD and you can also change padding.
When you change value, you must hit compile, otherwise you won’t see any changes. I
want more space on the left and right than on the top and bottom, so I go 20 for
left and right and 10 for top and bottom. Set what values you feel like look the best.
When we write some two-line text to test it, you can see, that the box is changing its
size appropriately, but I will also change Justification to center.
Now go to the Graph. Create new function which I name
TryShowInteractableInfoText. Add two input parameters. The first one name “Show?”
and leave it as Boolean. Second parameter name TextToShow and you can choose string or
text, both have pros and cons. I go with Text. Add Branch which Condition is “Show?”.
If we want to show the text, we must set it to text block, so drag in TB_InteractableText,
out of it search for Set Text…those two do the same functionality, so choose one of them.
Connect it after True and “In Text” connect with Text to Show. When the text is set, we
want to show it. So, drag in A_BorderedBox, out of it search for Set Visibility and leave
visibility as Visible. Duplicate it bellow, connect Target, change it to Hidden and
execute it, when result of branch is False. I also set default visibility to Hidden, but
our approach solves it, so you don’t need to. Now back to BP_ThirdPersonCharacter. Move
Loop for Info and disconnect it. First, we must create HUD, so add node Create
Widget. As Class select WBP_HUD. Promote Return Value to variable and name it HUD.
Out of right pin, search for Add To Viewport and after it finally execute LoopForInfo again.
Because here is nothing to change in the future, we can clean it up a bit. Select all three
new nodes, right-click to one of them and select Collapse Nodes and name it Set Up HUD.
Now move back to LoopForInfo. Move Delay to right and drag in reference to HUD. Out of it
search our function TryShowInteractableInfoText and add it in. Connect it before Delay and for
now we want just to test that it works properly so connect Return value of Raycast to Show?. Drag
out Out Hit and select Break Hit Result. Here we can see all information we get out of Raycast
function, but for now I just want to show some text, so I connect Location to Text To Show…it
automatically makes conversion…and we’re ready to test. Hit Compile and hit Play. You can see,
that when we don’t hit anything, nothing shows up. When we hit anything, text shows up. And when
we stop hitting any object, text is hidden again. We have interaction system done (almost), now
let’s create interactable objects. Go to Content folder and create new folder “Interfaces”. In it
create Blueprint interface. Again, you can add prefix BI or I, but I name it just Interactable.
Right after you open it, new function is waiting, so name it ShowInteractableInformation.
Add input parameter, name it HitComponent and change its type to Primitive Component.
Add output parameter, name it “Show?” and change its type to Boolean.
Add another Output parameter, name it “TextToShow” and change it to Text.
Add another function and name it Interact. Add Input parameter and as in the
previous function, name it HitComponent and change its type to Primitive Component.
Hit Compile and go to BP_ThirdPersonCharacter. Here, move those nodes to
right and delete conversion. After Raycast add call to function
ShowInteractableInformation of our new interface. Connect its output pins the
ones with the same name. As For Input parameters, connect Hit Component
of Break Hit Result with Hit Component, and Hit Actor is the Target. And here
you can see our completed function. It would be also good to be able to make interaction with another
object. So, move down a bit. We’ll be using Enhanced Input
System later in this series. For now, just search key and add one you
want to use for interaction. I use E key. Now, go up to LoopForInfo, copy all Raycast
related nodes and paste it down to E key event. Connect Pressed to Raycast. After Raycast
add call to function Interact and as before, connect Hit Actor of Break Hit Result to
Target and Hit Component with Hit Component. Now I quicky show you how to create
basic interactable objects and how to interact with them. Later in this
video we’ll be making propre ones. I just quickly create new folder for just
testing stuff and in it I create testing actor. In order for this actor to
be an interactive object, it must implement our interface Interactable.
You do it by going to Class Settings and under section Interfaces you have drop down menu Add.
Here you can see all interfaces this actor can implement so you can search for Interactable
and here you can see it. When you add it, you can see,
that on the left side was added functions of the interface.
I just add some mesh and you can implement those functions by double-clicking to them.
Here you can implement whatever logic you want. Function “Show Interactable Information”
will be used for showing to player text of what will the interaction do, and
function Interact will execute the logic. Here you can see that I created basic cube
which after pressing E key changes its state. I also forget turn off visibility of
Raycast, so set Draw Debug Type to None if you have it as I do.
But what if we want to interact just with part of the actor?
For this functionality create function in library Tracing named CompareComponents.
It doesn’t do any tracing, but I will us it only with it, so it’s ok…I guess.
Add two input parameters. First one is Hit Component which is Primitive Component.
Second one name BP Components which will be more Primitive Components,
so change it from Single to Array. BP Components will be a set of parts
of the blueprint, we want to interact with. Add For Each Loop. To Array connect BP Components.
Out of Array Element search for Equal and compare it with Hit Component.
To Loop Body add branch and to Condition connect result of Equal node.
If we found searched component we can stop looping, so after True add Return Node.
As the result of this function, we want to get, which component out of the
array is the one we want, so take Array Index and connect it to Return Node.
If this isn’t the part of blueprint we are looking for, we want to continue to go through Array,
so leave False statement blank. If we went through whole Array and there wasn’t
the searched component, we want to know as well. So, add Return Node after Completed and set Array
Index to -1, which we can’t get out of array. We don’t change any values in this function, only
getting one, so also check this function as Pure, which removes Execution pins that we don’t need.
Now let’s see how you can use it. I add a few basic mashes to blueprint
- Cube, Sphere and Plane. I add them after Event BeginPlay, Make Array
out of them and I promote it to variable. You can see, that Unreal
recognized they are static mashes, but because they are part of blueprint now, they
are as well Primitive components at the same time. Because approach will be the same for both
functions of interface, I just change displayed information. First, I add Compare Components
and connect into it the array of our objects. Out of Array Index Search for Switch on
Int and execute it after function starts. I add pins for each object and connect
them to appropriate Return Node. Default pin is for each number which isn’t added
as separate pin, so it’s for all negative and higher numbers. We want Return Node for
all possibilities, so add Return Node to Default pin and just uncheck “Show?”.
When we test it, you can see, that when I aim to base, nothing shows up,
and for each mesh is displayed appropriate text even it is one actor.
Now, let’s create propre interactable item. Good example is one you use in your life
in daily basis. I am talking about door. So, we’ll be creating sliding door and to make
it more interesting, it will be opened with lever. But because we don’t have 3d model of
it let’s go into Blender and quickly model it. If you want to follow my steps, just make sure
in preferences, under Input, you have checked “Emulate 3 Button Mouse“. This option let you
select connected parts by double-clicking. First, let’s create the door and frame in which
the door will be set. Shift+A, Mesh and add Cube. Open detail panel by clicking to the arrow here,
or by pressing N key, and set size of the door. I set X to 5, Y to 0.5 and Z to 3.
Switch to Edit Mode, press 3 for selecting faces and select bottom face.
Shift+S, Cursor to Selected. Switch to Object mode, right-click on the door, Set Origin
and select Origin to 3D Cursor. Shift+S and Cursor to World Origin. Shift+S,
Selection to Cursor. Ctrl+A for Apply and select All Transforms.
Now it’s positioned right and set for future exporting to Unreal.
Switch to Edit Mode and add 10 cm which is 0.1 to all narrow faces. So, select face,
press G for Move, lock axis (in this case by pressing Z or X) and write 0.1 (positive
or negative). Or after selecting a face, change appropriate value of Median.
Now the door is done for now, so duplicate it by pressing Shift+D and right-click.
One object rename to Door (I add _01), the second one rename to DoorFrame and
hide the Door. Select the large faces, press I for Inset, scale it down a
bit and press 2 for selecting edges. Select two top lines and set Z in
median to 3. Bottom ones set to 0. For side lines set X to 2.5 and “-2.5”.
Select middle faces on both sides, press X for Delete and select Faces.
Now we got groove in which the door will slide. Because this will be the inside part that
you can see, normals are wrong. You can check them by clicking here and turning on their visibility.
Those blue lines show direction of normal. In Unreal it would be transparent if you wouldn’t use
two-sided material. To fix it select all faces, Alt+N and select Recalculate Inside.
Turn off displaying normals. Select inner edges, E for extrude and right click.
Since thickness of the door is 50 cm, I decided that the door frame will be thick 1 meter,
so set Y to “-.5”. E for extrude, right-click, S for Scale and scale it up a bit.
Repeat the same process for the other side. Select both edges on one side and set X to 4 and -4.
To top edges set Z value to “3.5”. Bottom edges just have to be lover that the groove is,
so set Z value to “-0.2”. Now let’s finish it, so while you have selected two opposite edges,
press F for Fill. All you have to do now is select one edge facing into the blank space
and press F key 3 times. Because we fixed normals earlier, all new faces have correct orientation.
Why did I make the groove? When the door will be sliding it looks a bit better and
because the groove goes to all sides, the door can move to all sides as well.
I just select outer part of groove and hit Ctrl+B for bevel tool to lower
sharpness…and I do the same thing for the door. Now the door and door frame are done, so hide
them. And let’s create the lever and its frame. First let’s create the frame. Shift+A -> Mesh
-> Cylinder. Open details of added object. I want it more rounded, so set vertices to 64,
Radius set to “0.25” and Depth set to “0.2”. Proportions look alright, so continue. R for
Rotation, Y for locking axis and write 90. Ctrl+A and Apply All Transforms.
Switch to Edit Mode and now we create a groove in which the lever will be moving.
Select all faces except those two side circular ones. I for Inset. 10
cm groove looks too much to me. 6 cm looks good, so it’s 0.03 for both sides.
Select side faces and remove them. Press 3 on Numpad, turn ON X-Ray and
select all vertices bellow green line. Press X and remove vertices. Select all
vertices on one side and press F to Fill. Do it for the other side
and for bottom side as well. Now we have to decide how large
the groove is going to be. The fifth square looks like the best place to
start so select it. Press Numpad 1 for front view, turn ON X-Ray, select all squares from top to
the selected one, press X and delete those faces. Press one to switch to selecting vertices,
select all inner vertices on one side, press F to Fill and repeat
for the other side. Select inner square and fill it as well.
E for Extrude and right-click. S for Scale, Y for locking axis and scale
it down so that there is a bit of flat area. E for Extrude and push it down.
Select inner edges and add Bevel by Ctrl+B so edges are not that sharp.
I write 0.001 and do the same process for outer edges, except the bottom ones.
I also turn on Auto Smooth so it’s smoother. Rename the object to LeverFrame
and move to the lever itself. Shift+A, Mesh and add Cylinder.
Press R and Y and rotate it by 90 degrees. Ctrl+A and Apply Transforms.
Numpad 3 to side view, turn ON X-Ray and switch Viewport to Wireframe.
S for Scale and scale it down, so it’s smaller than the flat area on sides,
and its larger than bottom of the cavity. Numpad 7 to top view and scale it along X axis,
so it’s slightly thinner than the groove is. Select all side edges, Ctrl+B for
Bevel tool and I use value “0.01”, so now the wheel will be visible at a glance.
Shift+A and add Cylinder. Numpad 7 to top view, turn ON X-Ray,
S for Scale and scale the cylinder down, so it’s smaller or same size as unbeveled
part of the wheel. Numpad 3 to side view, G for Move, Z to lock Z axis and place it,
so top of it is above top of the wheel. Adjust height if needed and Ctrl+B for
Bevel so there is smooth transition to rod. Select middle face, E for extrude and
drag it up. Median Z “0.35” works for me. E for Extrude and right-click.
Numpad 7 for top view, S for scale and I make it the same size as the base part.
Numpad 3 for side view, E for extrude and set Z Median to “0.6” so the handle is pretty big.
Select top circle and outer edge of handle. Ctrl+B and bevel these edges.
Rename it to Lever and you can also add Auto Smooth.
For now, we will be using Unreal default materials. So, make
all objects we’ve done visible. While you’re in Object mode, press A to select
all objects and switch to UV Editing tab. Hover over right side and press A to select All
faces. Move your cursor to left side and press A to select all as well. Go to UV, Unwrap and select
Cube Projection. Expand Details and set Cube Size to 1. This way, all default materials in Unreal
will look the same size and I find this approach the best for prototyping with materials.
Last is exporting of these objects to Unreal. You can export them as one file,
but I export door and lever separately. So, I select Door and Frame. Now go to File, Export,
and select FBX. Name it appropriately, check Selected Objects and hit Export FBX and I
repeat the process for lever as well. Before we leave Blender, I also create new collections for
Door and Lever and move into them those objects, so when I make another 3d model, I can make it
here and I can turn ON/OFF visibility of already created objects for example for size comparison.
Save your Blender file and back to Unreal Engine. I create new folder and name it just Props. Drag
in “.fbx” files, select Do Not Create Materials and click to Import All.
Now open all imported static meshes and the first, we want to add to
them materials. So, open content browser, go to Starter Content and open Materials. For
door I like Sandstone material, so I click to it and by clicking to this icon of left going arrow,
you assign selected material to a material slot, without needing to drag them into it or repeatedly
searching for it. So, assign it to the door frame and door. You can use some metallic material to
lever and lever frame, but I like Rock Basalt. The second thing we need to do is changing
collisions. Automatic Collisions create the simplest convex collisions, so now you are
not able go through the door frame. For low poly objects (such is the door frame) just scroll
down in details to Collision section and change Collision Complexity to Use Complex As Simple. For
higher poly objects is better to create collisions in Blender or add Colliders in blueprint.
I do the same change for Lever. Other Objects are OK, so you can close those tabs. Go
to Props folder and create new blueprint class of Actor. Name it BP_Door and open
it. This will be a parent class to all doors we can use and will contains generic
functionalities that all doors should have. But what are these functionalities? For me it is
capability to open or close and toggle between those states, and capability to lock or unlock.
I also want to know if the door is in motion (opening or closing) and in what state the door is
currently in. We use inheritance, so no matter how we implement those functions, we can always just
cast and call parent function. So, let’s do it. Go to Event Graph and add Custom
Events. Name them Open, Close, Toggle and Close&Lock. You can add Unlock&Open and
implement it by yourself. I will add it later. Now add variables. First one is IsOpen
of Boolean type. Second one I name Opening/Closing of Boolean type. And the third
one name IsLocked and it’s Boolean type again. Variable IsOpen indicates state of the
door. If it’s true, the door is opened and if it’s false, the door is closed.
Variable Opening/Closing indicates if the door is in process of Opening or Closing.
In other words, if the door is moving. And IsLocked indicates if
the player can Open the door. Events Open and Close will manage the door
animation and changing variables. But Toggle will be the one we will be calling the most,
because if the door is closed, we don’t want to close it again, we want to open it!
And Close&Lock event can be used, e.g. when the player enters the boss area, this function
will be called, and the player can’t escape. Now to the door controller. Open content browser
and create new blueprint of Actor class. Name it BP_DoorOpener and open it. Go to Event Graph
and add one custom event “Use” that will contain animation and call the door function Toggle. Add
variable InUse of Boolean type, which fulfills the same logic as Opening/Closing in Door blueprint.
Add another variable, name it Door, and change its type to BP_Door. Lastly, go to Class Settings and
add interface Interactable. Finally, hit Compile. Open Content Browser, right-click
to BP_DoorOpener and select Create Child Blueprint Class. I name it BP_Lever_01.
Also, you can rename imported Static Meshes, if you haven’t already – I just remove name of
the fbx file. Now, open BP_Lever_01 and drag in lever and its frame. The lever looks good, but it
could be unnecessary hard for player to interact with it, because it’s thin. We can solve it by
selecting the Lever, clicking to Add button, and adding Capsule Collider. Now, just rename
it to LeverCollider, adjust location and size. Because this collider is only for interaction,
scroll down and under Collision select Custom. Change all to Collision Responses to
Ignore, but Trace Responses set to Block. Now go to Event Graph. First, let’s implement
Interact function, so double-click on in. We want to execute interaction only when curtain
circumstances are correct, so add Branch. To the circumstances: we want to interact only
with Lever Collider, so drag it in. Out of Hit Component search for Equal and connect
Level Collider to the second input pin. We also don’t want to do another interaction
when the lever is in use. Right-click and search and add Get InUse. And we want “when
it’s NOT in use”, so add to it NOT Boolean. Branch must be True only when both statements
are True, so add AND Boolean and connect it. If the branch is false, nothing
happens, and if it’s true call function Use. And Event Interact is done.
Now to the Use function. Go to left panel Functions, Override, and click on Use. When it is
in use, it is In Use, so search for Set InUse and check it to True. After that add Timeline and name
it Lever Rotation. I will be returning my lever to initial position, so connect Set InUse execution
pin to Play from Start and open the timeline. Change Length to 1 and add Float Track. But
what values are we changing? To get the answer, go to viewport and select the lever. I don’t
want the initial position to be in the middle, so switch to rotation and rotate it to the corner of
the groove. The axis along which we are rotating can be different according to the direction from
which we modelled the object. We can see that X rotation value is changed, so go back to timeline.
Rename track to Lever X Rotation. Right-click and add key, set Time to 0 and Value to initial
rotation value, which is in my case -60. I want to lever to be quickly pulled and then slowly
released, so add another key, set time to 0.1 and value to 60. Now we want to get it to the initial
state, so add Key, set Time to 1 and value to -60. For command to open the door add track, select
Add Event Track and name it Use Door. Add Key, I don’t know if value does anything,
so I set it to 0 and set Time to “0.1” and go back to Event Graph.
First, we want to animate the lever, so drag in its reference and out of it search
for Set Relative Rotation. Connect it after Update. Right-click to New Rotation and select
Split Struct Pin. Connect Lever X Rotation to New Rotation X and we can leave Y and Z
values at 0, because we didn’t change them. When the animation is finished, the lever
is no longer in use, so after Finished add Set InUse which is unchecked so it’s false.
To the Use Door pin, right-click and search for Get Door variable, which we added
in BP_DoorOpener blueprint. Out of it search for Toggle and connect it after Use
Door. And we’re done with Use function. Now let’s implement second function of
Interactable interface Show Interactable Information. We will use the same condition logic
as for Interact function, so move up and copy it, go to Show Interactable Information, paste
it and connect it. Duplicate Return Node, connect one with True and second one with
False. The one connected with False must have pin Show? unchecked. To Return Node after
True statement check Show? pin to true and write appropriate text to Text To Show.
I write there “Press [E] to use”. We are done here, so hit Compile and
the last thing we need is the door. Open Content Browser, and similar as with the
lever, right-click to BP_Door and Create Child Blueprint Class. I name it just BP_Door_01
and open it. Drag in Door meshes and BP_Lever. Position the lever to one side. You can see my
final transform on the screen. Duplicate it. Inverse Location X and Y. Rotation
Z set to -180 and now it’s mirrored on the other side of the door.
Now we must set reference of this door to the levers. To do it, go to Construction
Script. We have nothing in Parrent class, so we can delete inheritance here. Drag in levers
so we get references to them. We have only two levers here, so you can do it one by one or in
a simpler way that I show you later. For now, add For Each Loop and out of Array search for Make
Array. Add one pin and connect them with levers. Now it’s a bit tricky. Right-click into open
space and search for Get Child Actor. None of the options we see is the one we are looking
for. We have to uncheck Context Sensitive and the one we are looking for is Get Child Actor
under Child Actor Component. So, select it and to Target conncect Array Element. Drag out Child
Actor pin, turn back Context Sensitive, search for Cast To BP_DoorOpener and connect it with
Loop Body. Out of As BP Door Opener search for Set Door, add it in and connect it with the first
execution pin of Cast. Drag out input pin of Set Door and add Self reference. This way, you can set
reference of a blueprint to its child components. Now let’s implement functions of the door. Go to
Event Graph. As with the lever, add our function one by one, by going to Override and selecting
them. So, add Open, Close, Close&Lock and Toggle. Before we start any animation in timeline, it’s
good to change variables to the appropriate state. Start with Open. When we open the door, the door
is opened, so add Set IsOpen and set it to true. We are about to start animation, so add Set
Opening/Closing and set it to true as well. Copy it, paste it to Close and
connect it. When the door is closed it is not opened, so set IsOpen to False.
To Close&Lock add Set IsLocked and set it to True. After that, you could paste same sets as
with Close, but it is the same as after Close. Instead, we can avoid redundancy
by connecting the execution pin of Set IsLocked to Set IsOpen in Close.
Add Timeline and name it Open/Close. Event Open goes into Play and Even Close goes into Reverse.
If you’d want to have some doors start as opened, connect it to Play form
Start and Reverse from End. Open timeline, Add Float Track and name it Door
Z Location. Add Key and set Time to 0 and Value to 0. Because the default height is 300 and the
groove height is 10, value of opened door is -310. So, add another key, set
Time to 5 and Value to -310. Back to Event Graph. Drag in door reference, out
of it search for Set Relative Location and connect it with Update. Split Struct Pin of New Location
and connect Door Z Location with New Location Z. After Finished add Set
Opening/Closing and set it to false. Now go down and let’s implement Toggle function.
First, we must check if we can toggle the door state, so add Branch. We need to
check if the door is unlocked, so add Get IsLocked and to it add NOT Boolean.
We also want to change the state of the door only if the door is not in the changing process,
so add Get Opening/Closing and add NOT Boolean as well. We want to change state
only when both statements are true, so connect them into AND Boolean and
connect it into Condition node of Branch. When the branch is false, we want to do nothing,
so leave it blank. After True add another Branch that will decide if the door should Open or Close.
So, add Get IsOpen and connect it into Condition. When the door is open, we want to Close it. And
when the door is closed, we want to Open it. We are almost done here, so we can test it. Add
Door blueprint to your level and I move it a bit up, so bottom doesn’t flicker, and hit Play. Go
to the lever and press E. The door is going down and you can go through. Press E to the lever and
the door is closing. By the implementation that we did, you can use lever multiple times, but only
when the door stops moving, it does something. Now, let’s take advantage of inheritance. Go
back to BP_Door_01 and move up. All initial changing of variables will be same
for most of the potential doors. So, select all sets between Events and timeline,
Ctrl+X, go to BP_Door, paste it and connect it. Go back to BP_Door_01. Because we used
Override of functions, the code we inserted into the parent class isn’t here…yet.
We access it by right-clicking to Event Open and selecting Add Call to Parent Function. Take new
“Parent: Open” node, connect to it Event Open and connect it to Play. Repeat the process
similarly for Close and Close&Lock events. Now to the Toggle. We can see that
this implementation is generic and doesn’t contain anything for this door
only, because it’s only about switching states of the door when conditions are met.
So, select all the code except Event Toggle, Ctrl+X, delete Event Toggle, go to
BP_Door, paste it to Toggle and connect it. Now to how we can use inheritance to make
easy adding other functionalities. We have function Close&Lock, so let’s
implement function Unlock&Open. Add custom event and name it Unlock&Open. We
could do it as with Close&Lock, add Set IsLock, uncheck and connect it to Set IsOpen of Open
event. But locking and unlocking doesn’t have to be so easy in all cases. For example, what if we
want door that needs a key to open, and we don’t always want to open the door after it is unlocked?
For this it is better to create new function Unlock and add isLocked with false. Now it’s
working and we can Override it in future cases. Add new function Lock, add Set IsLocked and set
it to true. Go to Event Graph and replace Set IsLocked for Unlock&Open with Unlock function
and IsLocked for Close&Lock replace with Lock function.
Hit Compile and go back to BP_Door_01 because we
added new Function. Go to Functions, Override and select Unlock&Open. Move it above Event Open,
right-click, Add Call to Parent Function, connect it with Unlock&Open and connect it to
Play. Hit compile and let’s check that it still works. Sometimes when you move bunch of code, you
may forget to reconnect something so it’s better to test it right away. Everything still works.
Now let’s clear up the files, so in folder Props are parent blueprints and child blueprints
are in their files with their meshes. Open Content Browser and Save All, because
while moving files sometimes you move what you shouldn’t and Unreal crashes.
Create new folder and I name it StoneDoor. Move into it BP_Door_01 and static
meshes of door and its frame. Create another folder called Lever and
move into it BP_Lever_01 and static meshes of lever and its frame.
Now just let’s quickly look, how easy is to make door, that opens in other
directions. I take BP_Door_01 and rename it to BP_Door_Down. Duplicate it and replace “Down” with
“Up”. Open it, go and open timeline Open/Close, select 2nd key and remove minus from Value
so it’s 310. Now if we test it, you can see, that door goes up and it’s in line with the
groove as well. Don’t mind the overlapping of the floor and door going into the air, because
in proper game level, you wouldn’t see it. Similarly, we can do side
going door. In this case, we need value of sliding to the side that is plus
or minus 510. Go and open timeline Open/Close, rename Track to Door X Location and change
the value to -510. Now go back to Event Graph, disconnect connection leading to New Location Z
and connect Door X Location to New Location X. Hit compile and go to level preview. Here I place
the door to side wall, so it’s like in the game, where we wouldn’t see where the door is sliding
to. So, let’s test it…and it’s looking good. Now to the part that I promised
you earlier. In many cases, you don’t want to have lever as part of the
door, but you want to place it in your level. For this, duplicate blueprint of Side Door
and add to its name “_NoLever”. Open it, go to Consctruction script, delete all code here and
delete levers. Hit Compile and open BP_DoorOpener. Here just make variable Door public and hit
Compile. Place the new door into your level, as well as levers. I place one on wall here and
second one here. When you have selected lever, you can see here variable Door. You can
search for the door or just click to picker icon and pick the door. Don’t forget
to do it for both levers. If you don’t want to make variable of lever Door public, you
can assign door to lever in level blueprint. ---
So, we have finished the interaction system for
now and you should be able to create at least basic interactable items on your own now.
Last thing I do is clear the level and delete testing object. If you found this video useful,
give it a like and if you don’t want to miss next episode, subscribe. Thanks for watching and
see you in a next episode or in another video.