Skip to main content

Learn by Composition

The demo separates selection, target actions, objective tracking, door responses, and presentation. Open the assets in ElysAwareness/Demo/Composition to inspect the editable Blueprint examples.

Choose your starting point​

You can reuse the supplied behavior and change its presentation, build your own pieces against the shared contracts, or mix both approaches.

For a visual customization first, duplicate the relevant demo Widget Blueprints into your project's content folder. In the target marker example, duplicate the outer marker and the child widgets you want to edit, replace the children in its MarkerContent and DetailsContent slots, and assign the new outer class to the target's presenter. Editing a duplicate keeps future plugin updates separate from your project-owned changes.

WBP_ERP_DemoCorners and WBP_ERP_DemoRing expose FocusedColor, LockedColor and ReticleSize; WBP_ERP_DemoTargetDetails exposes FocusedFrameColor, LockedFrameColor and text styling. Edit those style properties and the UMG layout to create your own presentation. Preserve the shared targeting base and state forwarding when retaining the supplied behavior. Assign the resulting class through the presenter; SetWidgetPresentation also supports replacing it while a target is already locked.

For a behavior customization first, keep the supplied widget and replace a pipeline stage, challenge class or response component. The following sections explain those contracts. A custom mechanic still needs your own implementation; the framework provides the lifecycle and integration points.

Keep responsibilities separate​

An Awareness pipeline selects a candidate. The Targeting domain owns focus and lock state. Neither selection nor a lock should decide whether an actor is destroyed.

BP_ERP_DemoTargetAction is a Blueprint component contract. Its RequestAction function reports completion once and calls the overridable ApplyResponse. Add a derived component to an actor to give it a target action:

  • BP_ERP_DemoDisruptible hides the owner and disables collision.
  • BP_ERP_DemoDestroyTarget demonstrates replacing that response with destruction.

The demo controller looks for this capability on the locked target. A target without it cannot be destroyed by the controller. Replace or extend the action component to change behavior; the controller does not need another cast to a particular drone actor class.

Keep targeting and interaction independent​

Targeting owns the selected actor and its lock state. Interaction owns the nearby interaction candidate and the current interaction attempt. These domains can operate at the same time: a player can keep a drone locked while holding a button to open a door. Starting, cancelling or completing that door interaction does not require releasing the target.

Your game's input routing decides whether the two domains ever influence each other. Elys Awareness does not impose a universal priority between interacting and acting on a locked target.

For independent controls, use separate Enhanced Input actions in your PlayerController or Pawn:

The supplied demo maps F to IA_ERP_Interact and Left Mouse Button to IA_ERP_TargetAction. HandlePrimaryAction starts the interaction attempt; HandleTargetAction requests the locked actor's action. The interaction path never consults the lock.

  • Route the interaction action's Started event to StartInteractionAttempt, passing that input action. Route Completed and Canceled to StopInteractionAttempt with the same action.
  • Route a separate target-action input to GetLockedTarget, then to your gameplay action on that actor. The sample's BP_ERP_DemoTargetAction.RequestAction is one example of that gameplay action.
  • Keep the interaction route independent of IsLockedOn and GetLockedTarget. A valid locked target must not prevent the interaction input from reaching a door or another interactable.
  • Decide in your gameplay action whether acting on a target should release its lock. Do not release it merely because an unrelated interaction started.

If your game deliberately shares a button, implement that choice in its Blueprint input routing: choose the relevant action, provide matching on-screen instructions, and send release/cancel events to the interaction attempt that received the press. Other designs may temporarily disallow interactions during combat or clear a lock when entering a mini-game. Those are project-specific rules; keep them outside the generic targeting and interaction components.

When testing an independent setup, lock a target, approach a hold interaction, release midway, retry and complete it. The interaction should receive every input transition while the target remains locked, unless it independently becomes invalid.

Build independent objective groups​

Add BP_ERP_DemoObjectiveGroup to a puzzle owner and assign its Participants array in the level. The group observes the target-action components belonging to those actors. OnGroupCompleted is the output of the group, independent of any particular door or animation.

BP_ERP_DemoGateResponse is a separate response component. It listens to the group on its owner and moves the component carrying GateComponentTag by OpenOffset over OpenDuration. Change this response without modifying the group's counting logic.

Two puzzle owners should have disjoint participant arrays. Duplicating or replacing a target does not require a world-wide class search. Inspect RegisterParticipant, UnregisterParticipant, and DetachParticipants for explicit subscription ownership.

Implement a challenge entirely in Blueprint​

