From fa7659d9055725ec4c5531d1831f8e4d2cc9dc88 Mon Sep 17 00:00:00 2001 From: Sebastian Bularca Date: Mon, 6 Apr 2026 17:41:35 +0200 Subject: [PATCH] added pooling for the gui portraits --- Assets/Code/GameState/UI/PartyGuiView.cs | 132 +++++++++++++---------- 1 file changed, 74 insertions(+), 58 deletions(-) diff --git a/Assets/Code/GameState/UI/PartyGuiView.cs b/Assets/Code/GameState/UI/PartyGuiView.cs index c282b5c..05bcaa2 100644 --- a/Assets/Code/GameState/UI/PartyGuiView.cs +++ b/Assets/Code/GameState/UI/PartyGuiView.cs @@ -1,4 +1,3 @@ -using Jovian.Logger; using System.Collections.Generic; using Jovian.PopupSystem; using Nox.UI; @@ -7,14 +6,16 @@ using Object = UnityEngine.Object; namespace Nox.Game.UI { public class PartyGuiView { + private const int PoolSize = 4; + private readonly Transform portraitsContainer; private readonly PartyMemberSlot slotPrefab; private readonly PortraitsHolder portraitsHolder; private readonly IPopupSystem popupSystem; - private readonly List activeSlots = new(); + private readonly PartyMemberSlot[] slotPool = new PartyMemberSlot[PoolSize]; private PartyDefinition trackedParty; - private int trackedMemberCount; + private int activeCount; public PartyGuiView(Transform portraitsContainer, PartyMemberSlot slotPrefab, PortraitsHolder portraitsHolder, IPopupSystem popupSystem = null) { this.portraitsContainer = portraitsContainer; @@ -25,8 +26,17 @@ namespace Nox.Game.UI { public void Initialize(PartyDefinition party) { trackedParty = party; - trackedMemberCount = 0; - RebuildSlots(); + activeCount = 0; + + // Pre-create all slots (deactivated) + for(int i = 0; i < PoolSize; i++) { + if(slotPool[i] == null) { + slotPool[i] = Object.Instantiate(slotPrefab, portraitsContainer); + } + slotPool[i].gameObject.SetActive(false); + } + + PopulateSlots(); } public void Tick() { @@ -35,58 +45,59 @@ namespace Nox.Game.UI { } // Rebuild if member count changed - if(trackedParty.members.Count != trackedMemberCount) { - RebuildSlots(); + if(trackedParty.members.Count != activeCount) { + PopulateSlots(); } - // Update dynamic values (health, mana) - for(int i = 0; i < activeSlots.Count && i < trackedParty.members.Count; i++) { - var member = trackedParty.members[i]; - var slot = activeSlots[i]; - UpdateSlotStats(slot, member); + // Update dynamic values + var memberCount = Mathf.Min(activeCount, trackedParty.members.Count); + for(int i = 0; i < memberCount; i++) { + UpdateSlotStats(slotPool[i], trackedParty.members[i]); } } - private void RebuildSlots() { - // Clear existing - foreach(var slot in activeSlots) { - Object.Destroy(slot.gameObject); - } - activeSlots.Clear(); + private void PopulateSlots() { + var memberCount = trackedParty?.members != null + ? Mathf.Min(trackedParty.members.Count, PoolSize) + : 0; - if(trackedParty?.members == null) { - return; + // Activate slots for current members, deactivate the rest + for(int i = 0; i < PoolSize; i++) { + var slot = slotPool[i]; + if(i < memberCount) { + var member = trackedParty.members[i]; + slot.gameObject.SetActive(true); + + // Portrait + if(portraitsHolder != null && portraitsHolder.portraits.Length > 0) { + var idx = Mathf.Clamp(member.PortraitIndex, 0, portraitsHolder.portraits.Length - 1); + slot.portrait.sprite = portraitsHolder.portraits[idx]; + } + + UpdateSlotStats(slot, member); + } + else { + slot.gameObject.SetActive(false); + } } - trackedMemberCount = trackedParty.members.Count; + activeCount = memberCount; - foreach(var member in trackedParty.members) { - var slot = Object.Instantiate(slotPrefab, portraitsContainer); - slot.gameObject.SetActive(true); - - // Portrait - if(portraitsHolder != null && portraitsHolder.portraits.Length > 0) { - var idx = Mathf.Clamp(member.PortraitIndex, 0, portraitsHolder.portraits.Length - 1); - slot.portrait.sprite = portraitsHolder.portraits[idx]; - } - - UpdateSlotStats(slot, member); - activeSlots.Add(slot); + // Initialize popup triggers + if(popupSystem != null) { + popupSystem.InitializeTriggersInChildren(portraitsContainer, (trigger, view) => { + var slot = trigger.GetComponentInParent(); + if(slot == null) { + return; + } + var slotIndex = System.Array.IndexOf(slotPool, slot); + if(slotIndex < 0 || slotIndex >= activeCount) { + return; + } + var member = trackedParty.members[slotIndex]; + view.SetContent(builder => BuildCharacterPopup(builder, member)); + }); } - - // Initialize all popup triggers under the container - popupSystem?.InitializeTriggersInChildren(portraitsContainer, (trigger, view) => { - var slot = trigger.GetComponentInParent(); - if(slot == null) { - return; - } - var slotIndex = activeSlots.IndexOf(slot); - if(slotIndex < 0 || slotIndex >= trackedParty.members.Count) { - return; - } - var member = trackedParty.members[slotIndex]; - view.SetContent(builder => BuildCharacterPopup(builder, member)); - }); } private void BuildCharacterPopup(PopupContentBuilder builder, CharacterDefinition member) { @@ -99,14 +110,18 @@ namespace Nox.Game.UI { // Stats if(member.Stats?.stats != null) { - foreach(var stat in member.Stats.stats) { - if(stat.stat == StatType.None) { - continue; - } - builder.AddStat(stat.stat.ToString(), stat.value); - } + var level = member.Stats.GetValue(StatType.Level); + var xp = member.Stats.GetValue(StatType.Experience); + var health = member.Stats.GetValue(StatType.Health); + var mana = member.Stats.GetValue(StatType.Mana); + builder + .AddStat("Level", level) + .AddStat("XP", xp) + .AddSeparator() + .AddStat("Health", health) + .AddStat("Mana", mana) + .AddSeparator(); } - builder.AddSeparator(); // Attributes if(member.Attributes?.attributes != null) { @@ -152,12 +167,13 @@ namespace Nox.Game.UI { } public void Dispose() { - foreach(var slot in activeSlots) { - if(slot != null) { - Object.Destroy(slot.gameObject); + for(int i = 0; i < PoolSize; i++) { + if(slotPool[i] != null) { + Object.Destroy(slotPool[i].gameObject); + slotPool[i] = null; } } - activeSlots.Clear(); + activeCount = 0; } } }