Skip to main content

06 Conditional Event: Visual Logic Builder

๐Ÿ“‹ Overviewโ€‹

Usually, checking if a door should open requires code like: if (powerOn && (isAdmin || isLucky)). This demo demonstrates the Visual Condition Tree Builder, which lets you create complex, nested validation rules directly in the Editorโ€”removing the need for if/else checks in your scripts.

๐Ÿ’ก What You'll Learn
  • How to build complex logic trees without code
  • How to reference scene objects in conditions
  • How to use AND/OR groups for branching logic
  • How conditions act as gatekeepers for event callbacks

๐ŸŽฌ Demo Sceneโ€‹

Assets/TinyGiants/GameEventSystem/Demo/06_ConditionalEvent/06_ConditionalEvent.unity

Scene Compositionโ€‹

UI Layer (Canvas):

  • ๐ŸŽฎ Power Toggle Button - Top left corner

    • "Toggle Power (On)" / "Toggle Power (Off)"
    • Triggers ConditionalEventRaiser.TogglePower()
    • Controls the global SecurityGrid.IsPowerOn state
  • ๐ŸŽฎ Four Access Card Buttons - Bottom of screen

    • "Swipe GuestCard" โ†’ ConditionalEventRaiser.SwipeGuestCard() (Level 1, Visitor dept)
    • "Swipe StaffCard" โ†’ ConditionalEventRaiser.SwipeStaffCard() (Level 3, Management dept)
    • "Swipe AdminCard" โ†’ ConditionalEventRaiser.SwipeAdminCard() (Level 5, Director dept)
    • "Attempt Hacking" โ†’ ConditionalEventRaiser.AttemptHacking() (Level 0, DarkWeb dept)

Game Logic Layer (Demo Scripts):

  • ๐Ÿ“ค ConditionalEventRaiser - GameObject with the raiser script

    • Constructs AccessCard objects with different credentials
    • Raises OnAccessCard event for validation
    • Has NO validation logicโ€”just passes data
  • ๐Ÿ“ฅ ConditionalEventReceiver - GameObject with the receiver script

    • Contains OpenVault() method with ZERO conditional logic
    • Simply plays door animation when called
    • Assumes if called, all conditions passed
  • ๐Ÿ”Œ SecurityGrid - Scene object holding system state

    • Public property: IsPowerOn (bool)
    • Condition tree reads this value directly from scene instance

Visual Feedback Layer (Demo Objects):

  • ๐Ÿšช VaultDoorSystem - Massive double doors
    • Left and right doors slide open/closed
    • Status text displays: "LOCKED" / "ACCESS GRANTED" / "CLOSING..."
    • Steam VFX plays when doors open
  • ๐Ÿ’ก Power Indicator - Green sphere light
    • Glows when power is ON
    • Dims when power is OFF
  • ๐Ÿ–ผ๏ธ Screen Vignette - Fullscreen overlay
    • Green flash when power turns ON
    • Red flash when power turns OFF

๐ŸŽฎ How to Interactโ€‹

The Logic Gate Challengeโ€‹

The vault opens ONLY IF this condition evaluates to true:

[โšก Power ON]  AND  ([๐Ÿ… Admin] Level  OR  [๐Ÿท๏ธ Valid Department]  OR  [๐ŸŽฒ Lucky Hacker])

Step 1: Enter Play Modeโ€‹

Press the Play button in Unity. The vault should show "LOCKED" in red.


Step 2: Test with Power ON (Correct Setup)โ€‹

Ensure Power is ON:

  • Look at the top-left button: Should show "Toggle Power (On)"
  • Look at the power indicator (green sphere): Should be glowing
  • Screen vignette flashes green when toggled ON

Click "Swipe StaffCard":

  • Credentials: Level 3, Department "Management"
  • Logic Path:
    • โœ… Power ON โ†’ Pass
    • โŒ Level 3 < 4 โ†’ Fail (Admin check)
    • โœ… Department "Management" is in whitelist โ†’ Pass
    • Result: One branch passed in OR group
  • Outcome: ๐ŸŸข ACCESS GRANTED
    • Status text turns green
    • Steam VFX erupts from door base
    • Doors slide open smoothly
    • Doors close after 2 seconds
  • Console: [Vault] ACCESS GRANTED to Staff_Alice. Opening doors.

Click "Swipe AdminCard":

  • Credentials: Level 5, Department "Director"
  • Logic Path:
    • โœ… Power ON โ†’ Pass
    • โœ… Level 5 >= 4 โ†’ Pass (Admin check succeeds immediately)
    • Result: First condition in OR group passed
  • Outcome: ๐ŸŸข ACCESS GRANTED

