thanks in advance. I'm a Unity developer.
So I have my AI states in enum converted to a list.
public enum IdleState
{
BasicIdle,
PlayingWithKids,
Playfull,
Curious,
Bored,
MoveToCamera,
Waiting,
PlantMode,
Shy,
Crying
}
public List<IdleState> availableIdleStates = new List<IdleState>()
{
IdleState.BasicIdle,
IdleState.PlayingWithKids,
IdleState.Playfull,
IdleState.Curious,
IdleState.Bored,
IdleState.Waiting,
IdleState.PlantMode,
IdleState.Shy,
IdleState.Crying
};
I'm controlling the order of execution through my public list in my inspector witch works fine, however I would like to have basic idle (enum int = 0) execute multiple times in my inspector order of execution. Although when the list gets to my second basic idle it restarts and gets stuck between the two basic idles I assume its because its value in enum is 0, but i really don't know whats causing this, any help would be a blessing. thanks guys!
private void FixedUpdate()
{
if (Time.timeSinceLevelLoad > prevIdleStateChangeTime + currentStateDuration)
{
int i = availableIdleStates.FindIndex(x => x.Equals(currentIdleState))+1;
if (i >= availableIdleStates.Count)
{
i = 0;
}
changeState(availableIdleStates[i]);
}
switch (currentIdleState)
{
case IdleState.BasicIdle:
if (Time.timeSinceLevelLoad > subStateChangeTime + subStateDuration)
{
subStateChangeTime = Time.timeSinceLevelLoad;
switch (randInt)
{
//something
}
}
break;
case IdleState.PlayingWithKids:
if (Time.timeSinceLevelLoad > subStateChangeTime + subStateDuration)
{
int randInt = Random.Range(0, 3);
subStateChangeTime = Time.timeSinceLevelLoad;
switch (randInt)
{
//something
}
}
break;
etc..
every state change this method is being called:
private void changeState(IdleState NewState)
{
currentIdleState = NewState;
prevIdleStateChangeTime = Time.timeSinceLevelLoad;
mover.resetParameters();
subStateChangeTime = Time.timeSinceLevelLoad;
subStateDuration = -1;
}
availableIdleStates.FindIndex(x => x.Equals(currentIdleState))
Here. If first and second object is the same this will always find first occurence of your duplicated state (id = 0), your script changes it to id = 1 but in next update again first element is found and your id is back to 0. You should have field for that int value instead of finding index on list if you want to have duplicate elements.
Related
I have a unity project and want to call methods one after another using a predefined list.
In this test scenario I want to execute startTrialWithFixedValue1() two times, startTrialWithFixedValue2() two times and startTrialWithRandomValue() one time in the end. Every time the user makes an input, I want to execute the next method from the list. There are two major problems with my code:
(1) Whenever I use an if statement with return the variable countTrial becomes unreachable. The debug log shows always 0:1 and the first method is executed all the time.
(2) If I exclude the return statement, all methods are started at once.
[EDIT] To specify my question: How can I execute methods following the order of a given list.
Script A:
public int countTrial;
public int maxTrials = 16;
public Spawner spawner;
List<int> trialMarkers = new List<int>() {1, 1, 2, 2, 3};
public void chooseNextTrial()
{
for (int countTrial = 0; countTrial < maxTrials; countTrial++)
{
Debug.Log(countTrial + ": " + trialMarkers[countTrial]);
if (trialMarkers[countTrial] == 1)
{
spawner.startTrialWithFixedValue1();
return;
}
if (trialMarkers[countTrial] == 2)
{
spawner.startTrialWithFixedValue2();
return;
}
else
{
spawner.startTrialWithRandomValue();
return;
}
}
Script B:
public void handleUserInput()
{
if (Input.GetButtonDown("Fire3"))
{
deleteAllChildren();
chooseTrial.chooseNextTrial();
}
}
}
Hope you guys can help me!
[EDIT2] As suggested by Programmer: Remove the return statement in that function then run it again. Copy and paste the result of Debug.Log(countTrial + ": " + trialMarkers[countTrial]); the result is always:
5:3
5:3
5:3
...
You need to remove the For loop and handle the execution of Method more manualy
public int countTrial = 0;
public int maxTrials = 16;
public Spawner spawner;
List<int> trialMarkers = new List<int>() {1, 1, 2, 2, 3};
public void chooseNextTrial()
{
Debug.Log(countTrial + ": " + trialMarkers[countTrial]);
if (trialMarkers[countTrial] == 1)
{
spawner.startTrialWithFixedValue1();
}
if (trialMarkers[countTrial] == 2)
{
spawner.startTrialWithFixedValue2();
}
else
{
spawner.startTrialWithRandomValue();
}
}
And then inside your second script (Script B) which handles the user input
public void handleUserInput()
{
if (Input.GetButtonDown("Fire3"))
{
deleteAllChildren();
chooseTrial.chooseNextTrial();
chooseTrial.countTrial++;
}
}
End line: You shouldnt use a Fop loop since you want the sequence to be startied whith a player input action and handle it like this. Also adding a method like this:
public void NextCounter()
{
if(countTrial<trialMarkers.Count)
countTrial++
}
In your Script A and then call it like this in Script B to avoid your counter going above the list count.
chooseTrial.NextCounter();
Insteed of using the countTrial++ in SCript B
When you return in the method you are breaking out of your loop.
for (int countTrial = 0; countTrial < (maxTrials <= trialMarkers.Count ? maxTrails : trialMarkers.Count) ; countTrial++)
{
Debug.Log(countTrial + ": " + trialMarkers[countTrial]);
if (trialMarkers[countTrial] == 1)
{
spawner.startTrialWithFixedValue1();
}
if (trialMarkers[countTrial] == 2)
{
spawner.startTrialWithFixedValue2();
}
else
{
spawner.startTrialWithRandomValue();
}
}
Will execute the way you are asking. Also note I changed your iterator so that you do not get an object reference error in your loop.
How about doing something similar to what you describe in the title (which gives the impression that you have a "list of functions"). This example is easily extensible:
private Action[] _functions;
public void MainEntryPoint()
{
_functions = new Action[] { StartTrialWithFixedValue1, StartTrialWithFixedValue2, StartTrialWithRandomValue };
List<int> trialMarkers = new List<int>() { 1, 1, 2, 2, 3 };
DoThings(trialMarkers);
}
public void DoThings(IEnumerable<int> indexesOfFuctions)
{
foreach (var index in indexesOfFuctions)
{
_functions[index-1]();
}
}
private void StartTrialWithFixedValue1()
{
Trace.WriteLine("StartTrialWithFixedValue1");
}
private void StartTrialWithFixedValue2()
{
Trace.WriteLine("StartTrialWithFixedValue2");
}
private void StartTrialWithRandomValue()
{
Trace.WriteLine("StartTrialWithRandomValue");
}
I create an "array of functions" (actually of Delegates to functions), and then I use your list of instructions to execute them.
So sorry for this vague question... its doing my head in...
Basically just a test project, use the [+] key to add a bunch of values into the List.... The arrow keys need to go up and down the List values...
When a new value is added to the list the "historySelected" is reset, so that the 'Up Arrow'.. always selects the last item added in the List first, and then if you keep pressing it, it goes back through the List values. At anytime if the 'Down Arrow' key is pressed it needs to go back to the previous value in the List of values. At no point should a Up Arrow key followed by a Down Arrow key show the same List value, and vice versa..
The behavior I'm looking for is much like a developer console with a command history, where Up arrow goes further back in history, and Down arrow the opposite.
Again apologies for the code, its been through so many test changes, currently this works going Up arrow to the start of the List value, and then using the Down arrow to go all the back to the highest List index... but the problem is if you go half way through the List (or inbetween anyway), and switch from Up arrow.. to Down arrow.. the values increment/decrement don't act accordingly... I can't seem to get the right codelogic for it.
Any help or suggestions thanks.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ArrowKeys {
class Program {
//public static List<string> cmdHistory = new List<string>() { "1", "2", "3", "4", "5" };
public static List<string> cmdHistory = new List<string>();
public static int cmdHistoryCount = 0;
public static int historySelected = 0;
public static int num = 0;
public static string current = "";
public enum UpDown {
reset,
up,
down
};
public static UpDown LastUpDown;
static void Main(string[] args) {
bool running = true;
while (running) {
ConsoleKeyInfo kb = Console.ReadKey();
switch (kb.Key) {
case ConsoleKey.Escape:
Console.WriteLine("Exit");
running = false;
return;
case ConsoleKey.Add:
cmdHistory.Add(num.ToString());
cmdHistoryCount++;
historySelected= cmdHistoryCount;
LastUpDown = UpDown.reset;
Console.WriteLine(string.Join(" ", cmdHistory.Cast<string>().ToArray()));
num++;
break;
case ConsoleKey.UpArrow:
UpArrow();
LastUpDown = UpDown.up;
Console.WriteLine("UpArrow pressed");
Console.WriteLine(current);
break;
case ConsoleKey.DownArrow:
DownArrow();
LastUpDown = UpDown.down;
Console.WriteLine("DownArrow pressed");
Console.WriteLine(current);
break;
}
}
}
public static int Clamp(int value, int min, int max) {
return (value < min) ? min : (value > max) ? max : value;
}
public static void UpArrow() {
if (cmdHistoryCount != 0) {
if (LastUpDown == UpDown.down) {
if (historySelected - 1 == 0) {
return;
}
}
current = cmdHistory[historySelected - 1];
if (historySelected - 1 == 0) {
return;
}
historySelected--;
}
}
public static void DownArrow() {
if (cmdHistoryCount != 0) {
if (LastUpDown == UpDown.up) {
if (historySelected + 1 > cmdHistoryCount) {
return;
}
}
current = cmdHistory[historySelected - 1];
if (historySelected + 1 > cmdHistoryCount) {
return;
}
historySelected++;
}
}
}
}
It sounds like you simply need to stop your index going out of range. It's not clear what the existing code was intended to do, but your clarification seems to imply it's not necessary. Try this:
public static void UpArrow()
{
historySelected = Math.Max(0, historySelected - 1);
current = cmdHistory[historySelected];
}
public static void DownArrow()
{
var maxIndex = cmdHistory.Count - 1;
historySelected = Math.Min(maxIndex, historySelected + 1);
current = cmdHistory[historySelected];
}
If I'm understanding what you're looking for correctly, a pair of dueling stacks might work for your case. They're going to give you the FILO/LIFO style item access you're looking for. Drop the List and do something like:
var UpStack = new Stack<string>();
var DownStack = new Stack<string>();
On "new item"
UpStack.Push(newItem);
On "Up"
DownStack.Push(UpStack.Pop());
On "Down"
UpStack.Push(DownStack.Pop());
If you wanted a "buffer" item that isn't in either of the stacks, that's easy enough to do by just Popping into the buffer item. It's a little more management, because you'd have to push it onto one stack, then pop the other each time, but it's whatever. There's also the Peek() method, which gets the item on top of a Stack without Popping it, so you use that for your display item, as well.
I have the following algorithm:
class CycleData : List<IntPoint>{
public IntPoint startPoint;
public Boolean ended=false;
public CycleData(IntPoint startpoint) { startPoint = startpoint; base.Add(startpoint); }
}
class GeoDataGraphPoint
{
private IntPoint point;
private List<GeoDataGraphPoint> connected = new List<GeoDataGraphPoint>();
private int generation=-9999;
public void AddConnection(GeoDataGraphPoint c)
{
connected.Add(c);
c.connected.Add(this);
}
public GeoDataGraphPoint(IntPoint point)
{
this.point = point;
}
public List<CycleData> GetCycles(int gen)
{
if (generation != -9999)
{
var r = new CycleData(point);
return new List<CycleData> { r };
}
generation = gen;
List<CycleData> res = new List<CycleData>();
foreach (GeoDataGraphPoint p in connected)
{
if (p.generation != gen-1)
{
res.AddRange(p.GetCycles(gen + 1));
}
}
foreach (CycleData list in res)
{
if (list.ended == false)
{
list.Add(point);
if (list.startPoint == this.point)
{
list.ended = false;
}
}
}
gen = -9999;
return res;
}
}
Now in principle this should return every cycle in the graph (for polygon detection). However it seems to fail to return anything in some occasions, I suspect that there is some kind of memory problem as removing parts of the graph sometimes causes new cycles to be found.
Here is a part of the input where it fails:
connection:(2282,3) to (2282,-192)
connection:(2282,3) to (2085,3)
connection:(2282,-192) to (2282,3)
connection:(2282,-192) to (2466,-192)
connection:(2466,-192) to (2282,-192)
connection:(2466,-192) to (2466,581)
connection:(2466,581) to (2466,-192)
connection:(2466,581) to (1494,581)
connection:(1494,581) to (2466,581)
connection:(1494,581) to (1494,397)
connection:(1494,397) to (1494,581)
connection:(1494,397) to (2282,397)
connection:(2282,397) to (1494,397)
connection:(2282,397) to (2282,187)
connection:(2282,187) to (2282,397)
connection:(2282,187) to (2085,187)
connection:(2085,187) to (2282,187)
connection:(2085,187) to (2085,3)
connection:(2085,3) to (2085,187)
connection:(2085,3) to (2282,3)
connection:(2085,3) to (2085,187)
connection:(2085,3) to (2282,3)
connection:(2085,187) to (2282,187)
connection:(2085,187) to (2085,3)
connection:(2282,187) to (2282,397)
connection:(2282,187) to (2085,187)
connection:(2282,397) to (1494,397)
The above code is for two triangles arranged to form a square (in coordinates) where both sides touch one another so like this:
Where I can the function as following:
class GeoDataGraph : Dictionary<IntPoint, GeoDataGraphPoint>
{
public void resetGens()
{
foreach(var v in base.Values)
{
v.generation = -9999;
}
}
public static Island GetHolesInIsland(Island input)
{
GeoDataGraph graph = new GeoDataGraph();
for (int i = 0; i < input.area.Count-1; i = i + 2)
{
var p1 = new IntPoint(input.area[i].X, input.area[i].Y);
var p2 = new IntPoint(input.area[i + 1].X, input.area[i + 1].Y);
if (!graph.ContainsKey(p1)) graph.Add(p1, new GeoDataGraphPoint(p1));
if (!graph.ContainsKey(p2)) graph.Add(p2, new GeoDataGraphPoint(p2));
graph[p1].AddConnection(graph[p2]);
}
IntPoint min = new IntPoint(int.MaxValue, int.MaxValue);
List<IntPoint> minCycle = null;
List<List<IntPoint>> cycles = new List<List<IntPoint>>();
while (graph.Count != 0)
{
var first = graph.First();
var NewCycles = first.Value.GetCycles(1);
graph.resetGens();
if (NewCycles.Count == 0)
{
graph.Remove(first.Key);
Console.WriteLine("point" + first.Key + "is uncycled");
}
cycles.AddRange(NewCycles);
foreach (var cycle in NewCycles)
{
foreach (var cycleNode in cycle)
{
graph.Remove(cycleNode);
if (min.X > cycleNode.X || min.Y > cycleNode.Y)
{
minCycle = cycle;
min = cycleNode;
}
}
}
}
cycles.Remove(minCycle);
if (minCycle == null) { minCycle = new List<IntPoint>();
foreach(IntPoint a in input.area) {
Console.Write(a);
} }
input.holes = cycles;
input.area = minCycle;
return input;
}
}
}
where Island contains.area contains a list of points ordered by connected pairs.
The basic algorithm is simple: take a node recursively visit every node connected to it until you detect a cycle, then return that node and append any node on the way out until you find the start of the cycle again. Once you have found every node connected to the start node remove the cycles (they since we checked every node connected to the cycle we shouldn't be deleting the once we already did) and start again on the next node, if a node contains no cycles remove it. I suspect something might be going wrong at this step but am unsure.
Any idea what I'm doing wrong that causes a weird interdependence that causes seemingly unrelated polygons to go wrong?
I think that one problem is the way you ignore connected nodes using p.generation != gen-1. As you use depth first search you will tag all the nodes until the most depth and when backtracking I think it can miss some nodes or explore nodes twice.
As a general advise I can say: Don't reinvent the wheel yourself but use a known algorithm.
First ask yourself what you want to do. The number of cycles can be exponential. So the question is if you really need all the cycles.
If the answer is yes and you want to find all the cycles in a undirected graph you can get more information here.
If you don't really need all the cyles maybe what your are looking for is to find strongly connected components.
I am doing a project using Unity and C# but I don't feel this is necessarily Unity related. I have two separate hands that are represented by 2 instances of a hand class.
public class HandController
{//....class}
HandController LeftHand = new HandController();
HandController RightHand = new HandController();
I am constantly doing twice the work in a lot of areas to affect the hands because each hand needs to be treated independently. So for instance I am using a Leap motion controller and if one of the hands is not detected I want to inform the user of this. So I change the color of the hand in the update method.
Color notDetected = Color.red;
Color detected = new Color(189/255.0f, 165/255.0f, 134/255.0f);
if (!LeftHandTracked)
LeftHand.renderer.material.color = notDetected;
if (!RightHandTracked)
RightHand.renderer.material.color = notDetected;
if (LeftHandTracked)
LeftHand.renderer.material.color = detected;
if (RightHandTracked)
RightHand.renderer.material.color = detected;
Is there a more efficient way of doing this? I hate having duplicate if conditionals sprawled all over my code. I also am tracking fingers, so each finger needs to be recognized and I get an even worse chain of if conditionals
if (TappedFingers[0] && !_keySpamBlock)
LeftHand.SetSide(true, _pointer);
if (TappedFingers[1] && !_keySpamBlock)
LeftHand.SetSide(true, _middle);
if (TappedFingers[2] && !_keySpamBlock)
LeftHand.SetSide(true, _ring);
if (TappedFingers[3] && !_keySpamBlock)
LeftHand.SetSide(true, _pinky);
if (TappedFingers[4] && !_keySpamBlock)
RightHand.SetSide(true, _pointer);
if (TappedFingers[5] && !_keySpamBlock)
RightHand.SetSide(true, _middle);
if (TappedFingers[6] && !_keySpamBlock)
RightHand.SetSide(true, _ring);
if (TappedFingers[7] && !_keySpamBlock)
RightHand.SetSide(true, _pinky);
_pinky and _ middle and etc.. are hash values I pass into SetSide method in the HandController class that allow me to access the animationcontroller booleans I have set in Unity. SetSide() basically just sends the true if a user taps their finger and it plays an animation on the appropriate finger.
EDIT: To Clarify a little more whats going on
I am connecting to an API by inheriting a class and establishing an event listener:
public class AppListener : ErghisListener {
public delegate void onUpdate(Data d);
public event onUpdate Updated;
public override void OnErghisFrame(Data data)
{
Loom.QueueOnMainThread(() => { this.Updated(data); });
}
}
Then I have a MainController where recieve the data object from the API:
public class MainController: MonoBehaviour{
private AppListener _appListener;
private int _pointer;
private int _middle;
private int _ring;
private int _pinky;
void Start()
{
this._appListener = new AppListener();
this._appListener.Updated += callback;
this._pointer = Animator.StringToHash("Pointer");
this._middle = Animator.StringToHash("Middle");
this._ring = Animator.StringToHash("Ring");
this._pinky = Animator.StringToHash("Pinky");
}
public void callback(Data d)
{
// Here is where all my annoying if conditionals were.
bool[] TappedFingers = d.tappedF;
}
Your first code snippet would look much more logical if it was something like this:
class HandController : MonoBehaviour
{
bool m_Tracked;
Color NotDetected { get { return Color.red; } }
Color Detected { get { return new Color(189/255.0f, 165/255.0f, 134/255.0f); } }
public bool Tracked
{
if (m_Tracked == value) return;
m_Tracked = value;
renderer.material.color = value ? Detected : NotDetected;
}
}
// ...
LeftHand.Tracked = LeftHandTracked;
if (TappedFingers.Length != FINGERS*2)
{
Debug.LogError("Unexpected amount of fingers: " + TappedFingers.Length);
return;
}
for(int i = 0; i < FINGERS; i++)
{
LeftHand.SetSide(TappedFingers[i], i);
}
for(int i = FINGERS; i < FINGERS*2; i++)
{
RightHand.SetSide(TappedFingers[i], i-FINGERS);
}
You could simply use else here.
if (LeftHandTracked)
LeftHand.renderer.material.color = detected;
else
LeftHand.renderer.material.color = notDetected;
I would prefer inline conditional.
LeftHand.renderer.material.color = LeftHandTracked ? detected : notDetected;
As for the second example, you can wrap all the statements in a single if block to remove visual noise:
if (!_keySpamBlock)
{
if (TappedFingers[0])
LeftHand.SetSide(true, _pointer);
if (TappedFingers[1])
LeftHand.SetSide(true, _middle);
}
The other option with Linq (which is not more efficient, but so much prettier):
var sides = new[] { _pointer, _middle };
if (!_keySpamBlock)
TappedFingers.Zip(sides, (x, y) => { if (x) { LeftHand.SetSide(true, y); });
I'd say this is clear and looks good enough. I don't see how polymorphism could help here, but you could investigate it yourself.
for the first part:
LeftHand.renderer.material.color = LeftHandTracked ? detected : notDetected;
RightHand.renderer.material.color = RightHandTracked ? detected : notDetected;
second part:
if(!_keySpamBlock)
{
int index=Array.FindLastIndex(TappedFingers.Take(8).ToArray(), i => i);
switch (index)
{
case 0: {LeftHand.SetSide(true, _pointer); break;}
case 1: {LeftHand.SetSide(true, _middle); break;}
//.........
case 7: {RightHand.SetSide(true, _pinky); break;}
}
}
Would it be possible to tell me the best way of moving elements in a List<> up and down.
For example I have a class called Building and Building has a list of Rooms objects List<Room>. The rooms are added to the building by name, but I am using this structure to generate a tree view. The user has the option to move a room up and down within a building.
I was trying to use .Reverse(index, count) but this didn't seem to do anything:
// can this item actually be moved up (is it at the first position in it's current parent?)
if (moveDirection == MoveDirection.UP)
{
int roomIndex = parentBuilding.Rooms.IndexOf(room);
if (roomIndex == 0)
{
return;
}
else
{
// move this room up.
parentBuilding.Rooms.Reverse(roomIndex, 1);
}
}
Create a list extension. Call as List<T>.Move(1, MoveDirection.Up).
public static class ListExtensions
{
public static void Move<T>(this IList<T> list, int iIndexToMove,
MoveDirection direction)
{
if (direction == MoveDirection.Up)
{
var old = list[iIndexToMove - 1];
list[iIndexToMove - 1] = list[iIndexToMove];
list[iIndexToMove] = old;
}
else
{
var old = list[iIndexToMove + 1];
list[iIndexToMove + 1] = list[iIndexToMove];
list[iIndexToMove] = old;
}
}
}
public enum MoveDirection
{
Up,
Down
}
Things to consider
Exception handling - what if you are trying to move the bottom
element down or top element up? You will get an index out of range
because you can't move these up or down.
You could improve this and prevent handling exception by extending
functionality to moving the top element to the bottom element and
bottom element down to the top element etc.
Just do a swap:
int roomIndex = parentBuilding.Rooms.IndexOf(room);
if (roomIndex == 0)
{
return;
}
else
{
// move this room up.
var temp = parentBuilding.Rooms[index-1];
parentBuilding.Rooms[index-1] = parentBuilding.Rooms[index];
parentBuilding.Rooms[index] = temp;
}
Personally, I'd make extension method:
static void Swap<TSource>(this IList<TSource> source, int fromIndex, int toIndex)
{
if (source == null)
throw new ArgumentNullExcpetion("source");
TSource tmp = source[toIndex];
source[toIndex] = source[fromIndex];
source[fromIndex] = tmp;
}
Usage:
if (moveDirection == MoveDirection.UP)
{
int roomIndex = parentBuilding.Rooms.IndexOf(room);
if (roomIndex == 0)
{
return;
}
else
{
// move this room up.
parentBuilding.Rooms.Swap(roomIndex, roomIndex - 1);
}
}
How about using SortedDictionary<int, Room> instead of a list. You could store an index in as a Key of the Dictionary and just swap the values when needed.
Swapping places with the room that used to be above should do it:
int roomIndex = parentBuilding.Rooms.IndexOf(room);
if (roomIndex == 0)
{
return;
}
var wasAbove = parentBuilding.Rooms[roomIndex - 1];
parentBuilding.Rooms[roomIndex - 1] = room;
parentBuilding.Rooms[roomIndex] = wasAbove;
That said, I 'm not sure that this is the best object model for the situation; it's not clear that the order of rooms in the list plays a role, and it's also not clear how a room can be "moved up" -- what does that mean?
It might be better to have a RoomPlacement class that aggregates a room and enough information to locate it, and work with that instead.
try this:
int newIndex = whateverIndexYouWantItAt;
int oldIndex = parentBuilding.Rooms.IndexOf(room);
var item = parentBuilding.Rooms[oldIndex];
list.RemoveAt(oldIndex);
if (newIndex > oldIndex) newIndex--;
parentBuilding.Rooms.Insert(newIndex, item);