ChatScrollRect

Virtualized scroll view for displaying chat messages. Uses a fixed pool of ChatMessageLine instances that are recycled (cycled) as the user scrolls, enabling efficient rendering of arbitrarily large message histories without creating a UI element per message.

Definition

Namespace: Paragon.Townskeep.ChatSystem.HUD Assembly: Townskeep.dll

[RequireComponent(typeof(ScrollRect))]
public class ChatScrollRect : ParagonUIBehaviour

Inheritance: SerializedMonoBehaviourParagonBehaviourParagonUIBehaviour → ChatScrollRect

Remarks

ChatScrollRect implements a virtualized list pattern. Rather than instantiating a ChatMessageLine for every message in the channel history, it maintains a small pool of line objects sized to the viewport plus a small buffer. As the scroll position changes, lines that leave the viewport are recycled to the opposite end and populated with the appropriate message.

Virtualization Strategy

The pool is stored as a LinkedList<ChatMessageLine>. When scrolling:

  • Downward (towards older messages) — The first (top) line is moved to the end and populated with the next message beyond the visible range.

  • Upward (towards newer messages) — The last (bottom) line is moved to the beginning and populated with the previous message.

This cycling is driven by CycleLines(int count), which determines how many lines to cycle based on the delta between the previous and current scroll-position line indices.

Line Count Calculation

Each frame in Update(), the component recalculates:

  1. lineCount — The number of lines needed: viewport capacity + up to 2 buffer lines (clamped by available messages)

  2. bufferHeight — The total scrollable content height minus viewport height

  3. maxScrollPosition — Maximum scroll position based on total message count

If lineCount changes (e.g., window resize), RefreshLines() adds or removes ChatMessageLine instances to match.

Scroll Inputs

The component listens to two scroll sources:

  • ScrollRect.onValueChanged — Drag-based scrolling within the viewport

  • Scrollbar.onValueChanged — Direct scrollbar manipulation

Both are normalized to a position value via ScrollToPosition().

Message Indexing

Messages are accessed from the ChatWindow using C# Index with the hat (^) operator, providing reverse indexing from the end of the message buffer. This means the newest message is at ^1, second newest at ^2, etc.

Quick Lookup

Goal
How

Initialize

scrollRect.Initialize(chatWindow)

Add a single message

scrollRect.PushMessage(message)

Add multiple messages

scrollRect.PushMessages(messages)

Clear all displayed messages

scrollRect.ClearMessages()

Scroll to a position

scrollRect.ScrollToPosition(position)

Scroll to a specific line

scrollRect.ScrollToLine(index)

Get current line index

scrollRect.GetCurrentLineIndex()

Read current line count

scrollRect.LineCount

Properties

Property
Type
Description

LineCount

int

Current number of pooled line objects (viewport capacity + buffer)

ScrollPosition

float

Current absolute scroll position in pixels

ScrollValue

float

Normalized scroll value (01). Setting this scrolls to the corresponding position.

Fields

Field
Type
Access
Description

ChatMessagePrefab

ChatMessageLine

public

Prefab used when instantiating additional message lines

Methods

Initialize

Sets up the scroll rect with its parent ChatWindow, registers scroll listeners, and performs initial line refresh.

Parameter
Type
Description

chatWindow

ChatWindow

The parent chat window that provides message data

PushMessage

Adds a single new message to the display. Cycles the last line to the front and populates it with the message.

Parameter
Type
Description

message

ChatMessage

The chat message to display

PushMessages

Adds multiple messages to the display. Takes the first lineCount messages, reverses them, and pushes each one sequentially.

Parameter
Type
Description

messages

IEnumerable<ChatMessage>

Collection of messages to display

ClearMessages

Clears all messages from all pooled line objects.

ScrollToPosition

Scrolls to an absolute pixel position. Clamps to [0, maxScrollPosition]. Triggers line cycling if the scroll crosses a line boundary.

Parameter
Type
Description

position

float

Absolute scroll position in pixels

ScrollToLine

Scrolls to a specific line index with an optional pixel offset.

Parameter
Type
Default
Description

index

int

Target line index (clamped to [1, maxLineIndex])

offset

float

0.0f

Additional pixel offset from the line position

GetLinePosition

Returns the pixel position of a line at the given index.

Parameter
Type
Description

index

int

Line index (clamped to [1, maxLineIndex])

Returns: Pixel position of the line.

GetLineIndex

Calculates the line index at a given pixel position.

Parameter
Type
Description

position

float

Pixel position

Returns: The line index at that position.

GetCurrentLineIndex

Returns the line index corresponding to the current scroll position.

Returns: Current top-visible line index.

Common Pitfalls

circle-exclamation
circle-exclamation
circle-exclamation
circle-exclamation
circle-exclamation

See Also

Last updated