314 lines
11 KiB
C#
314 lines
11 KiB
C#
/*
|
|
* GameUI.cs - Unity UI Toolkit 2.0+ Game UI Entry Point
|
|
*
|
|
* Production-ready example demonstrating:
|
|
* - Unity UI Toolkit 2.0+ declarative patterns
|
|
* - ECS (Entity Component System) UI architecture
|
|
* - DDA 3.0 integration
|
|
* - Accessibility patterns (WCAG 3.0+)
|
|
* - Spatial computing (XR, eye-tracking)
|
|
* - Ethical engagement mechanics
|
|
*
|
|
* © 2026 - Agent Guardrails Template
|
|
*/
|
|
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using UnityEngine.UI.Core;
|
|
using Unity.Entities;
|
|
using Unity.DOTS;
|
|
using Unity.Jobs;
|
|
using Unity.Burst;
|
|
using AgentGuardrails.DDA;
|
|
using AgentGuardrails.Accessibility;
|
|
using AgentGuardrails.Ethical;
|
|
|
|
namespace AgentGuardrails.UnityUI
|
|
{
|
|
/// <summary>
|
|
/// Main Game UI Controller using Unity UI Toolkit 2.0+
|
|
/// Integrates ECS architecture with declarative UI patterns
|
|
/// </summary>
|
|
public class GameUI : MonoBehaviour
|
|
{
|
|
private EntityManager entityManager;
|
|
private DDAManager ddaManager;
|
|
private AccessibilityPreferences accessibilityPrefs;
|
|
private EthicalEngagement ethicalEngagement;
|
|
|
|
private Entity uiEntity;
|
|
private Entity hudEntity;
|
|
private Entity lootEntity;
|
|
private Entity skillTreeEntity;
|
|
|
|
public void Awake()
|
|
{
|
|
// Initialize ECS manager
|
|
entityManager = EntityManager.Instance;
|
|
|
|
// Initialize DDA 3.0 system
|
|
ddaManager = DDAManager.Instance;
|
|
|
|
// Initialize accessibility preferences
|
|
accessibilityPrefs = AccessibilityPreferences.Instance;
|
|
|
|
// Initialize ethical engagement system
|
|
ethicalEngagement = EthicalEngagement.Instance;
|
|
|
|
// Create UI entities through ECS
|
|
CreateUIEntities();
|
|
|
|
// Build UI hierarchy
|
|
BuildUIHierarchy();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates UI entities using ECS pattern
|
|
/// Each UI element is an entity with components
|
|
/// </summary>
|
|
private void CreateUIEntities()
|
|
{
|
|
// Main UI container entity
|
|
uiEntity = entityManager.CreateEntity();
|
|
uiEntity.AddComponent<UIElementComponent>();
|
|
uiEntity.AddComponent<LayoutComponent>();
|
|
uiEntity.AddComponent<HapticFeedbackComponent>();
|
|
|
|
// HUD entity - Action Phase
|
|
hudEntity = entityManager.CreateEntity();
|
|
hudEntity.AddComponent<CombatHUDComponent>();
|
|
hudEntity.AddComponent<DDAAdaptationComponent>();
|
|
|
|
// Loot panel entity - Reward Phase
|
|
lootEntity = entityManager.CreateEntity();
|
|
lootEntity.AddComponent<LootPanelComponent>();
|
|
lootEntity.AddComponent<TransparentRNGComponent>();
|
|
|
|
// Skill tree entity - Upgrade Phase
|
|
skillTreeEntity = entityManager.CreateEntity();
|
|
skillTreeEntity.AddComponent<SkillTreeComponent>();
|
|
skillTreeEntity.AddComponent<VolumetricUIComponent>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Builds UI hierarchy with Material-like theming
|
|
/// Core loop: Action → Reward → Upgrade
|
|
/// </summary>
|
|
private void BuildUIHierarchy()
|
|
{
|
|
var rootPanel = new Panel("GameUIRoot");
|
|
rootPanel.style.flexDirection = FlexDirection.Vertical;
|
|
|
|
// Combat HUD - Action Phase
|
|
var combatHUD = CreateCombatHUD();
|
|
combatHUD.style.flexGrow = 1f;
|
|
rootPanel.Add(combatHUD);
|
|
|
|
// Loot Panel - Reward Phase
|
|
var lootPanel = CreateLootPanel();
|
|
lootPanel.style.flexGrow = 1f;
|
|
rootPanel.Add(lootPanel);
|
|
|
|
// Skill Tree - Upgrade Phase
|
|
var skillTree = CreateSkillTree();
|
|
skillTree.style.flexGrow = 1f;
|
|
rootPanel.Add(skillTree);
|
|
|
|
// Rest State Indicator - Ethical Engagement
|
|
var restStateIndicator = CreateRestStateIndicator();
|
|
restStateIndicator.style.flexGrow = 0.5f;
|
|
rootPanel.Add(restStateIndicator);
|
|
|
|
// Apply accessibility styles
|
|
ApplyAccessibilityStyles(rootPanel);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates Combat HUD with DDA 3.0 visual adaptation
|
|
/// Reactive health bars with shape+color redundancy
|
|
/// </summary>
|
|
private Panel CreateCombatHUD()
|
|
{
|
|
var hudPanel = new Panel("CombatHUD");
|
|
hudPanel.style.flexDirection = FlexDirection.Horizontal;
|
|
|
|
// Player health bar - WCAG 3.0+ compliance
|
|
var playerHealthBar = new HealthBar("PlayerHealth");
|
|
playerHealthBar.healthState = HealthState.Normal;
|
|
playerHealthBar.shapeIndicator = true; // Colorblindness independence
|
|
playerHealthBar.ddaOpacity = ddaManager.UIOpacityFactor;
|
|
|
|
// Eye-tracking dwell indicator
|
|
playerHealthBar.dwellThreshold = 150f; // 150ms for eye-tracking
|
|
|
|
hudPanel.Add(playerHealthBar);
|
|
|
|
// Enemy health bar
|
|
var enemyHealthBar = new HealthBar("EnemyHealth");
|
|
enemyHealthBar.ddaTier = ddaManager.CurrentTier;
|
|
|
|
hudPanel.Add(enemyHealthBar);
|
|
|
|
return hudPanel;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates Loot Panel with transparent RNG display
|
|
/// Ethical engagement: no obfuscated drop rates
|
|
/// </summary>
|
|
private Panel CreateLootPanel()
|
|
{
|
|
var lootPanel = new Panel("LootPanel");
|
|
lootPanel.style.flexDirection = FlexDirection.Vertical;
|
|
|
|
// Transparent loot table display
|
|
var lootTableLabel = new Label("Loot Table Transparency");
|
|
lootPanel.Add(lootTableLabel);
|
|
|
|
// Inline drop rate display for each item
|
|
var currentLootTable = LootTableManager.CurrentTable;
|
|
foreach (var item in currentLootTable.Items)
|
|
{
|
|
var itemRow = new Panel("LootItemRow");
|
|
itemRow.Add(new Label(item.Name));
|
|
itemRow.Add(new Label($"Drop Rate: {item.DropRate}%"));
|
|
lootPanel.Add(itemRow);
|
|
}
|
|
|
|
// Pity timer visualization
|
|
var pityTimerProgress = new ProgressBar("PityTimer");
|
|
pityTimerProgress.value = currentLootTable.PityTimerCount;
|
|
pityTimerProgress.maxValue = currentLootTable.PityTimerMax;
|
|
lootPanel.Add(pityTimerProgress);
|
|
|
|
// Volumetric UI for legendary items
|
|
if (currentLootTable.IsLegendary())
|
|
{
|
|
var volumetricRenderer = new VolumetricRenderer();
|
|
volumetricRenderer.SetDepth(0.5f); // Z-axis parallax
|
|
lootPanel.Add(volumetricRenderer);
|
|
}
|
|
|
|
return lootPanel;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates Skill Tree with DOTS pathfinding
|
|
/// Uses GPU instancing for efficient node rendering
|
|
/// </summary>
|
|
private Panel CreateSkillTree()
|
|
{
|
|
var skillTreePanel = new Panel("SkillTree");
|
|
skillTreePanel.style.flexDirection = FlexDirection.Vertical;
|
|
|
|
// DOTS-based skill tree rendering
|
|
var skillTreeJob = new SkillTreeLayoutJob
|
|
{
|
|
skillPoints = GameManager.Instance.SkillPoints,
|
|
unlockedSkills = GameManager.Instance.UnlockedSkills,
|
|
depthFactor = 0.3f // Parallax for spatial computing
|
|
};
|
|
|
|
// Schedule job on burst-compiled thread
|
|
var handle = skillTreeJob.Schedule();
|
|
handle.Complete();
|
|
|
|
// GPU instancing for skill nodes
|
|
skillTreePanel.SetGPUInstancing(true);
|
|
|
|
return skillTreePanel;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates Rest State Indicator for ethical engagement
|
|
/// Mandatory calm state after intense sessions
|
|
/// </summary>
|
|
private Panel CreateRestStateIndicator()
|
|
{
|
|
var restStatePanel = new Panel("RestStateIndicator");
|
|
restStatePanel.style.backgroundColor = new Color(0.2f, 0.4f, 0.2f);
|
|
|
|
var restStateLabel = new Label("Rest State Activated - Calm Mode");
|
|
restStatePanel.Add(restStateLabel);
|
|
|
|
// Timer for rest state trigger
|
|
var restStateTimer = 0;
|
|
restStatePanel.RegisterCallback(
|
|
OnUpdate => {
|
|
restStateTimer++;
|
|
if (GameManager.Instance.SessionDuration > 45 && restStateTimer >= 5)
|
|
{
|
|
ethicalEngagement.EnterRestState();
|
|
}
|
|
}
|
|
);
|
|
|
|
return restStatePanel;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Applies WCAG 3.0+ accessibility styles
|
|
/// Minimum contrast ratio: 4.5:1 (Level AA)
|
|
/// </summary>
|
|
private void ApplyAccessibilityStyles(Panel rootPanel)
|
|
{
|
|
// High contrast mode for colorblindness
|
|
if (accessibilityPrefs.ColorblindnessMode != ColorblindnessMode.None)
|
|
{
|
|
rootPanel.style.backgroundColor = Color.white;
|
|
rootPanel.SetBackground("high-contrast-border");
|
|
}
|
|
|
|
// Shape + icon redundancy for all interactive elements
|
|
rootPanel.SetShapeRedundance(true);
|
|
|
|
// Eye-tracking support: dwell-based selection
|
|
rootPanel.dwellThreshold = 150f;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Triggers haptic feedback for UI interactions
|
|
/// Scales intensity with DDA 3.0 tier
|
|
/// </summary>
|
|
private void TriggerHapticFeedback(UIEvent event)
|
|
{
|
|
var hapticComponent = uiEntity.Get<HapticFeedbackComponent>();
|
|
hapticComponent.ApplyProfile(HapticProfile.FromEvent(event));
|
|
}
|
|
}
|
|
|
|
// Component definitions for ECS
|
|
public struct UIElementComponent : IComponent { }
|
|
public struct LayoutComponent : IComponent { }
|
|
public struct HapticFeedbackComponent : IComponent { }
|
|
public struct CombatHUDComponent : IComponent { }
|
|
public struct DDAAdaptationComponent : IComponent { }
|
|
public struct LootPanelComponent : IComponent { }
|
|
public struct TransparentRNGComponent : IComponent { }
|
|
public struct SkillTreeComponent : IComponent { }
|
|
public struct VolumetricUIComponent : IComponent { }
|
|
|
|
// DOTS job for skill tree layout
|
|
[BurstCompile]
|
|
public struct SkillTreeLayoutJob : IJob
|
|
{
|
|
public int skillPoints;
|
|
public NativeArray<Skill> unlockedSkills;
|
|
public float depthFactor;
|
|
|
|
public void Execute()
|
|
{
|
|
// DOTS-based skill tree layout calculation
|
|
for (int i = 0; i < unlockedSkills.Length; i++)
|
|
{
|
|
var skill = unlockedSkills[i];
|
|
skill.layoutPosition = CalculateSkillPosition(skill, depthFactor);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Placeholder data structures
|
|
public enum HealthState { Normal, Critical }
|
|
public enum ColorblindnessMode { None, Protanopia, Deuteranopia, Tritanopia }
|
|
public enum UIEvent { CombatTrigger, CombatSuccess, LootReveal, SkillUnlock }
|
|
} |