Click "Swipe GuestCard":

  • Credentials: Level 1, Department "Visitor"
  • Logic Path:
    • โœ… Power ON โ†’ Pass
    • โŒ Level 1 < 4 โ†’ Fail (Admin check)
    • โŒ Department "Visitor" not in whitelist โ†’ Fail
    • ๐ŸŽฒ Random(0-100) > 70 in nested AND group โ†’ ~30% chance
    • Result: Most likely all branches fail
  • Outcome: ๐Ÿ”ด LOCKED (90% of the time)
    • Vault remains closed
    • Status text stays red
  • Console: (No receiver log because condition failed)

Step 3: Test with Power OFF (Failure Case)โ€‹

Click "Toggle Power" (Turn OFF):

  • Button text changes to "Toggle Power (Off)"
  • Power indicator dims
  • Screen vignette flashes RED

Click "Swipe AdminCard":

  • Credentials: Level 5 (Admin level)
  • Logic Path:
    • โŒ Power OFF โ†’ Fail at root AND condition
    • Evaluation stops immediately (short-circuit)
  • Outcome: ๐Ÿ”ด LOCKED
    • Even admins cannot bypass the power requirement
    • Receiver method is NEVER called
  • Console: [Terminal] Scanning... (but no vault log)
๐Ÿ” Security Design

The AND logic at the root ensures that no credential can bypass the power requirement. This demonstrates how condition trees can enforce hard requirements.


๐Ÿ—๏ธ Scene Architectureโ€‹

The Condition Tree Structureโ€‹

The vault's access logic is implemented as a visual tree in the Behavior Window:

๐ŸŸฆ ROOT (AND) โž” Must pass BOTH major branches
โ”‚
โ”œโ”€ โšก SecurityGrid.IsPowerOn == true โž” [Power Status Check]
โ”‚
โ””โ”€ ๐ŸŸง Branch 2 (OR) โž” Must pass AT LEAST ONE below
โ”‚
โ”œโ”€ ๐Ÿ… Arg.securityLevel >= 4 โž” [High Clearance]
โ”œโ”€ ๐Ÿท๏ธ Arg.department โˆˆ [Mgmt, IT] โž” [Dept. Validation]
โ”œโ”€ ๐ŸŽฒ Random(0-100) > 90 โž” [10% Luck Pass]
โ”‚
โ””โ”€ ๐ŸŸฆ Nested Group (AND) โž” Combined low-level check
โ”œโ”€ ๐Ÿ”ข Arg.securityLevel >= 1 โž” [Basic Access]
โ””โ”€ ๐ŸŽฒ Random(0-100) > 70 โž” [30% Luck Pass]

Event Definitionโ€‹

Game Event Editor

Event NameTypePurpose
OnAccessCardGameEvent<AccessCard>Validates card credentials through condition tree

The AccessCard Data Structure:

[System.Serializable]
public class AccessCard
{
public string holderName; // "Staff_Alice", "Admin_Root", etc.
public int securityLevel; // 1=Guest, 3=Staff, 5=Admin
public string department; // "Management", "IT", "Visitor", etc.
}

Behavior Configuration with Condition Treeโ€‹

Click the (AccessCard) icon in the Behavior column to open the Behavior Window:

Condition Tree

Root AND Group:

  • Condition 1: Scene Object Reference
    • Source: SecurityGrid GameObject in scene
    • Property: IsPowerOn (bool)
    • Operator: == (Equals)
    • Target: true
    • Purpose: Hard requirementโ€”power must be ON

Nested OR Group: The OR group provides multiple valid paths to access:

  • Condition A: Event Argument Check

    • Source: Arg.securityLevel (int from AccessCard)
    • Operator: >= (Greater Or Equal)
    • Target: 4
    • Purpose: Admin-level credentials
  • Condition B: List Membership Check

    • Source: Arg.department (string from AccessCard)
    • Operator: In List (Contained In)
    • Target: Constant List ["Management", "IT"]
    • Purpose: Whitelisted departments
  • Condition C: Random Chance

    • Source: Random Value (0-100 range)
    • Operator: > (Greater)
    • Target: 90
    • Purpose: 10% lucky bypass for hackers
  • Nested AND Group: Guest Access Logic

    • Sub-condition 1: Arg.securityLevel >= 1 (Valid card)
    • Sub-condition 2: Random(0-100) > 70 (30% chance)
    • Purpose: Guests have lower chance but must have valid card
๐ŸŽจ Drag & Drop Building

You can build this tree visually in the Behavior Window:

  1. Click "+ Condition" to add individual checks
  2. Click "+ Group" to add AND/OR containers
  3. Drag the โ‰ก handle to reorder conditions
  4. Switch between AND/OR logic by clicking the group label

