Between the Folds #013 - CommonCollider System


Throughout WHALIEN, there are lots of actions that are triggered when the player (or any other character/object) reaches a designated area. Such actions can be noticeable for the player - like triggering a scripted sequence or the camera zooming out - but some actions are also unnoticeable – like saving the game and setting a new checkpoint.

Most frequently we need to trigger multiple actions at the beginning of a new level, such as

  • saving the game
  • updating the latest checkpoint
  • loading/unloading other levels
  • starting a scripted action
  • displaying some dialogue
  • unlocking an ability and displaying the corresponding tutorial video
  • unlocking an achievement
  • etc.

All of these actions are ideally executed at the same time, but there are cases where some of them need to be executed in a predetermined order. For example, we might want to first display a dialogue and afterwards unlock a new ability for the player.

Having individual triggers for each of these functionalities would be very cumbersome, because having them all fire at the same time would require all triggers to be placed at the exact same location and have identical dimensions. In this setup, we would have to make some triggers ever so slightly smaller to have them be fired later and keep the predetermined order.

(Some actions combined into one collider. This trigger displays a static mesh and unlocks an ability and an achievement on overlap.)

Core

Our CommonCollider system allows us to trigger the execution of multiple actions with a single collider. The order in which these actions are executed can be defined by the designers. The CommonCollider system consists of two elements, the CommonColliderComponent and the IColliderSystemImplementable-interface.

This feature allows us to keep our levels tidy and simplifies getting an overview of all actions triggered at a specific point. It also makes adding new actions to an existing trigger less cumbersome.

(Multiple functions combined into one collider. This trigger prepares the state of the game for the newly entered level.)

CommonColliderComponent

The CommonColliderComponent is a BoxCollider that manages all actions attached to its owning actor. Whenever the Collider registers an overlap, it forwards the event to all IColliderSystemImplementable components attached to its owner. The order of execution of these actions can be customized in the editor.


IColliderSystemImplementable

Each action usable in our CommonCollider system needs to be an ActorComponent implementing the IColliderSystemImplementable interface. It declares the virtual function ExecuteFunctionality(), which is called on CommonColliderComponent::BeginOverlap() and EndOverlap(). Each component must override the function to define the logic to be executed on begin or end overlap.

(Examples of classes implementing IColliderSystemImplementable: The logic of individual actions is usually simple because they only have to accomplish simple tasks.)

(The ICommonColliderInterface definition: Interfaces in UE4 require a special setup to be recognized by the engine and usable in Blueprint.)

Challenges

One UE4-specific challenge we had to overcome for our CommonColliders was that overlap events aren’t fired if they happen during or before BeginPlay(). This can for example happen when the player spawns inside a CommonCollider. Firing the overlap events manually during BeginPlay() doesn’t work either, because GetAllOverlappingComponents() returns an empty array at that time.

Once all actors have finished their BeginPlay(), GetAllOverlappingActors() works as intended, so normally, we could use the C++ delegate UWorld::OnWorldBeginPlay (which is fired once all actors have finished their BeginPlay()). However, since we use LevelStreaming and some actors are only loaded in after OnWorldBeginPlay, this approach is not applicable for us. Therefore, we subscribe to our own delegate OnLevelStreamed, which is fired whenever a new level is streamed in and all contained actors have received their BeginPlay(). Therefore GetAllOverlappingComponents() works here. If you want to learn more about our LevelStreaming system, check out our second devlog entry.

(Code to subscribe to [i]OnLevelStreamed [/i]on [i]BeginPlay()[/i] and manually trigger the overlaps once the event is fired.)

Since first creating the CommonCollider system, we’ve continuously integrated new functionalities. It has become a staple in our toolbox to keep our levels clean and structured. If you have any questions or ideas about what other actions we could add to our CommonColliders, feel free to reach out!

- Andi, Ralf

Leave a comment

Log in with itch.io to leave a comment.