You need a slot collection. I’ll assume you want to know exactly which NPC is sitting where, identified by some integer.
A slot manager is a collection in memory that has a fixed amount of items that can change their state. In theory no two slots should share the same state (unless it’s 0; Edit: in my case it’s a special value of EMPTY), but I’ll ignore that constraint for the sake of simplicity.
You want a couple of features to make this useful, let’s start from the most basic ones first.
First you need an array to represent your seats.
using System;
using System.Collections.Generic;
using UnityEngine;
public class SeatCollection {
public const int EMPTY = -1;
int[] _seats;
int _occupied;
public SeatCollection(int seatCount) {
_seats = new int[seatCount];
Array.Fill(_seats, EMPTY, 0, seatCount); // fill in the 'empty' values
_occupied = 0;
}
}
First we want this basic check in place, this helps with the logic.
// returns true if the seat is vacant, false if not
public bool IsVacant(int seatIndex)
=> _seats[seatIndex] == EMPTY;
Then you want to introduce the means of reading and manipulating the slots.
public int SeatContent(int seatIndex)
=> _seats[seatIndex];
// returns false if the seat was already occupied, we don't want the occupant to 'perish'
public bool TryAssignSeat(int seatIndex, int npcId) {
if(npcId < 0) throw new ArgumentException("NPC id cannot be a negative number.");
if(!IsVacant(seatIndex)) return false;
_seats[seatIndex] = npcId;
_occupied++;
return true;
}
Then you want some helpers to allow you to abstract the collection further. And also to allow for basic ‘unseating’.
// returns EMPTY if seat wasn't occupied, otherwise returns id of unseated NPC
public int Unseat(int seatIndex) {
if(!IsVacant(seatIndex)) {
var npcId = _seat[seatIndex];
_seats[seatIndex] = EMPTY;
_occupied--;
return npcId;
}
return EMPTY;
}
// this is the less smart way to do this
// public bool TryAssignRandomSeat(int npcId)
// => TryAssignSeat(Random.Range(0, _seats.Length), npcId);
Then something to help you query the seats.
public int TotalSeats => _seats.Length;
public int OccupiedSeats => _occupied;
public int VacantSeats => TotalSeats - OccupiedSeats;
// this would be a smarter way to do random seating
public bool TryAssignRandomSeat(int npcId) {
if(VacantSeats == 0) return false; // this is critical because we know there's no space
// there are ways to make this more optimal, but will work just fine for small seat counts
while(!TryAssignSeat(Random.Range(0, _seats.Length), npcId)) {}
return true;
}
// returns the seat index of specified NPC, or EMPTY if it wasn't found
public int SeatOf(int npcId) {
int found = EMPTY;
for(int i = 0; i < _seats.Length; i++)
if(_seats[i] == npcId) { found = i; break; }
return found;
}
// returns true if the specified NPC was seated, false if not
public bool IsSeated(int npcId)
=> SeatOf(npcId) != EMPTY;
Then something to help you iterate through the seated NPCs.
// returns the seated NPCs, one by one in a foreach clause
IEnumerator<int> SeatedNPCs() {
for(int i = 0; i < _seats.Length; i++)
if(!IsVacant(i)) yield return _seats[i];
}
// returns the occupied seats, one by one in a foreach clause
IEnumerator<int> OccupiedSeats() {
for(int i = 0; i < _seats.Length; i++)
if(!IsVacant(i)) yield return i;
}
// unseats everyone and returns an array containing 'everyone'
public int[] UnseatEveryone() {
var result = new int[_occupied];
int index = 0;
for(int i = 0; i < _seats.Length; i++) {
if(!IsVacant(i)) {
result[index++] = _seats[i];
_seats[i] = EMPTY;
}
}
_occupied = 0;
return result;
}
This is how you can use this
var mySchoolBus = new SeatCollection(24);
mySchoolBus.TryAssignRandomSeat(npc1);
mySchoolBus.TryAssignRandomSeat(npc2);
Debug.Log(mySchoolBus.IsSeated(npc3));
Debug.Log(mySchoolBus.IsSeated(npc2));
Debug.Log(mySchoolBus.SeatOf(npc2));
foreach(var npc in mySchoolBus.SeatedNPCs()) {
Debug.Log(npc);
}
foreach(var seat in mySchoolBus.OccupiedSeats()) {
Debug.Log(seat);
}
Debug.Log(mySchoolBus.SeatContent(1) == SeatCollection.EMPTY);
mySchoolBus.Unseat(mySchoolBus.SeatOf(npc1));
mySchoolBus.TryAssignRandomSeat(npc3);
var unseated = mySchoolBus.UnseatEveryone();
Debug.Log(unseated.Length);
NOTE: If something doesn’t work, it’s probably a typo. Please let me know and I’ll fix it.
Also keep in mind I’m likely to edit this a couple of times more, so make sure to refresh the page from time to time.
Edit:
Changed all occurrences of _seats.Count → _seats.Length, that was a major typo on my part.