Monday, 9 May 2016

FMP Week 17 - Technical Implementation - How to Pick up and Spin Objects in UE4

2/05/16 - 6/05/16

This is the first week of "technical implementation", according to my schedule. Technical implementation refers to any of the more technical areas of my FMP, such as any Blueprint systems, matinees or other complicated dynamic elements I need to add.

In my brief, I stated that my environment would be interactive, and that the bulk of that interactivity would come from being able to pick up and look at notes/objects.

I didn't have to spend much time building the note system as I'd already prototyped it just before FMP for testing purposes, so it more of a matter of implementing and refining the Blueprints.

Explaining the Interactive Object Blueprint

First off, let me start by saying that as I didn't follow any tutorials or consult anyone else the Blueprint I built is guaranteed to not be the only way to do this, and quite possibly isn't the best way either (though I think I did a pretty good job)... and with that, let's begin.

In The Character Blueprint

In the FirstPersonCharacter Blueprint, we start off by sending out a line raytrace whenever E is pressed. E is our action button. The start and out end points of the raytrace are determined by the player location and rotation in the world - the times by value at the bottom is essentially how far we want the raytrace to travel out into the world.

Next, we break the hit and either fire the On Interaction message (we'll get to that in a second) and freeze the player, or we fire the On Interaction message and unfreeze the player - the direction of the branch is determined by a boolean called "Open". Open refers to whether the object viewer window is open or not and is set at the end of each script path.
Basically, this just means that when E is pressed the first time, the player is frozen and the viewer comes up, but if it's pressed a second time then the player will be unfrozen and the viewer will close.

"Open" affects whether the player can move or not by adding these branch nodes in between all of the movement things in the player blueprint.

Lastly, we add this to re-draw our player HUD after the object viewer is closed.

Now, going back to these nodes:

"On Interaction" and "Freeze Player" are both custom events built in interfaces. 
The Interactive interface looks like this:

It simply fires the "On Interaction" event and isn't used to return any values.

Freeze player looks like this:

It returns a boolean called IsFrozen. The point of this event is just to return a True value when an actor with this interface assigned to it is hit with the raytrace - the value is then set to the "Open" boolean in the player blueprint.

The Freeze Player interface needs to be assigned to the FirstPersonCharacter Blueprint. The Freeze Player and Interactive interfaces both need to be assigned to our main Blueprint - "InteractiveObject".

Final player blueprint

In The Interactive Object Blueprint

The InteractiveObject blueprint is our main blueprint. After the player fires out the raytrace, if it hits an object with the Interactive Interface assigned to it, this blueprint will run.

The viewport set up for the blueprint consists of a post processing volume, a basic sphere, a basic cube, a trigger box and a material billboard.

We also need to create the following variables:

Base Object and View Object are both static meshes. Material is a material. ViewerPositionXby, Gamepad Angle x and Gamepad Angle y are floats. Object Text is a string. CanRotate and TextIsVis are boolean values. TextColour is a slate colour.

Now, let's go to the construction script. First we do with to allow us to change the meshes for the base object and viewable object in each instance of the Blueprint.

Next, we do this so we can change the material in each Blueprint instance.

This is to allow us to be able to move the location of the material billboard in each instance of the Blueprint. My material billboard is a flashing circle - this is to indicate to the player where viewable objects are from a distance.

This allows us to adjust the position of the overlap volume in each instance - you could also make a similar thing to allow you to adjust the size of the volume in the instance, but I didn't do that.

And now onto our main event graph! This is likely confusing, but I hope I can explain well enough.

First off, we call our custom event that we created in the Interactive Interface - this links up our character blueprint with this one. After that, we remove all widgets from the character, thus removing our player HUD (the little circle in the middle of the screen in my project).

Next, we branch off into 2 things based on whether the sphere is visible. The sphere is our viewable mesh, so if it's not visible than we know the player isn't looking at the object.
On either side of the branch, we play the appropriate sound at that location - either pick-up or put-down.
We then enable input if the object is being picked up or disable input if it's being put down. Let's follow the "pick up" path from here first.

We add a post processing component  - in here I changed the depth of field to blur out anything that wasn't the object we were looking at. Next, set the following variables to true - these will be important later on.

After that, we add ViewObjectWidget to the player viewport - basically our HUD when looking at an object. We assign to it our text colour and object text that we set can set in each instance of this Blueprint.

Now we have to set the cube (our base object) to be invisible and our sphere (are viewable object) to be visible, and move that in front of the player. The float value "ViewerPositionXby" is used to allow us to adjust how far away from the player the object needs to be - the default value is 30.

That's the end of the "pick up" path, so let's go back to the branch node and follow the "put down" path.

This is very simple. First we destroy our post processing component that was made earlier, then we remove all the widgets from the player (getting rid of the view object HUD)

Lastly for this, we set the sphere (our viewable object) to invisible our the cube (our base object) to be visible.

So now we should have it so the player can "pick up" an object and it should move to be in front of them, their movement frozen, but we need to add the ability to spin the object round using either the mouse or right thumbstick.

For the mouse, we do this:

And for the gamepad, this:

Now that's done, we need to add the feature to toggle the description on and off, we which as follows:

Finally, we have one thing left to do - to add a highlight around the object when the player enters of the overlap volume. In the Blueprint, we need to add this:

This turns on the object's Render Custom Depth and sets the material billboard to be invisible, so the little flashing circle is no long visible up close.
For the highlight to actually work though, we need to create the following material first:

Make sure the material domain is set to post process

After we need to make a new post processing volume in the level and add the material we just created as a blendable to it:

Lastly, we need to attend to our ViewObjectWidget. Mine looks like this:

The important thing here is the Text Block. We need to create the following bindings:

And have these variables:

 The graph in the widget should look let this:

Now we're able to change the text in each Blueprint instance.

In theory, that's everything we need to create the interactive objects, but in order for it to work properly we need to make sure that every base object as a collision mesh on it (so the raytrace has something to hit), and every viewable object doesn't have a collision it (so the collision doesn't hit the player).

Final interactive object blueprint

The finished product