Derive a Blueprint from ERPInteractionChallenge. The reusable native base supplies lifecycle and reporting; your Blueprint supplies the mechanic.

  1. Reset the mechanic's own variables in Reset.
  2. Initialize any presentation state in StartChallenge.
  3. Handle input in OnInputPressed or OnInputActionPressed.
  4. Use ReportProgress for normalized progress and ReportStep for a stepped sequence.
  5. Call FinishChallenge(true) to execute the interaction, or FinishChallenge(false) to fail it.

ReportProgress clamps finite values to 0–1 and does not complete automatically by default. Enable CompleteAtOne only when progress actually represents completion. Countdown and moving-cursor values may reach 1 without completing the challenge.

FinishChallenge emits one outcome per attempt. Further reports are ignored. The interaction component calls PrepareChallengeAttempt before starting a runtime duplicate. It resets the completion guard even if a Blueprint override of Reset does not call its parent. If you manage attempts yourself, use PrepareChallengeAttempt followed by StartChallenge.

BP_ERP_DemoTwoStageChallenge is the example of a new mechanic based directly on this contract: complete two input stages before the configurable time limit. The same outcome API supports success, timeout failure and retries.

Its presentation is Demo/UI/WBP_ERP_DemoTwoStage, authored directly from ERPChallengeWidgetBase. Open its Event Graph to follow progress, completion, and reset into ordinary UMG controls. Demo/Challenges/Demo_ERP_Interactable_TwoStage configures the mechanic through ChallengeClass; duplicate this actor or replace that class to experiment.

Add or replace targeting feedback​

All ERPBaseTargetingFeedbackComponent subclasses on the current target receive focus, descriptor and lock notifications. Add independent components for a marker, a sound or a material effect. Call RefreshTargetFeedback on the Targeting component after adding or removing a receiver at runtime.

For a Blueprint-owned effect, disable Use Default Custom Depth Feedback. Set WidgetClass to None for a receiver that does not create a view. OnTargetLockChanged provides a separate lock/unlock hook.

The optional built-in outline supports FeedbackMeshTag to select primitives. Multiple feedback layers share temporary outline ownership. Releasing the last layer restores the prior state, provided a different system has not subsequently replaced that state. Shared use of the same stencil value by unrelated systems still requires an application-level ownership convention.

Use SetWidgetPresentation(NewWidgetClass, NewOffset) to replace a view at runtime. The replacement receives the current actor, descriptor, focus and lock state. Pass None to remove it. If you edit presentation properties directly, call RefreshPresentation to apply them. WidgetOffset is a local distance in centimeters, affected by the actor transform; it is not a pixel offset.

This actor-local convenience presenter retains one requesting player at a time. Projects needing simultaneous split-screen presentation should use a separate presenter per local player. Do not treat a single shared actor-local widget as a split-screen HUD.

Replace part of the marker​

The drone has two feedback components: the existing material effect and BP_ERP_DemoTargetPresenter. The presenter uses Demo/UI/WBP_ERP_DemoTargetMarker. Its Designer contains two Named Slots:

SlotDefault contentResponsibility
MarkerContentWBP_ERP_DemoCornersFocus and lock reticle
DetailsContentWBP_ERP_DemoTargetDetailsDescriptor name

Replace either child with another widget derived from ERPTargetingWidgetBase. SynchronizeViews forwards actor, descriptor, focus and lock state through the shared base API; it does not cast to a particular skin. WBP_ERP_DemoTargetMarker_Ring demonstrates the same composition with a different reticle.

The outer view is 180 × 150 Slate units. The reticle is centered on the actor; the name sits underneath with a fixed screen-space gap. The presenter uses zero world offset, so drone scale does not distort that gap. TargetDescriptorData on each drone instance supplies its name.

WBP_ERP_DemoStatusHUD provides an editable TargetingHelp footer with the demo's default keyboard controls. Remove or replace this panel in the Designer for a different teaching layout. These static hints describe the supplied demo mappings; projects with remapping should supply hints from their input mapping resolver.

Practice the extension contract​

  • Add a targetable actor without a target-action component. Locking it must not imply destruction.
  • Replace disruption with another response component without changing the controller.
  • Place two objective groups and complete one without affecting the other.
  • Add a second feedback component while retaining the original marker.
  • Replace the marker widget while locked and check that the new view retains the target and lock state.
  • Run the two-stage Blueprint challenge, fail by timeout, then retry successfully.

Keep the final widget composition and demo gameplay in Blueprint. Reusable native widget bases and lifecycle helpers are appropriate; puzzle-specific behavior should remain visible in the learning assets.