370 lines
12 KiB
C#
370 lines
12 KiB
C#
/*
|
|
* dda-system.cs - DDA 3.0 Enemy AI Heuristic Adjustment
|
|
*
|
|
* Production-ready example demonstrating:
|
|
* - Dynamic Difficulty Adjustment (DDA 3.0)
|
|
* - Enemy AI heuristic adaptation
|
|
* - UI visual adaptation based on player stress
|
|
* - Performance metrics drive aesthetic adjustments
|
|
* - Emergent gameplay through difficulty scaling
|
|
*
|
|
* © 2026 - Agent Guardrails Template
|
|
*/
|
|
|
|
using UnityEngine;
|
|
using Unity.Entities;
|
|
using Unity.DOTS;
|
|
using Unity.Jobs;
|
|
using Unity.Burst;
|
|
using Unity.Collections;
|
|
using AgentGuardrails.Accessibility;
|
|
using AgentGuardrails.Ethical;
|
|
|
|
namespace AgentGuardrails.DDA
|
|
{
|
|
/// <summary>
|
|
/// DDA 3.0 Manager - Dynamic Difficulty Adjustment System
|
|
/// Adjusts enemy AI heuristics and UI based on player performance
|
|
/// </summary>
|
|
public class DDAManager : MonoBehaviour
|
|
{
|
|
private static DDAManager _instance;
|
|
public static DDAManager Instance => _instance;
|
|
|
|
private EntityManager entityManager;
|
|
private NativeArray<Entity> enemyEntities;
|
|
private PlayerPerformanceMetrics performanceMetrics;
|
|
|
|
public DifficultyTier CurrentTier { get; private set; }
|
|
public float UIOpacityFactor { get; private set; }
|
|
|
|
public enum DifficultyTier
|
|
{
|
|
Difficult, // Stressed players - reduced complexity
|
|
Normal, // Standard presentation
|
|
Relaxed // High engagement - enhanced feedback
|
|
}
|
|
|
|
public void Awake()
|
|
{
|
|
_instance = this;
|
|
entityManager = EntityManager.Instance;
|
|
enemyEntities = new NativeArray<Entity>(50, Allocator.Persistent);
|
|
performanceMetrics = new PlayerPerformanceMetrics();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adjusts enemy AI heuristics based on player performance
|
|
/// DDA 3.0 core: adapts difficulty to player KDR and stress
|
|
/// </summary>
|
|
public void AdjustEnemyHeuristics(float playerKDR, int sessionDuration)
|
|
{
|
|
// Calculate DDA tier from performance metrics
|
|
CurrentTier = CalculateDifficultyTier(playerKDR, sessionDuration);
|
|
|
|
// Adjust enemy AI heuristics
|
|
AdjustEnemyAI(CurrentTier);
|
|
|
|
// Adjust UI opacity for stressed players
|
|
UIOpacityFactor = CalculateUIOpacity(CurrentTier);
|
|
|
|
// Notify ethical engagement system
|
|
EthicalEngagement.Instance.OnDDATierChange(CurrentTier);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculates DDA tier from player performance
|
|
/// KDR (Kill/Death Ratio) and session duration factors
|
|
/// </summary>
|
|
private DifficultyTier CalculateDifficultyTier(float playerKDR, int sessionDuration)
|
|
{
|
|
// DDA 3.0 algorithm:
|
|
// - KDR < 0.5: Difficult (stressed player)
|
|
// - KDR 0.5-1.5: Normal (balanced)
|
|
// - KDR > 1.5: Relaxed (dominant player)
|
|
|
|
if (playerKDR < 0.5f || sessionDuration > 45)
|
|
{
|
|
return DifficultyTier.Difficult;
|
|
}
|
|
else if (playerKDR < 1.5f)
|
|
{
|
|
return DifficultyTier.Normal;
|
|
}
|
|
else
|
|
{
|
|
return DifficultyTier.Relaxed;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adjusts enemy AI behavior based on DDA tier
|
|
/// Emergent gameplay: AI adapts to player skill
|
|
/// </summary>
|
|
private void AdjustEnemyAI(DifficultyTier tier)
|
|
{
|
|
var aiJob = new EnemyAIAdjustmentJob
|
|
{
|
|
enemyEntities = enemyEntities,
|
|
tier = tier,
|
|
aggressionFactor = CalculateAggressionFactor(tier),
|
|
accuracyFactor = CalculateAccuracyFactor(tier)
|
|
};
|
|
|
|
// Schedule AI adjustment on DOTS job system
|
|
var handle = aiJob.Schedule();
|
|
handle.Complete();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculates UI opacity factor for DDA tier
|
|
/// Reduces visual complexity for stressed players
|
|
/// </summary>
|
|
private float CalculateUIOpacity(DifficultyTier tier)
|
|
{
|
|
switch (tier)
|
|
{
|
|
case DifficultyTier.Difficult:
|
|
// Stressed players: reduce opacity (0.7)
|
|
return 0.7f;
|
|
case DifficultyTier.Normal:
|
|
// Standard opacity (1.0)
|
|
return 1.0f;
|
|
case DifficultyTier.Relaxed:
|
|
// Engaged players: slight enhancement (1.2)
|
|
return 1.2f;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculates enemy aggression factor
|
|
/// Higher tier = more aggressive AI
|
|
/// </summary>
|
|
private float CalculateAggressionFactor(DifficultyTier tier)
|
|
{
|
|
switch (tier)
|
|
{
|
|
case DifficultyTier.Difficult:
|
|
return 0.5f; // Reduced aggression
|
|
case DifficultyTier.Normal:
|
|
return 1.0f; // Standard aggression
|
|
case DifficultyTier.Relaxed:
|
|
return 1.5f; // Enhanced aggression
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculates enemy accuracy factor
|
|
/// Scales with player performance
|
|
/// </summary>
|
|
private float CalculateAccuracyFactor(DifficultyTier tier)
|
|
{
|
|
switch (tier)
|
|
{
|
|
case DifficultyTier.Difficult:
|
|
return 0.6f; // Reduced accuracy
|
|
case DifficultyTier.Normal:
|
|
return 1.0f; // Standard accuracy
|
|
case DifficultyTier.Relaxed:
|
|
return 1.4f; // Enhanced accuracy
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// DOTS Job for enemy AI adjustment
|
|
/// Burst-compiled for performance
|
|
/// </summary>
|
|
[BurstCompile]
|
|
public struct EnemyAIAdjustmentJob : IJob
|
|
{
|
|
public NativeArray<Entity> enemyEntities;
|
|
public DifficultyTier tier;
|
|
public float aggressionFactor;
|
|
public float accuracyFactor;
|
|
|
|
[BurstCompile]
|
|
public void Execute()
|
|
{
|
|
for (int i = 0; i < enemyEntities.Length; i++)
|
|
{
|
|
var enemy = enemyEntities[i];
|
|
var aiComponent = enemy.Get<EnemyAIComponent>();
|
|
|
|
// Adjust AI heuristics
|
|
aiComponent.aggression = aggressionFactor;
|
|
aiComponent.accuracy = accuracyFactor;
|
|
aiComponent.reactionTime = CalculateReactionTime(tier);
|
|
|
|
enemy.Set(aiComponent);
|
|
}
|
|
}
|
|
|
|
private float CalculateReactionTime(DifficultyTier tier)
|
|
{
|
|
switch (tier)
|
|
{
|
|
case DifficultyTier.Difficult:
|
|
return 1.5f; // Slower reaction
|
|
case DifficultyTier.Normal:
|
|
return 1.0f; // Standard reaction
|
|
case DifficultyTier.Relaxed:
|
|
return 0.7f; // Faster reaction
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Player performance metrics for DDA calculation
|
|
/// Tracks KDR, session duration, stress indicators
|
|
/// </summary>
|
|
public struct PlayerPerformanceMetrics
|
|
{
|
|
public float KDR; // Kill/Death Ratio
|
|
public int sessionDuration; // Minutes
|
|
public float stressLevel; // 0.0-1.0
|
|
public float accuracy; // Hit accuracy
|
|
public int wins;
|
|
public int losses;
|
|
|
|
public void Update(float kdr, int duration, float stress)
|
|
{
|
|
KDR = kdr;
|
|
sessionDuration = duration;
|
|
stressLevel = stress;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enemy AI Component for ECS
|
|
/// Stores heuristic values for DDA adjustment
|
|
/// </summary>
|
|
public struct EnemyAIComponent : IComponent
|
|
{
|
|
public float aggression;
|
|
public float accuracy;
|
|
public float reactionTime;
|
|
public float detectionRange;
|
|
public int behaviorState;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// UI Adaptation System for DDA 3.0
|
|
/// Visual complexity adjusts based on tier
|
|
/// </summary>
|
|
public class UIAdaptationSystem : MonoBehaviour
|
|
{
|
|
private DDAManager ddaManager;
|
|
|
|
public void Initialize()
|
|
{
|
|
ddaManager = DDAManager.Instance;
|
|
}
|
|
|
|
public void AdaptUI()
|
|
{
|
|
var tier = ddaManager.CurrentTier;
|
|
var opacity = ddaManager.UIOpacityFactor;
|
|
|
|
// Reduce visual complexity for stressed players
|
|
if (tier == DDAManager.DifficultyTier.Difficult)
|
|
{
|
|
SimplifyUIComplexity();
|
|
ReduceParticleEffects();
|
|
LowerHapticIntensity();
|
|
}
|
|
else if (tier == DDAManager.DifficultyTier.Relaxed)
|
|
{
|
|
EnhanceVisualFeedback();
|
|
IncreaseParticleEffects();
|
|
RaiseHapticIntensity();
|
|
}
|
|
}
|
|
|
|
private void SimplifyUIComplexity()
|
|
{
|
|
// Hide decorative elements
|
|
UISystem.Instance.HideDecorativeElements();
|
|
|
|
// Reduce animation complexity
|
|
UISystem.Instance.SimplifyAnimations();
|
|
}
|
|
|
|
private void ReduceParticleEffects()
|
|
{
|
|
// Lower particle density
|
|
ParticleSystem.Instance.SetDensity(0.5f);
|
|
}
|
|
|
|
private void LowerHapticIntensity()
|
|
{
|
|
// Reduce haptic feedback intensity
|
|
HapticSystem.Instance.SetIntensity(HapticIntensity.Light);
|
|
}
|
|
|
|
private void EnhanceVisualFeedback()
|
|
{
|
|
// Show additional visual cues
|
|
UISystem.Instance.ShowEnhancedCues();
|
|
}
|
|
|
|
private void IncreaseParticleEffects()
|
|
{
|
|
// Increase particle density
|
|
ParticleSystem.Instance.SetDensity(1.5f);
|
|
}
|
|
|
|
private void RaiseHapticIntensity()
|
|
{
|
|
// Increase haptic feedback intensity
|
|
HapticSystem.Instance.SetIntensity(HapticIntensity.Strong);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Emergent Gameplay Controller
|
|
/// DDA-driven emergent behaviors
|
|
/// </summary>
|
|
public class EmergentGameplayController : MonoBehaviour
|
|
{
|
|
private DDAManager ddaManager;
|
|
|
|
public void OnDDATierChange(DDAManager.DifficultyTier tier)
|
|
{
|
|
// Trigger emergent gameplay events
|
|
switch (tier)
|
|
{
|
|
case DDAManager.DifficultyTier.Difficult:
|
|
// Player struggling: spawn help event
|
|
SpawnHelpEvent();
|
|
break;
|
|
case DDAManager.DifficultyTier.Relaxed:
|
|
// Player dominant: spawn challenge event
|
|
SpawnChallengeEvent();
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void SpawnHelpEvent()
|
|
{
|
|
// Emergent gameplay: helpful NPC appears
|
|
EventSystem.Instance.Trigger("HelpNPCSpawn");
|
|
}
|
|
|
|
private void SpawnChallengeEvent()
|
|
{
|
|
// Emergent gameplay: elite enemy spawns
|
|
EventSystem.Instance.Trigger("EliteEnemySpawn");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Haptic intensity levels for DDA adaptation
|
|
/// </summary>
|
|
public enum HapticIntensity
|
|
{
|
|
Light, // 20% - Difficult tier
|
|
Moderate, // 50% - Normal tier
|
|
Strong // 80% - Relaxed tier
|
|
}
|
|
} |