Advertisement
Guest User

Untitled

a guest
Apr 30th, 2025
57
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 13.17 KB | None | 0 0
  1. // --- Component Definitions ---
  2.  
  3. // Represents an entity's ability to equip items.
  4. public struct EquipmentComponent
  5. {
  6.     // Stores equipped items (Entity ID) per slot.
  7.     // Assuming EquipmentSlot is an enum or similar identifier.
  8.     public Dictionary<EquipmentSlot, int> EquippedItems;
  9.  
  10.     // Flag to indicate equipment changed and stats might need recalculation.
  11.     public bool NeedsRecalculation;
  12. }
  13.  
  14. // Indicates an item can be equipped into a specific slot.
  15. public struct EquippableComponent
  16. {
  17.     public EquipmentSlot Slot;
  18. }
  19.  
  20. // Data specific to entities that can bark.
  21. public struct BarkVolumeComponent
  22. {
  23.     public int BaseVolume;     // The inherent bark volume without items.
  24.     public int CurrentVolume;  // The final calculated volume including bonuses.
  25. }
  26.  
  27. // Data for items that modify bark volume.
  28. public struct BarkBonusComponent
  29. {
  30.     public int Bonus;
  31. }
  32.  
  33. // Example: Tag component to identify an entity as a 'Dog'
  34. // (though often the presence of BarkVolumeComponent might be enough).
  35. public struct DogTag { }
  36.  
  37. // Example: Tag component to identify an entity as an 'Item'.
  38. public struct ItemTag { }
  39.  
  40. // --- System Definitions ---
  41.  
  42. // Handles the logic of equipping items.
  43. public class EquipSystem
  44. {
  45.     // Hypothetical EntityManager to access component data.
  46.     private readonly EntityManager entityManager;
  47.  
  48.     public EquipSystem(EntityManager manager)
  49.     {
  50.         this.entityManager = manager;
  51.     }
  52.  
  53.     // Attempts to equip an itemEntity onto a unitEntity.
  54.     public void EquipItem(int unitEntityId, int itemEntityId)
  55.     {
  56.         // Check if both entities exist and have the necessary components.
  57.         if (!entityManager.HasComponent<EquipmentComponent>(unitEntityId) ||
  58.             !entityManager.HasComponent<EquippableComponent>(itemEntityId))
  59.         {
  60.             Console.WriteLine($"ECS Equip: Entity missing required components for equip.");
  61.             return;
  62.         }
  63.  
  64.         // Get references to the components (often involves pointers or specific ECS API calls).
  65.         ref var equipment = ref entityManager.GetComponent<EquipmentComponent>(unitEntityId);
  66.         var equippable = entityManager.GetComponent<EquippableComponent>(itemEntityId); // Read-only is fine.
  67.  
  68.         EquipmentSlot slot = equippable.Slot;
  69.  
  70.         // --- Unequip Existing Item (If Any) ---
  71.         // In a full system, you'd likely call an UnequipSystem or use an event.
  72.         if (equipment.EquippedItems.ContainsKey(slot))
  73.         {
  74.             int currentlyEquippedItemId = equipment.EquippedItems[slot];
  75.             Console.WriteLine($"ECS Equip: Unequipping item {currentlyEquippedItemId} from slot {slot} first.");
  76.             // UnequipSystem.UnequipItem(unitEntityId, currentlyEquippedItemId); // Ideal approach
  77.             // Simplified for this example: just remove it here.
  78.             equipment.EquippedItems.Remove(slot);
  79.             // Mark for recalculation because an item was removed.
  80.             equipment.NeedsRecalculation = true;
  81.         }
  82.  
  83.         // --- Equip New Item ---
  84.         equipment.EquippedItems[slot] = itemEntityId;
  85.         Console.WriteLine($"ECS Equip: Equipped item {itemEntityId} to unit {unitEntityId} in slot {slot}.");
  86.  
  87.         // Mark the unit's equipment as changed, signalling stat recalculation might be needed.
  88.         equipment.NeedsRecalculation = true;
  89.     }
  90. }
  91.  
  92. // Handles recalculating BarkVolume based on equipped items.
  93. public class BarkVolumeUpdateSystem
  94. {
  95.     private readonly EntityManager entityManager;
  96.  
  97.     public BarkVolumeUpdateSystem(EntityManager manager)
  98.     {
  99.         this.entityManager = manager;
  100.     }
  101.  
  102.     public void Update()
  103.     {
  104.         // Query for all entities that have BarkVolume AND Equipment,
  105.         // AND whose equipment needs recalculation.
  106.         var query = entityManager.QueryEntitiesWithComponents<BarkVolumeComponent, EquipmentComponent>();
  107.  
  108.         foreach (int entityId in query)
  109.         {
  110.             // Get components for the entity that needs updating.
  111.             ref var equipment = ref entityManager.GetComponent<EquipmentComponent>(entityId);
  112.  
  113.             // Only update if flagged. Reset the flag after processing.
  114.             if (!equipment.NeedsRecalculation) continue;
  115.  
  116.             ref var barkVolume = ref entityManager.GetComponent<BarkVolumeComponent>(entityId);
  117.  
  118.             Console.WriteLine($"ECS Update: Recalculating BarkVolume for entity {entityId}.");
  119.  
  120.             int totalBonus = 0;
  121.  
  122.             // Iterate through equipped items.
  123.             foreach (var kvp in equipment.EquippedItems)
  124.             {
  125.                 int itemId = kvp.Value;
  126.                 // Check if the equipped item provides a bark bonus.
  127.                 if (entityManager.HasComponent<BarkBonusComponent>(itemId))
  128.                 {
  129.                     var itemBonus = entityManager.GetComponent<BarkBonusComponent>(itemId); // Read-only.
  130.                     totalBonus += itemBonus.Bonus;
  131.                     Console.WriteLine($" - Item {itemId} provides +{itemBonus.Bonus} bark bonus.");
  132.                 }
  133.             }
  134.  
  135.             // Calculate the final volume.
  136.             barkVolume.CurrentVolume = barkVolume.BaseVolume + totalBonus;
  137.             Console.WriteLine($" - BaseVolume: {barkVolume.BaseVolume}, TotalBonus: {totalBonus}, New CurrentVolume: {barkVolume.CurrentVolume}");
  138.  
  139.             // Reset the flag now that recalculation is done.
  140.             equipment.NeedsRecalculation = false;
  141.         }
  142.     }
  143. }
  144.  
  145. // --- Helper/Setup Code (Simplified) ---
  146. public enum EquipmentSlot { Head, Paws, Collar }
  147.  
  148. // VERY basic stand-in for a real ECS EntityManager/World.
  149. public class EntityManager
  150. {
  151.     private Dictionary<int, Dictionary<Type, object>> entities = new Dictionary<int, Dictionary<Type, object>>();
  152.     private int nextEntityId = 1;
  153.  
  154.     public int CreateEntity() {
  155.         int id = nextEntityId++;
  156.         entities[id] = new Dictionary<Type, object>();
  157.         return id;
  158.     }
  159.  
  160.     public void AddComponent<T>(int entityId, T component) where T : struct
  161.     {
  162.         if (entities.ContainsKey(entityId)) {
  163.             entities[entityId][typeof(T)] = component;
  164.         }
  165.     }
  166.  
  167.     public bool HasComponent<T>(int entityId) where T : struct
  168.     {
  169.         return entities.ContainsKey(entityId) && entities[entityId].ContainsKey(typeof(T));
  170.     }
  171.  
  172.     // NOTE: Real ECS uses optimized ways to get component references (ref returns).
  173.     // This boxing/unboxing version is for demonstration only and is inefficient.
  174.     public ref T GetComponent<T>(int entityId) where T : struct
  175.     {
  176.         if (!HasComponent<T>(entityId)) {
  177.              throw new KeyNotFoundException($"Entity {entityId} does not have component {typeof(T).Name}");
  178.         }
  179.         // This is NOT how you'd return a 'ref struct' in a real ECS.
  180.         // It requires more complex unsafe code or specific library features.
  181.         // We'll simulate the modification effect by re-assigning after potential changes.
  182.         // This limitation makes the 'ref' keyword in the Systems illustrative rather than functional here.
  183.         object compObj = entities[entityId][typeof(T)];
  184.         T comp = (T)compObj;
  185.         // **PROBLEM**: This returns a *copy*. We can't directly return a ref to the dictionary value easily here.
  186.         // For the example, we'll rely on systems *re-adding* the modified component if needed (less ideal).
  187.         // A better stub would manage component pools directly.
  188.  
  189.         // Workaround for stub: We can't return ref T easily. Systems will need to AddComponent again if they modify.
  190.         // Let's make GetComponent just return a copy for this stub.
  191.          return ref GetActualComponentRef<T>(entityId); // Cheating for demo
  192.     }
  193.  
  194.     // Helper to bypass limitation for demo (Still not real ECS performance/safety)
  195.     private ref T GetActualComponentRef<T>(int entityId) where T : struct {
  196.        // This requires storing components differently, maybe arrays per type.
  197.        // Too complex for this example stub. Systems will just get copies.
  198.        // **Let's adjust the systems to work with copies for this simple demo.**
  199.        throw new NotSupportedException("Returning 'ref T' is complex without a full ECS framework. Adjusting example systems.");
  200.     }
  201.  
  202.  
  203.     // Adjusted GetComponent (returns copy)
  204.      public T GetCopyGetComponent<T>(int entityId) where T : struct
  205.     {
  206.          if (!HasComponent<T>(entityId)) {
  207.              throw new KeyNotFoundException($"Entity {entityId} does not have component {typeof(T).Name}");
  208.         }
  209.          return (T)entities[entityId][typeof(T)];
  210.     }
  211.  
  212.  
  213.     public List<int> QueryEntitiesWithComponents<T1, T2>() where T1 : struct where T2 : struct
  214.     {
  215.         List<int> result = new List<int>();
  216.         foreach (var kvp in entities) {
  217.             if (kvp.Value.ContainsKey(typeof(T1)) && kvp.Value.ContainsKey(typeof(T2))) {
  218.                 result.Add(kvp.Key);
  219.             }
  220.         }
  221.         return result;
  222.     }
  223.      public List<int> QueryEntitiesWithComponents<T1, T2, T3>()
  224.         where T1 : struct where T2 : struct where T3 : struct
  225.     {
  226.         List<int> result = new List<int>();
  227.         foreach (var kvp in entities) {
  228.             if (kvp.Value.ContainsKey(typeof(T1)) &&
  229.                 kvp.Value.ContainsKey(typeof(T2)) &&
  230.                 kvp.Value.ContainsKey(typeof(T3))) {
  231.                 result.Add(kvp.Key);
  232.             }
  233.         }
  234.         return result;
  235.     }
  236. }
  237.  
  238.  
  239. // --- Main Execution Logic ---
  240. public class EcsExampleRunner
  241. {
  242.     public static void Run()
  243.     {
  244.         // --- Setup ---
  245.         var entityManager = new EntityManager(); // Use adjusted EntityManager
  246.         var equipSystem = new EquipSystem(entityManager); // Pass adjusted manager
  247.         var barkSystem = new BarkVolumeUpdateSystem(entityManager); // Pass adjusted manager
  248.  
  249.         // Adjust Systems to use GetCopyGetComponent and AddComponent for updates
  250.         // (This modification would be needed inside the system classes shown above)
  251.         // For brevity, imagine the System classes now call:
  252.         // var componentCopy = entityManager.GetCopyGetComponent<T>(id);
  253.         // componentCopy.Value = newValue;
  254.         // entityManager.AddComponent(id, componentCopy); // Re-add modified copy
  255.  
  256.         // --- Create Entities ---
  257.         int dogEntity = entityManager.CreateEntity();
  258.         entityManager.AddComponent(dogEntity, new DogTag()); // Optional tag
  259.         entityManager.AddComponent(dogEntity, new EquipmentComponent {
  260.             EquippedItems = new Dictionary<EquipmentSlot, int>(),
  261.             NeedsRecalculation = true // Start dirty to calculate initial volume
  262.         });
  263.         entityManager.AddComponent(dogEntity, new BarkVolumeComponent { BaseVolume = 10, CurrentVolume = 10 });
  264.  
  265.         int loudCollarItem = entityManager.CreateEntity();
  266.         entityManager.AddComponent(loudCollarItem, new ItemTag()); // Optional tag
  267.         entityManager.AddComponent(loudCollarItem, new EquippableComponent { Slot = EquipmentSlot.Collar });
  268.         entityManager.AddComponent(loudCollarItem, new BarkBonusComponent { Bonus = 5 });
  269.  
  270.         int squeakyToyItem = entityManager.CreateEntity();
  271.         entityManager.AddComponent(squeakyToyItem, new ItemTag());
  272.         entityManager.AddComponent(squeakyToyItem, new EquippableComponent { Slot = EquipmentSlot.Paws });
  273.         // No BarkBonusComponent on this item
  274.  
  275.         Console.WriteLine("--- Initial State ---");
  276.         // Initial bark volume calculation
  277.         barkSystem.Update(); // Needs adjustment to use GetCopy/AddComponent
  278.         // Show initial volume (requires adjusted GetCopyGetComponent)
  279.         // var initialBark = entityManager.GetCopyGetComponent<BarkVolumeComponent>(dogEntity);
  280.         // Console.WriteLine($"Dog {dogEntity} initial BarkVolume: {initialBark.CurrentVolume}");
  281.  
  282.  
  283.         Console.WriteLine("\n--- Equipping Loud Collar ---");
  284.         equipSystem.EquipItem(dogEntity, loudCollarItem); // Needs adjustment to use GetCopy/AddComponent
  285.  
  286.         // Recalculate stats after equipping
  287.         barkSystem.Update(); // Needs adjustment to use GetCopy/AddComponent
  288.         // Show updated volume
  289.         // var updatedBark = entityManager.GetCopyGetComponent<BarkVolumeComponent>(dogEntity);
  290.         // Console.WriteLine($"Dog {dogEntity} BarkVolume after collar: {updatedBark.CurrentVolume}");
  291.  
  292.  
  293.         Console.WriteLine("\n--- Equipping Squeaky Toy ---");
  294.         equipSystem.EquipItem(dogEntity, squeakyToyItem); // Needs adjustment to use GetCopy/AddComponent
  295.  
  296.         // Recalculate (BarkVolume shouldn't change as toy has no bonus)
  297.         barkSystem.Update(); // Needs adjustment to use GetCopy/AddComponent
  298.         // Show volume again
  299.         // var finalBark = entityManager.GetCopyGetComponent<BarkVolumeComponent>(dogEntity);
  300.         // Console.WriteLine($"Dog {dogEntity} BarkVolume after toy: {finalBark.CurrentVolume}");
  301.  
  302.         // --- Add Unequip Example ---
  303.         // Console.WriteLine("\n--- Unequipping Loud Collar ---");
  304.         // UnequipSystem would be needed here...
  305.         // E.g., UnequipSystem.Unequip(dogEntity, loudCollarItem);
  306.         // barkSystem.Update();
  307.         // ... show volume ...
  308.     }
  309. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement