NPC Speech Bubble Component

Overview

NPC Speech Bubbles are world-space UI panels that float above characters and display short contextual text when the player is nearby. They provide ambient storytelling and gameplay signposting without requiring a full dialogue interaction — an NPC might say "Have you seen the blacksmith?" when you walk past, shift to "Please, find my missing cart!" once a relevant quest is active, and go silent after you've already spoken to them.

The system is built from two cooperating parts:

  • NPCSpeechBubble — a per-NPC MonoBehaviour that owns the bubble content, proximity detection, and conditions for what text to show.

  • SpeechBubbleManager — a scene singleton that coordinates all active bubbles, caps how many are visible at once, and handles object pooling so bubble UI instances are reused rather than instantiated and destroyed at runtime.

Text content is driven by Text Variants — a list of conditional text entries evaluated in priority order each time the bubble activates. Conditions can gate variants on quest state, dialogue flags, and objective progress, so the same NPC can say something different depending on where the player is in the story. If no variant condition matches, a configurable Default Text is shown instead.

Bubbles respond to proximity: each NPC defines its own activation and deactivation distances, with optional hysteresis to prevent flickering. Line-of-sight checking is also supported. The Manager enforces a global cap on how many bubbles can be visible simultaneously, prioritising the NPCs closest to the player when the limit is reached.

Properties

Property
Type
Description

Dialogue Trigger

DialogueTrigger

Optional link to a DialogueTrigger on the same NPC. Auto-detected via GetComponent at Start if not assigned. Used by the quest indicator and auto-hide logic.

Player Transform

TransformReference

The player transform used for distance calculations. Falls back to GameObject.FindGameObjectWithTag("Player") at Start if left empty.

Bubble Anchor

Transform

The world-space transform the bubble is parented to. If unset, the NPC's own transform is used. The Bubble Offset is applied in local space relative to this anchor.

NPC Aligner

Aligner

Optional Malbers Aligner component. When assigned, the NPC rotates to face the player the moment they enter activation range.


Proximity Settings

Property
Type
Default
Description

Activation Distance

Float (1–50)

4

Player must be within this distance (metres) for the bubble to become eligible to show.

Deactivation Distance

Float (1–55)

5

Player must move beyond this distance for the bubble to become ineligible. Must be ≥ Activation Distance — auto-corrected with a warning if not. The gap between the two values provides hysteresis: the bubble won't flicker on and off as the player hovers right at the edge.

Require Line of Sight

Bool

false

When enabled, a Physics raycast is cast from the NPC to the player each frame. If an obstacle on Obstacle Layers blocks it, the NPC is treated as out of range even if within distance.

Obstacle Layers

LayerMask

All

The layers that count as obstructions for line-of-sight checks. Only relevant when Require Line of Sight is true.


Text Content

Property
Type
Default
Description

Text Variants

SpeechBubbleTextVariant[]

Empty

Conditional text entries evaluated in priority order. See Text Variants section below.

Default Text

String

"Hello there!"

Shown when no Text Variant's condition is met, or when the variants list is empty. At Start, if no variants are configured, a single Always variant is automatically created from this value.

Randomize Text

Bool

false

When true, selects randomly from all matching variants rather than taking the highest-priority one.

Cycle Text

Bool

false

When true, re-evaluates and updates the displayed text every Text Cycle Interval seconds while the bubble is visible.

Text Cycle Interval

Float

5

Seconds between text cycles. Only used when Cycle Text is enabled.


Quest Integration

Property
Type
Default
Description

Linked Quest

Quest

None

The quest this NPC is associated with. Drives the quest state indicator icon and the hide-on-complete behaviour.

Linked Objective

QuestObjective

None

A specific objective within the linked quest. Reserved for fine-grained per-objective indicator logic.

Hide When Quest Complete

Bool

true

When true, the bubble stops showing entirely once the linked quest reaches the completed state.

Show Quest Indicator

Bool

true

When true, an icon is overlaid on the bubble reflecting the quest's current state. See Quest State Indicator below.


Visual Settings

Property
Type
Default
Description

Custom Bubble Prefab

GameObject

None

Override the SpeechBubbleManager's default prefab for this specific NPC. The prefab must have a SpeechBubbleUI component. If left blank, the Manager's pooled prefab is used.

Bubble Offset

Vector3

(0, 2, 0)

Local-space offset from the anchor transform. Adjust Y to position the bubble above the NPC's head.

Billboard to Camera

Bool

true

Passes this flag to the SpeechBubbleUI component, which rotates the bubble to face the camera each frame.

Fade In Duration

Float

0.3

Duration in seconds for the bubble's appear fade.

Fade Out Duration

Float

0.2

Duration in seconds for the bubble's disappear fade. The bubble instance is not returned to the pool until this duration has elapsed.