Sender Setup (ConditionalEventRaiser)โ€‹

Select the ConditionalEventRaiser GameObject:

ConditionalEventRaiser Inspector

Event Channel:

  • Request Access Event: OnAccessCard

Scene Reference:

  • Security Grid: SecurityGrid GameObject (for power toggle functionality)
  • Screen Vignette: UI overlay for visual power feedback

How Cards Work:

// Guest Card (Relies on luck)
SwipeGuestCard() โ†’ AccessCard("Guest_Bob", 1, "Visitor")

// Staff Card (Valid department)
SwipeStaffCard() โ†’ AccessCard("Staff_Alice", 3, "Management")

// Admin Card (High level)
SwipeAdminCard() โ†’ AccessCard("Admin_Root", 5, "Director")

// Hacker (Pure randomness)
AttemptHacking() โ†’ AccessCard("Unknown_Hacker", 0, "DarkWeb")

Receiver Setup (ConditionalEventReceiver)โ€‹

Select the ConditionalEventReceiver GameObject:

ConditionalEventReceiver Inspector

Vault Visuals:

  • Door ROOT: VaultDoorSystem (Transform)
  • Left Door: DoorLeft (Transform) - slides left when opening
  • Right Door: DoorRight (Transform) - slides right when opening
  • Steam VFX Prefab: Particle system for door opening effect

Feedback:

  • Status Text: StatusText (TextMeshPro) - displays access status

Behavior Binding:

  • Event: OnAccessCard
  • Method: ConditionalEventReceiver.OpenVault(AccessCard card)
  • Condition Tree: Acts as gatekeeper (configured above)
๐ŸŽฏ Zero-Logic Receiver

The OpenVault() method contains NO conditional checks. It's called only if the condition tree evaluates to true. This separates validation logic (data layer) from action logic (behavior layer).


๐Ÿ’ป Code Breakdownโ€‹

๐Ÿ“ค ConditionalEventRaiser.cs (Sender)โ€‹

using UnityEngine;
using TinyGiants.GameEventSystem.Runtime;

public class ConditionalEventRaiser : MonoBehaviour
{
[Header("Event Channel")]
[GameEventDropdown] public GameEvent<AccessCard> requestAccessEvent;

[Header("Scene Reference")]
[SerializeField] private SecurityGrid securityGrid;

public void SwipeGuestCard()
{
// Level 1, Dept "Visitor"
// Fails level check, fails dept check
// Relies on Random > 70 in nested AND group (~30% chance)
SendRequest("Guest_Bob", 1, "Visitor");
}

public void SwipeStaffCard()
{
// Level 3, Dept "Management"
// Fails level check (3 < 4)
// Passes department check (Management is whitelisted)
SendRequest("Staff_Alice", 3, "Management");
}

public void SwipeAdminCard()
{
// Level 5
// Passes level check immediately (5 >= 4)
SendRequest("Admin_Root", 5, "Director");
}

public void AttemptHacking()
{
// Level 0
// Pure reliance on Random > 90 (10% chance)
SendRequest("Unknown_Hacker", 0, "DarkWeb");
}

private void SendRequest(string name, int level, string dept)
{
if (requestAccessEvent == null) return;

// Construct the data packet
AccessCard card = new AccessCard(name, level, dept);

// Raise the event
// The condition tree evaluates BEFORE calling the receiver
requestAccessEvent.Raise(card);

Debug.Log($"[Terminal] Scanning... Name: {name} | Lv: {level} | Dept: {dept}");
}
}

Key Points:

  • ๐ŸŽฏ No Validation - Sender just creates data and raises event
  • ๐Ÿ“ฆ Data Construction - Each button creates a unique credential profile
  • ๐Ÿ”‡ Zero Logic - No knowledge of what conditions must be met

๐Ÿ“ฅ ConditionalEventReceiver.cs (Listener)โ€‹

using UnityEngine;
using TMPro;
using System.Collections;

