Wave Shooter : Day 5 : Interaction

Time for Ammo

I’ve set the goal of making a complete game in a little over one month, while only working on the project for a few hours each evening. In another write up, I’ll break down the design decisions that go into scoping a project for this goal.

This morning, I want to solve the problem of ammo. Do we make it infinite? If not, then how do we balance it so that it’s not too punishing? Either way, this means we need ammo drops and that means: The interaction system needs to be reworked


Why does it need to be reworked?

When I originally started looking at setting up a set of tools for quickly building First Person Shooters, I spent months studying the various kits on the unreal engine marketplace to see what they offered. I landed on using the one from Infima Games.

It’s a starting point, that will need to be reworked over time.

It has some drawbacks. Mostly, some of the approaches used are much more complicated than I think they need to be. What it does offer is a terrific feel for the action right out of the box. The code while overly complex is accessible and modular enough to allow me to replace things overtime.

I’ve slowly been doing just that and today I’m going to replace the interaction system. The current setup already uses an actor component which makes the work of replacing it straightforward. I first need to find references to that component in the player character and replace them with logic from my new component.


What’s the goal here?

The current system passes around a hit result to determine interaction. I want to simplify that with a reference to an actor which is set by determining the best current candidates for interaction. If that actor variable is not set, then we know we can’t interact. This will also simplify the process of implementing anything else we might want such as highlighting the object, spawning widget popups with information, or triggering any other action.


Considerations

I want the component to be as self-contained and as simple as possible. It should focus on providing basic interaction but not have any knowledge of the interactable or the player using it. Its sole purpose is to provide the ability for the player to interact with something.

When finished all it takes is adding the component to a player character and everything for interaction is immediately ready to go.


Blueprint Interface

The easiest way I can think of to trigger the logic when needed while avoiding unnecessary dependencies is to implement an interface for the interactable that has events for when something becomes the current target and when it is no longer the current interaction target.

For now, the interface only needs 3 functions.

  • Let the interactable know it’s now the current focused interactable.
  • Let the interactable know the player is trying to use it.
  • Let the interactable know it is no longer focused by the player.

In the Interactor Component, we handle the tracing for an interactable, set the current interactable and remove any previous interactable.

Interactor Component Tick event

Processing the hit is simply a matter of clearing the current target if the hit is invalid and updating the current target if it’s changed from the last target set.

On the Interactable we implement the interface. We use the focus change functions to change the rendering of custom depth on the mesh which activates the highlight by the post process material.


Collision Object Channels, Trace Channels, and Presets. Use them.

Another big problem with the template as is, is its use of custom collision settings. These should never ever be used. Setting up collision profiles in project settings can trivialize a great deal of logic. Custom collision overrides can make it very hard to track down bugs and makes it much harder to adjust collisions settings later on.

To solve this problem, I’m setting up a trace channel for interactables and a custom profile to assign for any collision that should be traced against for interaction.


Dynamic Actor Outlines

I want interactables to have a visible outline when they have player focus. Outlining actors in Unreal Engine is fairly straight forward. We use the custom depth and stencils to outline the mesh using a post process material. When an actor becomes the current interaction target, we need to set the mesh to render custom depth and set the appropriate stencil bit.

Several years ago, when I first started looking at how to do this type of outline, I found a few articles by Tom Looman extremely helpful. I’m linking those here, and I would offer that the materials he sells are worth the few dollars he asks for them.


Custom Controller Data Class

To facilitate setting the proper image for the current controller and input action, I’ve subclassed the UCommonInputBaseControllerData class and I use that subclass for any input data assets in editor.

The Controller Data stores a map of images to inputs for each controller type. There are Data assets for Keyboard and Mouse, Xbox Gamepad, Dual Sense Controllers, Steam, etc…

I’ve added two functions to the custom class. One function to retrieve the image assigned to an action in the input data, and another to check if the data contains a certain key.


Interaction Pop-up Widget

In blueprint, I determine the Controller Data that is appropriate for the currently used input method and set a soft reference to it.

The image assigned to the input key in that data asset is then retrieved and used to set the image on the widget. This functionality is very important if we want to use the “Full Controller Support” tag on Steam as doing so requires that we display appropriate images for the inputs of each controller type.

Because this is all triggered when the last used input device changes, the widget will update in real-time in game.


Enhanced Input

To see that input is handled automatically we use an enhanced input action. As long as IA_Interact is assigned to the current input context everything will just work.


What’s Next?

Implementing all of this took about an hour. The custom input data class was created in the past for use in the framework I use for common UI.

I may do a more detailed breakdown of some of the elements here in a future post. There are also some additional challenges not addressed here, such as if this is used for item drops which require interaction to activate then how do we allow the player to cycle through those if they spawn on top of each other?

There’s a simple solution for that but for now, I’m moving on to the next enemy archetype and the enemy dismemberment system.