Use Typing Effect

Bool

false

When true, text is revealed character by character at Typing Speed rather than appearing all at once.

Typing Speed

Float

0.05

Seconds per character for the typing effect. Only used when Use Typing Effect is true.


Audio

Property
Type
Description

Audio Source

AudioSource

The AudioSource used for all bubble sounds. Assign for spatialised (3D) audio anchored to the NPC. If unassigned, no sounds will play.

Default Bubble Sound

AudioClipReference

Sound played when the bubble shows, unless the active Text Variant has its own variantSound assigned. Variant sounds always take priority over this default.


Interaction

Property
Type
Default
Description

Interaction Distance

Float (0.5–10)

2

When the player is within this distance, the Interaction Prompt is displayed on the bubble via SpeechBubbleUI.ShowInteractionPrompt().

Interaction Prompt

String

"Press E to talk"

The text shown in the interaction prompt area of the bubble UI when the player is close enough.

Auto Hide on Dialogue

Bool

true

Hides the bubble for all NPCs whenever any dialogue begins. The bubble re-appears after dialogue ends, subject to the cooldown below.

Cooldown After Dialogue

Float

2

Seconds after a dialogue ends before this bubble is allowed to show again. Prevents bubbles from immediately popping back up after a conversation.


Quest State Styling

Controls the colours and icons shown in the quest state indicator when Show Quest Indicator is enabled.

Property
Type
Default
Description

Quest Available Color

Color

Yellow

Tint applied to the indicator icon when the linked quest is available but not yet started.

Quest Active Color

Color

White

Tint applied when the quest is in progress but not yet completable.

Quest Complete Color

Color

Cyan

Tint applied when all objectives are done and the quest is ready to turn in.

Quest Available Icon

Sprite

None

Icon sprite for the available state. Conventionally an exclamation mark (!).

Quest Active Icon

Sprite

None

Icon sprite for the in-progress state. Conventionally a question mark (?).

Quest Complete Icon

Sprite

None

Icon sprite for the ready-to-turn-in state.


Events

Event
When It Fires

OnBubbleShown

Immediately after ShowBubble() makes the bubble visible and fires the fade-in.

OnBubbleHidden

Immediately after HideBubble() is called, before the fade-out completes.

OnPlayerEnterRange

The first frame the player's distance drops to or below Activation Distance (and passes line-of-sight if required).

OnPlayerExitRange

The first frame the player's distance exceeds Deactivation Distance.


Text Variants

Text Variants (SpeechBubbleTextVariant) are the core of the contextual text system. Each variant is an independent entry in the list that carries its own display text, a condition, and a priority score.

At Start, all variants are sorted by Priority (highest first) and this order is retained for the lifetime of the component.

When the bubble is about to show, GetCurrentVariant() runs EvaluateConditions() on each variant in priority order and collects all that pass. The winner is:

  • The first match (highest priority) — normal mode.

  • A random pick from all matches — when Randomize Text is enabled.

If nothing matches, Default Text is shown instead.

Text Variant Fields

Field
Type
Default
Description

Text

String

"Hello!"

The speech bubble text displayed when this variant is selected.

Condition Type

Enum

Always

Which condition must pass. See condition types below.

Required Quest

Quest

None

The quest referenced by quest-based condition types.

Quest State Condition

Enum

Active

The required state. Used by some condition types for context (see below).

Required Objective

QuestObjective

None

A specific objective that must be completed. Only evaluated by QuestObjectiveComplete.

Required Dialogue Flag

String

""

The flag name to check in DialogueManager. Only evaluated by DialogueFlag.

Expected Flag Value

Bool

true

Whether the flag must be true or false. Only evaluated by DialogueFlag.

Variant Sound

AudioClipReference

None

Per-variant audio override. When assigned, this plays instead of the component-level Default Bubble Sound whenever this variant is selected or cycled to.

Priority

Int (0–100)

0

Higher numbers are evaluated first. When multiple variants match, the highest-priority one wins (unless Randomize Text is on).

Condition Types

Condition Type
Passes When

Always

Always passes. Use for default ambient chatter that shows when no other condition matches.

QuestAvailable

The Required Quest is available (not yet started, not completed).

QuestActive

The Required Quest is currently active.

QuestCompleted

The Required Quest has been completed.

QuestObjectiveComplete

The Required Quest is active and the Required Objective has been completed within it.

DialogueFlag

The flag named Required Dialogue Flag in DialogueManager equals Expected Flag Value.

NoQuestActive

The Required Quest is not currently active (available or completed — anything but in-progress).

Tip: Stack multiple variants with increasing priority to create layered NPC awareness. A priority-0 Always variant provides ambient dialogue; a priority-10 QuestActive variant overrides it once the quest begins; a priority-20 QuestObjectiveComplete variant overrides that once a key task is done.


