added pooling for the gui portraits

This commit is contained in:
Sebastian Bularca
2026-04-06 17:41:35 +02:00
parent f42885830a
commit fa7659d905

View File

@@ -1,4 +1,3 @@
using Jovian.Logger;
using System.Collections.Generic; using System.Collections.Generic;
using Jovian.PopupSystem; using Jovian.PopupSystem;
using Nox.UI; using Nox.UI;
@@ -7,14 +6,16 @@ using Object = UnityEngine.Object;
namespace Nox.Game.UI { namespace Nox.Game.UI {
public class PartyGuiView { public class PartyGuiView {
private const int PoolSize = 4;
private readonly Transform portraitsContainer; private readonly Transform portraitsContainer;
private readonly PartyMemberSlot slotPrefab; private readonly PartyMemberSlot slotPrefab;
private readonly PortraitsHolder portraitsHolder; private readonly PortraitsHolder portraitsHolder;
private readonly IPopupSystem popupSystem; private readonly IPopupSystem popupSystem;
private readonly List<PartyMemberSlot> activeSlots = new(); private readonly PartyMemberSlot[] slotPool = new PartyMemberSlot[PoolSize];
private PartyDefinition trackedParty; private PartyDefinition trackedParty;
private int trackedMemberCount; private int activeCount;
public PartyGuiView(Transform portraitsContainer, PartyMemberSlot slotPrefab, PortraitsHolder portraitsHolder, IPopupSystem popupSystem = null) { public PartyGuiView(Transform portraitsContainer, PartyMemberSlot slotPrefab, PortraitsHolder portraitsHolder, IPopupSystem popupSystem = null) {
this.portraitsContainer = portraitsContainer; this.portraitsContainer = portraitsContainer;
@@ -25,8 +26,17 @@ namespace Nox.Game.UI {
public void Initialize(PartyDefinition party) { public void Initialize(PartyDefinition party) {
trackedParty = party; trackedParty = party;
trackedMemberCount = 0; activeCount = 0;
RebuildSlots();
// 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() { public void Tick() {
@@ -35,58 +45,59 @@ namespace Nox.Game.UI {
} }
// Rebuild if member count changed // Rebuild if member count changed
if(trackedParty.members.Count != trackedMemberCount) { if(trackedParty.members.Count != activeCount) {
RebuildSlots(); PopulateSlots();
} }
// Update dynamic values (health, mana) // Update dynamic values
for(int i = 0; i < activeSlots.Count && i < trackedParty.members.Count; i++) { var memberCount = Mathf.Min(activeCount, trackedParty.members.Count);
var member = trackedParty.members[i]; for(int i = 0; i < memberCount; i++) {
var slot = activeSlots[i]; UpdateSlotStats(slotPool[i], trackedParty.members[i]);
UpdateSlotStats(slot, member);
} }
} }
private void RebuildSlots() { private void PopulateSlots() {
// Clear existing var memberCount = trackedParty?.members != null
foreach(var slot in activeSlots) { ? Mathf.Min(trackedParty.members.Count, PoolSize)
Object.Destroy(slot.gameObject); : 0;
}
activeSlots.Clear();
if(trackedParty?.members == null) { // Activate slots for current members, deactivate the rest
return; 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) { // Initialize popup triggers
var slot = Object.Instantiate(slotPrefab, portraitsContainer); if(popupSystem != null) {
slot.gameObject.SetActive(true); popupSystem.InitializeTriggersInChildren(portraitsContainer, (trigger, view) => {
var slot = trigger.GetComponentInParent<PartyMemberSlot>();
// Portrait if(slot == null) {
if(portraitsHolder != null && portraitsHolder.portraits.Length > 0) { return;
var idx = Mathf.Clamp(member.PortraitIndex, 0, portraitsHolder.portraits.Length - 1); }
slot.portrait.sprite = portraitsHolder.portraits[idx]; var slotIndex = System.Array.IndexOf(slotPool, slot);
} if(slotIndex < 0 || slotIndex >= activeCount) {
return;
UpdateSlotStats(slot, member); }
activeSlots.Add(slot); 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<PartyMemberSlot>();
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) { private void BuildCharacterPopup(PopupContentBuilder builder, CharacterDefinition member) {
@@ -99,14 +110,18 @@ namespace Nox.Game.UI {
// Stats // Stats
if(member.Stats?.stats != null) { if(member.Stats?.stats != null) {
foreach(var stat in member.Stats.stats) { var level = member.Stats.GetValue(StatType.Level);
if(stat.stat == StatType.None) { var xp = member.Stats.GetValue(StatType.Experience);
continue; var health = member.Stats.GetValue(StatType.Health);
} var mana = member.Stats.GetValue(StatType.Mana);
builder.AddStat(stat.stat.ToString(), stat.value); builder
} .AddStat("Level", level)
.AddStat("XP", xp)
.AddSeparator()
.AddStat("Health", health)
.AddStat("Mana", mana)
.AddSeparator();
} }
builder.AddSeparator();
// Attributes // Attributes
if(member.Attributes?.attributes != null) { if(member.Attributes?.attributes != null) {
@@ -152,12 +167,13 @@ namespace Nox.Game.UI {
} }
public void Dispose() { public void Dispose() {
foreach(var slot in activeSlots) { for(int i = 0; i < PoolSize; i++) {
if(slot != null) { if(slotPool[i] != null) {
Object.Destroy(slot.gameObject); Object.Destroy(slotPool[i].gameObject);
slotPool[i] = null;
} }
} }
activeSlots.Clear(); activeCount = 0;
} }
} }
} }