public class ConditionalEventReceiver : MonoBehaviour
{
[Header("Vault Visuals")]
[SerializeField] private Transform doorROOT;
[SerializeField] private Transform leftDoor;
[SerializeField] private Transform rightDoor;
[SerializeField] private ParticleSystem steamVFXPrefab;

[Header("Feedback")]
[SerializeField] private TextMeshPro statusText;

private Vector3 _leftClosedPos;
private Vector3 _rightClosedPos;

private void Start()
{
// Store closed positions for animation
if(leftDoor) _leftClosedPos = leftDoor.localPosition;
if(rightDoor) _rightClosedPos = rightDoor.localPosition;

UpdateStatusText("LOCKED", Color.red);
}

/// <summary>
/// [Event Callback - Condition Gated]
///
/// CRITICAL: This method contains NO validation logic!
///
/// The GameEvent Condition Tree acts as the gatekeeper.
/// If this method executes, it means ALL conditions evaluated to TRUE:
/// - Power is ON
/// - AND at least one of: Admin level, Valid dept, or Lucky random
///
/// This separation allows designers to modify access rules in the Editor
/// without touching code.
/// </summary>
public void OpenVault(AccessCard card)
{
if (_isOpen) return;

Debug.Log($"<color=green>[Vault] ACCESS GRANTED to {card.holderName}. " +
"Opening doors.</color>");

StartCoroutine(OpenSequenceRoutine(card.holderName));
}

private IEnumerator OpenSequenceRoutine(string name)
{
_isOpen = true;
UpdateStatusText("ACCESS GRANTED", Color.green);

// Spawn steam VFX
if (doorROOT != null && steamVFXPrefab != null)
{
Vector3 spawnPos = doorROOT.position;
spawnPos.y -= 2.6f;

var vfxInstance = Instantiate(steamVFXPrefab, spawnPos, Quaternion.identity);
vfxInstance.Play();
Destroy(vfxInstance.gameObject, 2.0f);
}

// Open doors (slide outward)
float t = 0;
while(t < 1f)
{
t += Time.deltaTime * 2f;
if(leftDoor)
leftDoor.localPosition = Vector3.Lerp(_leftClosedPos,
_leftClosedPos + Vector3.left * 1.2f, t);
if(rightDoor)
rightDoor.localPosition = Vector3.Lerp(_rightClosedPos,
_rightClosedPos + Vector3.right * 1.2f, t);
yield return null;
}

yield return new WaitForSeconds(2.0f);
UpdateStatusText("CLOSING...", Color.yellow);

// Close doors (slide back)
t = 0;
while(t < 1f)
{
t += Time.deltaTime * 2f;
if(leftDoor)
leftDoor.localPosition = Vector3.Lerp(_leftClosedPos + Vector3.left * 1.2f,
_leftClosedPos, t);
if(rightDoor)
rightDoor.localPosition = Vector3.Lerp(_rightClosedPos + Vector3.right * 1.2f,
_rightClosedPos, t);
yield return null;
}

_isOpen = false;
UpdateStatusText("LOCKED", Color.red);
}

private void UpdateStatusText(string text, Color col)
{
if (statusText)
{
statusText.text = text;
statusText.color = col;
}
}
}

Key Points:

  • ๐ŸŽฏ Zero Conditional Logic - No if statements checking credentials
  • ๐Ÿ”“ Trust-Based Execution - If called, all conditions already passed
  • ๐ŸŽจ Pure Presentation - Just plays door animation and VFX
  • ๐Ÿ—๏ธ Separation of Concerns - Validation (data) vs Action (behavior)

๐Ÿ”Œ SecurityGrid.cs (Scene State)โ€‹

using UnityEngine;

public class SecurityGrid : MonoBehaviour
{
// This public property is read by the condition tree
public bool IsPowerOn = true;

public void TogglePower()
{
IsPowerOn = !IsPowerOn;

// Update visuals...
Debug.Log($"[Environment] Power System is now: {(IsPowerOn ? "ONLINE" : "OFFLINE")}");
}
}

Key Points:

  • ๐Ÿ”Œ Public State - IsPowerOn is accessible to condition tree
  • ๐Ÿ“ Scene Object - Condition references this specific GameObject instance
  • ๐ŸŽฎ Runtime Changes - Toggling power immediately affects condition evaluation

๐Ÿ”‘ Key Takeawaysโ€‹

ConceptImplementation
๐ŸŽฏ Visual LogicBuild complex conditions without writing code
๐ŸŒณ Tree StructureAND/OR groups allow nested branching logic
๐Ÿ“ Scene ReferencesRead properties directly from GameObjects in the scene
๐ŸŽฒ Random ConditionsBuilt-in random value source for chance-based logic
๐Ÿ”€ Argument AccessReference event data properties in conditions
๐Ÿšช Gatekeeper PatternConditions control whether callbacks execute
๐ŸŽ“ Design Insight

The Visual Condition Tree is perfect for:

  • Access control systems - Doors, terminals, restricted areas
  • Quest requirements - Check multiple conditions before quest completion
  • Buff activation - Only apply effects if prerequisites met
  • AI behavior - Decision trees for enemy reactions
  • Loot systems - Validate drop conditions (level, luck, location)

By moving logic into data (the condition tree asset), you enable designers to tune gameplay rules without programmer intervention!


๐ŸŽฏ What's Next?โ€‹

You've mastered conditional logic. Now let's explore time-based event control with delays and scheduling.

Next Chapter: Learn about delayed execution in 07 Delayed Event