Quest State Indicator

When Show Quest Indicator is enabled and a Linked Quest is assigned, the indicator logic evaluates quest state each time ShowBubble() is called:

Quest State
Icon Shown
Colour

Quest available (not yet started)

Quest Available Icon

Quest Available Color

Quest active and objectives incomplete

Quest Active Icon

Quest Active Color

Quest active and all objectives complete (ready to turn in)

Quest Complete Icon

Quest Complete Color

Quest completed

Icon hidden

Quest not found / no quest assigned

Icon hidden


Visibility Gate Order

The Manager calls CanShowBubble before deciding to show any bubble. All of the following must pass:

  1. Not Force Hidden (via ForceHide()).

  2. Player is in range — distance ≤ activation threshold and line-of-sight passes if required.

  3. No dialogue is active, or Auto Hide on Dialogue is false.

  4. Cooldown after dialogue has elapsed.

  5. Linked quest is not completed, or Hide When Quest Complete is false.

If all five pass, the Manager then applies its own global cap (see Speech Bubble Manager below). A bubble that passes all local conditions but is pushed out by the cap is neither shown nor hidden — it waits for the next priority update cycle.


Public API

Method
Description

ShowBubble()

Called by the Manager. Acquires a pooled instance, resolves the current text variant, applies visual settings, and triggers the fade-in.

HideBubble(bool immediate = false)

Called by the Manager or internally. Triggers fade-out. The pool release is delayed by fadeOutDuration + 0.1s unless immediate is true.

ForceHide(bool immediate = false)

Sets the isForcedHidden flag and hides the bubble. The bubble will not show again until ReEnableAfterForceHide() is called.

ReEnableAfterForceHide()

Clears the forced-hide flag and requests a Manager visibility update.

ManualShow()

Clears the forced-hide flag and requests a Manager visibility update. Does not bypass proximity or condition checks — the Manager decides whether to show.

ManualHide()

Calls HideBubble() with the default fade.

RefreshText()

If the bubble is currently visible, re-evaluates the variant conditions and updates the displayed text immediately.

UpdateDistanceToPlayer()

Recalculates cachedDistanceToPlayer and updates isInRange. Called every frame in Update() and can also be called externally.

IsVisible()

Returns true if the bubble is currently shown.

Read-only properties:

Property
Type
Description

IsBubbleVisible

Bool

Whether the bubble is currently in the shown state.

IsInRange

Bool

Whether the player is currently within the activation/deactivation hysteresis zone.

DistanceToPlayer

Float

Last cached world-space distance to the player. Updated every frame.

CanShowBubble

Bool

Evaluates all five local visibility gates. Does not account for Manager limits.

BubbleAnchorTransform

Transform

The resolved anchor — bubbleAnchor if set, otherwise the NPC's own transform.


Scene Gizmos

Gizmos are only drawn when Debug Mode is enabled on the component.

Gizmo
Colour
What It Represents

Wire sphere (always)

Green

Activation distance

Wire sphere (always)

Yellow

Deactivation distance

Wire sphere (always)

Blue

Interaction distance

Wire cube (selected only)

Cyan

World position of the bubble anchor + offset

Scene label (selected only)

Cyan

"Speech Bubble\nN variants"

Usage Tips

  • Hysteresis distance — always set Deactivation Distance 1–2 metres above Activation Distance. A player standing exactly at the activation boundary will constantly cross it if both values are equal, causing the bubble to flicker.

  • Layered variants — use Always at priority 0 as a fallback, then override it with quest-aware variants at higher priorities. The NPC appears aware of the player's progress without any extra scripting.

  • Cycling ambient chatter — enable Cycle Text with several Always variants at equal priority and Randomize Text enabled. The NPC will rotate through different lines of ambient speech while the player is nearby.

  • Post-dialogue cooldown — set Cooldown After Dialogue to at least 2–3 seconds. This prevents the speech bubble from immediately reappearing right after the player closes a full dialogue conversation.

  • Per-NPC custom prefabs — if a particular NPC needs a stylistically different bubble (e.g. a monster growling instead of talking), assign a Custom Bubble Prefab directly on that NPC's component. All other NPCs continue using the Manager's pool.

  • Pool size — set Initial Pool Size to match or exceed Max Visible Bubbles. If the pool runs dry at runtime, a new instance is instantiated on the fly, which causes a brief hitch.

  • Global hide for cutscenes — call SpeechBubbleManager.Instance.HideAllBubbles() at the start of a cutscene or menu, and ShowAllBubbles() when returning to gameplay.

  • Debug overlay — enable Debug Mode on the Manager during development to see a live stats overlay in Play Mode showing exactly how many bubbles are registered, eligible, and visible, alongside pool usage.

Last updated