Skip to main content

Class BaseSurveyHandler

Abstract MonoBehaviour that renders a UI Toolkit survey, validates required responses, and enforces attention-check rules before advancing the participant to the next study step.

[RequireComponent(typeof(UIDocument))]
public abstract class BaseSurveyHandler : MonoBehaviour

Inheritance​

Derived​

Examples​

// Minimal post-drive survey: render one page, then advance the game mode.
[RequireComponent(typeof(UIDocument))]
public sealed class PostScenarioSurvey : BaseSurveyHandler
{
[SerializeField] private SurveyPageData surveyPageData;
private List _responses = new List();

private void Start()
{
UiDoc.rootVisualElement.Q(SUBMIT_BUTTON_NAME).clicked += () =>
OnSurveySubmit(_responses = GatherSurveyResponses());

InitialModalWindowSetup();

var root = UiDoc.rootVisualElement.Q(SURVEY_ROOT_CONTAINER_NAME);
SurveyPageGeneration(root, surveyPageData, _responses);
}

// Called only after all required fields pass and attention checks clear:
protected override void MoveOntoNext() => Gamemode?.EndSession();
}

Remarks​

This class handles the full survey lifecycle: building the UI from SurveyPageData ScriptableObjects, scraping typed UI elements back into SurveyResponse objects on submission, and showing modal dialogs when required questions are unanswered or attention-check conditions fail.

Concrete subclasses implement MoveOntoNext to define what happens after a valid submission — typically advancing a scene-graph state machine or loading the next scenario. This keeps the survey logic reusable across different study flow configurations.

The attention-check system is optional (gated on AttentionCheckService.AttentionCheckEnabled) and tracks how many times a participant fails a catch question. After a configured number of failures the session is aborted, following standard MTurk/Prolific data quality protocols.

Fields​

ATTACHED_TEXTFIELD_WIDTH​

The fixed width, in pixels, of a text field attached to a radio button or checkbox option. Attached fields neither grow nor shrink so they cannot displace their sibling options.

protected const float ATTACHED_TEXTFIELD_WIDTH = 160

Field Value​

float

ATTENTION_CHECK_WINDOW_BUTTON_NAME​

The name of the button in the attention check window that allows proceeding. This is used for querying elements within the UI Toolkit.

protected const string ATTENTION_CHECK_WINDOW_BUTTON_NAME = "AttentionCheckButton"

Field Value​

string

ATTENTION_CHECK_WINDOW_NAME​

The name of the window for the attention check popup. This is used for querying elements within the UI Toolkit.

protected const string ATTENTION_CHECK_WINDOW_NAME = "AttentionCheckPopUp"

Field Value​

string

CustomSurveyPreset​

Per-survey override of the global UI preset. When empty, the project-wide SurveySettings.instance.Presets are used instead.

[Tooltip("When enabled, the generator will use the assigned preset instead of the master survey UI preset configured in the project settings.")]
[SerializeField]
protected Optional<SurveyUIPresetsAsset> CustomSurveyPreset

Field Value​

Optional<SurveyUIPresetsAsset>

Remarks​

Allows individual surveys within the same study to have distinct visual styling (e.g., a post-drive survey styled differently from a pre-session consent form) without changing the global default.

OPTION_BOX_NAME​

The name of the container that holds the group of survey options. This is used for querying elements within the UI Toolkit.

protected const string OPTION_BOX_NAME = "optionGroupBox"

Field Value​

string

The name of the canvas used for displaying popup elements in the survey. This is used for querying elements within the UI Toolkit.

protected const string POPUP_CANVAS_NAME = "PopupForground"

Field Value​

string

REQUIRED_CHECK_WINDOW_BUTTON_NAME​

The name of the button in the required field check window that allows proceeding. This is used for querying elements within the UI Toolkit.

protected const string REQUIRED_CHECK_WINDOW_BUTTON_NAME = "RequiredButton"

Field Value​

string

REQUIRED_CHECK_WINDOW_NAME​

The name of the window for the required field validation popup. This is used for querying elements within the UI Toolkit.

protected const string REQUIRED_CHECK_WINDOW_NAME = "RequiredCheckPopUp"

Field Value​

string

SUBMIT_BUTTON_NAME​

