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
POPUP_CANVAS_NAME
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
SurveyPresets
Resolves the effective UI preset: per-survey override when set, project default otherwise.
protected SurveyVisualPresets SurveyPresets { get; }
Property Value
UiDoc
The UIDocument associated with this survey handler.
protected UIDocument UiDoc { get; }
Property Value
Methods
ActivateAttentionCheckModalWindow()
Activates the Attention Check modal window.
protected void ActivateAttentionCheckModalWindow()
ActivateRequiredModalWindow()
Activates the Required Check modal window.
protected void ActivateRequiredModalWindow()
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
| Name | Type | Description |
|---|---|---|
questionMetadata | List<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
| Name | Type | Description |
|---|---|---|
questionnaireData | List<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
| Name | Type | Description |
|---|---|---|
questionnaireData | List<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
| Name | Type | Description |
|---|---|---|
answer | SurveyResponse | The 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
| Name | Type | Description |
|---|---|---|
storedValue | IEnumerable<string> | Values the participant selected or entered. |
attentionValues | IEnumerable<string> | Correct expected values for this catch question. |
condition | SurveyItemData.AttentionCheckParameters.LogicalCondition | AND 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
| Name | Type | Description |
|---|---|---|
submitedAnswers | List<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
| Name | Type | Description |
|---|---|---|
_rootGroupBox | GroupBox | The root GroupBox to add the generated survey page to. |
pageData | SurveyPageData | The data defining the page. |
questionsDatas | List<SurveyResponse> | A list of SurveyResponse objects representing the survey questions. |