Dynamically ordering a vertical layout group
I'm attempting to display an ordered list to the user of personnel inside a sector (labeled trisect). This is a vertical layout group, and for the rows I'm using gameobject prefabs that when disabled are added to a pool. That pool holds on to disabled game objects until I need another one of that type, as to keep the scene uncluttered and save some memory.
The pooling is causing the sort to not work. If I disable the pool, it will sort people in barracks by their STR as intended. Without, it appears to have no sorting effect whatsoever.
I am attempting to sort via setsiblingindex(int i) or setLastSibling(). This works initially, but when the pooled items are reused, the order is off. I've checked in debug to make sure that the soldier list sorts properly and even checked what values were sent in setsiblingindex(i). What it revealed is that sibling index 0 has the most strength, but when I looked at the list, it showed that item nearly halfway down the list.
Pool code:
public GameObject AddPersonnelRow(Soldier sol)
{
GameObject personnelRow;
if (_inactivePersonnelRows.Count < 1)
{
personnelRow = GameObject.Instantiate(personnelRowPrefab);
personnelRow.transform.SetParent(personnelGrid);
}
else
{
personnelRow = _inactivePersonnelRows[0];
personnelRow.SetActive(true);
personnelRow.GetComponentInChildren<Toggle>().isOn = false;
_inactivePersonnelRows.RemoveAt(0);
}
return personnelRow;
}
public void RemovePersonnelRow(GameObject pRow)
{
_inactivePersonnelRows.Add(pRow);
pRow.SetActive(false);
pRow.transform.SetAsLastSibling();
}
Sort code:
private void Sort()
{
List<TrisectRow> soldiers;
switch (_trisect.trisect.station.Subtype)
{
case Subtypes.Barracks:
soldiers = _trisectPersonnel
.OrderByDescending(x => x.soldier.strength).ToList();
break;
case Subtypes.Research:
soldiers = _trisectPersonnel
.OrderByDescending(x => x.soldier.mind).ToList();
break;
default:
soldiers = _trisectPersonnel
.OrderByDescending(x => x.soldier.level)
.ThenByDescending(x => x.soldier.hp)
.ThenByDescending(x => x.soldier.strength).ToList();
break;
}
for (int i = 0; i < soldiers.Count(); i++)
{
soldiers[i].mono.transform.SetAsLastSibling();
}
}
TrisectRow class:
public class TrisectRow
{
public GameObject mono { get; set; }
public Soldier soldier { get; set; }
public TrisectRow(GameObject mono, Soldier soldier)
{
this.mono = mono;
this.soldier = soldier;
}
}
@TBruce Added it. Soldier just has base stats, the mono object is just the unity row to display.
I get your sort but I do not understand what you are doing here
for (int i = 0; i < soldiers.Count(); i++)
{
soldiers[i].mono.transform.SetAsLastSibling();
}
Also, how/where/when is AddPersonnelRow
called and you have
if (_inactivePersonnelRows.Count < 1)
which leads one to believe that _inactivePersonnelRows.Count
will never be greater than zero gain if ever set to true.
Forgive me for the questions but I am trying to wrap my head around what you are doing with the amount of code provided.
Edit: I just refreshed an I see your added images, could you explain what is wrong/right and what it should be (and which sort method you used)?
Answer by TBruce · Jan 03, 2017 at 05:41 AM
Not sure what you are going for here but I am going to assume that you are displaying the separate rows on the game screen. If this is the case then you need to set the Y
position for each of the rows. Something like the following [will differ slightly depending on your implementation] (this should be done after your switch/sort statement)
for (int i = 0; i < soldiers.Count(); i++)
{
Vector3 position = soldiers[i].mono.transform.position;
position.y = soldierPrefab.transform.position.y + (i * rowOffset);
soldiers[i].mono.transform.position = position;
}
transform.SetAsLastSibling()
and transform.SetSiblingIndex()
are only setting the transforms in the hierarchy, not on the screen.
If I understand what you want to do is that you want to sort your list then display each of the list objects on screen in their sorted order.
Your switch statement already sorts the TrisectRow
list correctly, you just need to change the position of the objects according to their index.
In the sample code I listed above I placed my prefab location at the top. I the calculated the offset from one row to the next and placed it in my test example.
I have included two Unity packages, one uses the Unity UI and the other uses TextMesh that shows slightly modified versions of your script (the main purpose was just to show the sorting).
Yes, this worked for my setup. Thank you for the help!