The name of the button used to submit the survey. This is used for querying elements within the UI Toolkit.

protected const string SUBMIT_BUTTON_NAME = "SubmitButton"

Field Value​

string

SURVEY_ROOT_CONTAINER_NAME​

The name of the root container where the survey is added. This is used for querying elements within the UI Toolkit.

protected const string SURVEY_ROOT_CONTAINER_NAME = "AddToMe"

Field Value​

string

Properties​

AttentionCheckService​

Service for handling attention checks during the survey.

protected AttentionCheckService AttentionCheckService { get; }

Property Value​

AttentionCheckService

Gamemode​

The current game mode.

protected GameMode Gamemode { get; }

Property Value​

GameMode

SurveyPresets​

Resolves the effective UI preset: per-survey override when set, project default otherwise.

protected SurveyVisualPresets SurveyPresets { get; }

Property Value​

SurveyVisualPresets

UiDoc​

The UIDocument associated with this survey handler.

protected UIDocument UiDoc { get; }

Property Value​

UIDocument

Methods​

ActivateAttentionCheckModalWindow()​

Activates the Attention Check modal window.

protected void ActivateAttentionCheckModalWindow()

ActivateRequiredModalWindow()​

Activates the Required Check modal window.

protected void ActivateRequiredModalWindow()

CloseModalWindow()​

Close the modal window

protected void CloseModalWindow()

GatherSurveyResponses(List<SurveyResponse>)​

Scrapes the live UI document for all optionGroupBox containers and converts their selected input elements back into a typed SurveyResponse list.

protected List<SurveyResponse> GatherSurveyResponses(List<SurveyResponse> questionMetadata)

Parameters​

NameTypeDescription
questionMetadataList<SurveyResponse>The per-question response objects created by SurveyResponse}@), already carrying title, required and attention-check metadata. Their values lists are populated in place.

Returns​

List<SurveyResponse> — The same list instance passed in, with participant values filled in.

Remarks​

UI Toolkit does not have a built-in form model, so responses are gathered by querying the element tree at submission time. The switch on concrete element types (BaseBoolField, TextField, DropdownField, SliderInt) covers every question variant generated by SurveyResponse}@). Disabled text fields paired with unchecked radio buttons are skipped so "other" text boxes are not submitted when the parent option is not selected.

The element tree only carries participant input, not the question's configuration, so the per-question metadata created during generation (required flag, attention-check values) is passed back in and populated in place. Building fresh SurveyResponse objects here would discard that metadata and silently disable both validation checks.

All values are stored as strings regardless of question type so that the SurveyResponse structure is uniform and JSON-serialisable without a type-per-question-variant class hierarchy.

InitialModalWindowSetup()​

Initializes modal windows and buttons for handling attention check and required check.

protected virtual void InitialModalWindowSetup()

IsAllAttentionCheckConditionClear(List<SurveyResponse>)​

Return whether all attention check questions in the current survey have been passed.

protected bool IsAllAttentionCheckConditionClear(List<SurveyResponse> questionnaireData)

Parameters​

NameTypeDescription
questionnaireDataList<SurveyResponse>List of the user's survey answers.

Returns​

bool — True if all attention check conditions are met, otherwise false.

IsAllRequiredSurveyAnswered(List<SurveyResponse>)​

Returns whether all required survey questions have been answered.

protected bool IsAllRequiredSurveyAnswered(List<SurveyResponse> questionnaireData)

Parameters​

NameTypeDescription
questionnaireDataList<SurveyResponse>List of the user's survey answers.

Returns​

bool — True if all required questions are answered, otherwise false.

IsAttentionCheckConditionClear(SurveyResponse)​

Evaluates whether the attention check conditions for this specific question has been passed.

protected bool IsAttentionCheckConditionClear(SurveyResponse answer)

Parameters​

NameTypeDescription
answerSurveyResponseThe user-provided answer of a specific survey question

Returns​

bool — True if the condition is met, otherwise false.

IsAttentionCheckConditionClear(IEnumerable<string>, IEnumerable<string>, LogicalCondition)​

Evaluates whether a participant's multi-value response satisfies the catch-question criteria using the specified logical operator.

protected bool IsAttentionCheckConditionClear(IEnumerable<string> storedValue, IEnumerable<string> attentionValues, SurveyItemData.AttentionCheckParameters.LogicalCondition condition)

Parameters​

NameTypeDescription
storedValueIEnumerable<string>Values the participant selected or entered.
attentionValuesIEnumerable<string>Correct expected values for this catch question.
conditionSurveyItemData.AttentionCheckParameters.LogicalConditionAND requires all expected values to be present in the correct quantity; OR requires at least one match.

Returns​

bool — true if the attention check passes; false if the participant failed.

Remarks​

AND validation uses group-by counts rather than simple set intersection so that duplicate required values (e.g., a catch question asking the participant to select "Option A" twice) are handled correctly. The optimised O(m+n) approach avoids an O(m×n) nested loop for surveys with large option sets.

OR validation uses Intersect, which is sufficient because only one match is required regardless of duplicates.

MoveOntoNext()​

Advances the participant to the next study step after a valid survey submission. Implemented by concrete subclasses to match the specific study flow (e.g., load next scene, advance scene-graph state, unlock next timeline segment).

protected abstract void MoveOntoNext()

OnAttentionButtonSubmit()​

Handles submission of the attention check window.

protected virtual void OnAttentionButtonSubmit()

OnRequiredButtonSubmit()​

Handles submission of the required check window.

protected virtual void OnRequiredButtonSubmit()

OnSurveySubmit(List<SurveyResponse>)​

Validates and processes a survey submission: checks required fields first, then the attention-check catch question, and only calls MoveOntoNext when both pass.

protected virtual void OnSurveySubmit(List<SurveyResponse> submitedAnswers)

Parameters​

NameTypeDescription
submitedAnswersList<SurveyResponse>Responses gathered by SurveyResponse}).

Remarks​

The required check runs before the attention check intentionally — a participant who didn't answer a required question should be told to complete the form, not shown an attention-check failure popup. The submit button is disabled on success to prevent double-submission, which would trigger MoveOntoNext twice.

When the attention check fails, the failure counter is incremented before showing the modal. If the participant has exceeded the allowed failure count, OnAttentionButtonSubmit calls AttentionCheckService.AttentionAbort rather than advancing, following standard data-quality protocols for online studies.

SurveyPageGeneration(GroupBox, SurveyPageData, in List<SurveyResponse>)​

Generates a survey page with questions and options.

protected void SurveyPageGeneration(GroupBox _rootGroupBox, SurveyPageData pageData, in List<SurveyResponse> questionsDatas)

Parameters​

NameTypeDescription
_rootGroupBoxGroupBoxThe root GroupBox to add the generated survey page to.
pageDataSurveyPageDataThe data defining the page.
questionsDatasList<SurveyResponse>A list of SurveyResponse objects representing the survey questions.
  • Examples
  • Remarks
  • Fields
    • ATTACHED_TEXTFIELD_WIDTH
    • ATTENTION_CHECK_WINDOW_BUTTON_NAME
    • ATTENTION_CHECK_WINDOW_NAME
    • CustomSurveyPreset
    • OPTION_BOX_NAME
    • POPUP_CANVAS_NAME
    • REQUIRED_CHECK_WINDOW_BUTTON_NAME
    • REQUIRED_CHECK_WINDOW_NAME
    • SUBMIT_BUTTON_NAME
    • SURVEY_ROOT_CONTAINER_NAME
  • Properties
    • AttentionCheckService
    • Gamemode
    • SurveyPresets
    • UiDoc
  • Methods
    • ActivateAttentionCheckModalWindow()
    • ActivateRequiredModalWindow()
    • CloseModalWindow()
    • GatherSurveyResponses(List<SurveyResponse>)
    • InitialModalWindowSetup()
    • IsAllAttentionCheckConditionClear(List<SurveyResponse>)
    • IsAllRequiredSurveyAnswered(List<SurveyResponse>)
    • IsAttentionCheckConditionClear(SurveyResponse)
    • IsAttentionCheckConditionClear(IEnumerable<string>, IEnumerable<string>, LogicalCondition)
    • MoveOntoNext()
    • OnAttentionButtonSubmit()
    • OnRequiredButtonSubmit()
    • OnSurveySubmit(List<SurveyResponse>)
    • SurveyPageGeneration(GroupBox, SurveyPageData, in List<SurveyResponse>)