How to get last few element from foreach gameobject.transform - c#

currently i do it manually by checking every loop of array with if statement
float addGap = gapFix;
foreach (Transform child in topViewPlan.transform)
{
if (child.name.Substring(5, 2).Equals("45") || child.name.Substring(5, 2).Equals("46") || child.name.Substring(5, 2).Equals("47") || child.name.Substring(5, 2).Equals("48"))
{
//rearrange child position
if (!child.name.Substring(5, 2).Equals("45"))
child.transform.localPosition += Vector3.right * addGap * 2;
else
child.transform.localPosition += Vector3.right * addGap;
}
}
is there any possibilities to get last few element of topViewPlan.transform ?
as an example letsay topViewPlan.transform consist of 10 element, and I want last 4 element (which is element 7,8,9 and 10) so maybe I could write :-
foreach (Transform child in topViewPlan.transform.getLast(4)){} //this is just example
so i could get last 4 element of the topViewPlan.transform

You can use GetComponentsInChildren< Transform >() which will give you and array with child and the object itself.
for exemple :
var childs = GetComponentsInChildren<Transform>();
int offset = 5; // want the five last elements
for(int i=childs.Length - offset; i<childs.Length; ++i)
{
// Do something with childs[i]
}
But I would assume that this code is inefficient and unstable, I can't assure that the array returned by GetComponentsInChildren is sorted in the right way (parent at 0 and childrens afterwards). A more sure and easy way would be that every child of your GameObject have a particular component, let's say :
class ChildrenIdentificator : MonoBehavior
{
public int id = 0;
}
You would set the id in every child so it have the behavior you want and then you can do :
var childs = GetComponentsInChildren<ChildrenIdentificator>();
for(int i=0 ; i<childs.Length ; ++i)
{
if(childs[i].id == // I let you figure out the rest
}
This way you have a better control and you can see directly what you are doing. You also avoid doing string comparison.
In any case I strongly recommand to not use GetComponentsInChildren at each frame, to solve that you can store the childs array in the Start() function before using it afterward.

Use
transform.childCount
to get number of childs then to get a child do this :
for example this will return child number 5 :
transform.GetChild(5);
the code you need :
int numberOfChildNeeded = 5;
for (int i = transform.childCount - 1; i > transform.childCount - numberOfChildNeeded ; i--)
{
//do something
transform.GetChild(i)
}

Related

Shuffling nested properties on Unity ReorderableList reorder

I have a CustomEditor with a ReorderableList that displays a nested ReorderableList for each element. When I drag elements in the outer, parent ReorderableList to change their order, the inner lists don't change their order correspondingly. Here is a gif of what happens:
As you can see, the first item always has one Connected Waypoints, and the second item always has two.
This is the Pathing Agent script:
public class PathingAgent : MonoBehaviour
{
[System.Serializable]
public class ConnectedWaypointsListContainer
{
public List<WaypointObject> connections = new List<WaypointObject>();
}
public List<WaypointObject> waypoints = new List<WaypointObject>();
public List<ConnectedWaypointsListContainer> connectedWaypoints = new List<ConnectedWaypointsListContainer>();
}
These are the relevant parts of the CustomEditor:
waypointsList = new ReorderableList(serializedObject, serializedObject.FindProperty("waypoints");
SerializedProperty connectedWaypointsProperty = serializedObject.FindProperty("connectedWaypoints");
...
waypointsList.onReorderCallbackWithDetails = (ReorderableList list, int oldIndex, int newIndex) =>
{
connectedWaypointsProperty.arraySize++;
connectedWaypointsProperty.GetArrayElementAtIndex(connectedWaypointsProperty.arraySize - 1).objectReferenceValue = connectedWaypointsProperty.GetArrayElementAtIndex(oldIndex).objectReferenceValue;
if(newIndex < oldIndex)
{
for(int i = oldIndex; i > newIndex + 1; --i)
{
connectedWaypointsProperty.MoveArrayElement(i - 1, i);
}
connectedWaypointsProperty.MoveArrayElement(connectedWaypointsProperty.arraySize - 1, newIndex);
}
else
{
for(int i = oldIndex; i < newIndex - 1; ++i)
{
connectedWaypointsProperty.MoveArrayElement(i + 1, i);
}
connectedWaypointsProperty.MoveArrayElement(connectedWayointsProperty.arraySize - 1, newIndex);
}
if(connectedWaypointsProperty.GetArrayElementAtIndex(connectedWaypointsProperty.arraySize - 1) != null)
{
connectedWaypointsProperty.DeleteArrayElementAtIndex(connectedWaypointsProperty.arraySize - 1);
}
connectedWaypointsProperty.DeleteArrayElementAtIndex(connectedWaypointsProperty.arraySize - 1);
My attempt was to manually shuffle along the ConnectedWaypointsListContainer(s), which required caching the first one to be overwritten and overwriting the last with that saved data. However, I get an error when I try to duplicate the to-be-cached list as the last element in the serialized array by assigning the objectReferenceValue: "type is not a supported pptr value".
How can I cause the connectedWaypoints to reorder along with the waypoints? If I'm on the right track by shuffling the arrays manually, how do I properly make a temp copy so the first element overwritten isn't lost?
Make sure you are making a call to
serializedObject.ApplyModifiedProperties();
so that the changes applies back to the original object.
The symptom hints that this is the case.
Further reading:
https://docs.unity3d.com/Manual/editor-CustomEditors.html
https://docs.unity3d.com/ScriptReference/SerializedObject.html

Get number of children a game object has via script

Title says it all: What is the best way to find out how many children a gameObject has via script.
EDIT 1:
A simple variable transform.hierarchyCount, has been added to Unity 5.4 and above. This should simplify this.
OLD answer for Unity 5.3 and Below:
transform.childCount provided by Adrea is usually the way to do this but it does not return a child under the child. It only returns a child that is directly under the GameObject transform.childCount is been called on. That's it.
To return all the child GameObjects, whether under the child of another child which is under another child then you have to do some more work.
The function below can count child:
public int getChildren(GameObject obj)
{
int count = 0;
for (int i = 0; i < obj.transform.childCount; i++)
{
count++;
counter(obj.transform.GetChild(i).gameObject, ref count);
}
return count;
}
private void counter(GameObject currentObj, ref int count)
{
for (int i = 0; i < currentObj.transform.childCount; i++)
{
count++;
counter(currentObj.transform.GetChild(i).gameObject, ref count);
}
}
Let's say below is what your hierarchy looks like:
With a simple test script:
void Start()
{
Debug.Log("Child Count: " + transform.childCount);
int childs = getChildren(gameObject);
Debug.Log("Child Count Custom: " + childs);
}
This is the result between transform.childCount and the custom function:
Child Count: 2
Child Count Custom: 9
As, you can see the transform.childCount will not count childs of child but only child of the transform. The custom function was able to count all the child GameObjects.
You can access its Transform and use transform.childCount.
Update: this method works for retrieving all children at the first level. If you want to retrieve the children in the overall hierarchy (also at the deeper levels), follow Programmer's answer.

Splitting List based on element variable and element position

hey I'm trying to split a list based on if a bool of the element is true or not. but each time it has passed some true's and encounters a false i want it also to start a new list with the all the false until it encounters true again and so on. so basicly grouping sequences of falses and trues
public void SortWalls()
{
List<Node> innerWallNodes;
foreach(Wall w in walls)
{
WallAxis ax = w.axis;
innerWallNodes = new List<Node>();
for(int i=w.wallNodes.Count-1; i>=0; i--)
{
if(w.wallNodes[i].markedForDoor)
{
//split wall!!
innerWallNodes.Add(w.wallNodes[i]);
w.wallNodes.RemoveAt(i);
}
}
if(innerWallNodes.Count > 0)
{
Wall wall = new Wall(innerWallNodes, ax);
innerWalls.Add(wall);
}
}
}
i did it like this and then build a mesh based on the first and last element of a List. but since there are many scenarios where the innerWallNodes could be somewhere in the middle of the list that get "cut out" and so my remaining "outer wall" would still have the same node index in my grid for the first and last in it's list, still overdrawing my "inner wall"
so lets say every node !markedForDoor is 0 and a every node markedForDoor is 1 and they order something like below in my list.
like this:
|000|11111|00000|11|000| how would i get a list for every between |...| ?
how do i do this in a simple way. I thought Linq would have something for this but can't find anything.
Linq won't help. Here is the code:
List<List<YouObjectType>> SplitList(List<YourObjectType> listToSplit) {
List<List<YouObjectType>> listOfLists = new List<List<YourObjectType>>();
List<YourObjectType> tmp = new List<YourObjectType>();
foreach(YourObjectType item in listToSplit) {
if (tmp.Count > 0
&& tmp[tmp.Count - 1] != item) {
// Compare you items here as you wish,
// I'm not sure what kind of objects
// and what kind of comparison you are going to use
listOfLists.Add(tmp);
tmp = new List<YourObjectType>();
}
tmp.Add(item);
}
if (tmp.Count > 0) {
listOfLists.Add(tmp);
}
return listOfLists;
}
Here is a simple way of doing that (no Linq)
List<Node> input = ...;
var output = new List<List<Node>>();
for (int end = 0; end < input.Count; )
{
int start = end;
while (++end < input.Count && input[end].markedForDoor == input[start].markedForDoor) { }
output.Add(input.GetRange(start, end - start));
}
Lookup Group Results by Contiguous keys on MSDN.
See how it applies to your case on Rextester.

How to get an item from a list by its property, and then use it's other property?

class Node
{
int number;
Vector2 position;
public Node(int number, Vector2 position)
{
this.number = number;
this.position = position;
}
}
List<Node>nodes = new List<Node>();
for (int i = 0; i < nodes.Count; i++) //basically a foreach
{
// Here i would like to find each node from the list, in the order of their numbers,
// and check their vectors
}
So, as the code pretty much tells, i am wondering how i can
find a specific node from the list, specifically one with the attribute "numbers" being i (Eg going through all of them in the order of their "number" attribute).
check its other attribute
Have tried:
nodes.Find(Node => Node.number == i);
Node test = nodes[i];
place = test.position
they cant apparently access node.number / node.position due to its protection level.
Also the second one has the problem that the nodes have to be sorted first.
Also looked at this question
but [] solution is in the "Tried" caterology, foreach solution doesn't seem to work for custom classes.
I'm a coding newbie (Like 60 hours), so don't
Explain in a insanely hard way.
Say i am dumb for not knowing a this basic thing.
Thanks!
I would add properties for Number and Position, making them available to outside users (currently their access modifier is private):
class Node
{
public Node(int number, Vector2 position)
{
this.Number = number;
this.Position = position;
}
public int Number { get; private set; }
public Vector2 Position { get; private set; }
}
Now your original attempt should work:
nodes.Find(node => node.Number == i);
However, it sounds like sorting the List<Node> and then accessing by index would be faster. You would be sorting the list once and directly indexing the list vs looking through the list on each iteration for the item you want.
List<Node> SortNodes(List<Node> nodes)
{
List<Node> sortedNodes = new List<Node>();
int length = nodes.Count; // The length gets less and less every time, but we still need all the numbers!
int a = 0; // The current number we are looking for
while (a < length)
{
for (int i = 0; i < nodes.Count; i++)
{
// if the node's number is the number we are looking for,
if (nodes[i].number == a)
{
sortedNodes.Add(list[i]); // add it to the list
nodes.RemoveAt(i); // and remove it so we don't have to search it again.
a++; // go to the next number
break; // break the loop
}
}
}
return sortedNodes;
}
This is a simple sort function. You need to make the number property public first.
It will return a list full of nodes in the order you want to.
Also: The searching goes faster as more nodes are added to the sorted nodes list.
Make sure you that all nodes have a different number! Otherwise it would get stuck in an infinite loop!

How do I create a dynamic tree in c# that adds up parents to respective children then recusively goes back through?

I want to be able to go through a loop with if statements that will store a set of data. After the first loop gets its values I want to make a loop that goes through the list of values just created. In that loop there will be if statements that add children to the respect current digit in the list. Also each child will add the value of its respective parent. After that occurs the program will go through another loop adding a set of children to each new child previously dynamically made. The new set of children will add the value of the respected parent to there current value.
Some nodes may have 0 children some could have as many as 100. After the tree is created I need to go back through and compare each set of children for each parent and set the respective child sets value that I find to the parent, until eventually the root value will be determined.
Below is a generic outline of part of sort of what I am looking to do.
Basically i'm looking to make a dynamic tree(or any structure that works), then compare its values and find one root optimal value. Any suggestions/ help is welcome, I can't seem to rap my head around how to do this.
class Program
{
static void Main(string[] args)
{
List<int> numbers = new List<int>();
for (int i = 0; i <= 7; i++)
{
for (int j = 0; j <= 7; j++)
{
if (j == 4 || j == 2)
{
numbers.Add(j);
}
}
}
Console.WriteLine();
foreach (int x in numbers)
{
for (int i = 0; i <= 7; i++)
{
for (int j = 0; j <= 7; j++)
{
if (j == 4 || j == 2)
{
// add a child to the current digit
// add current digit to its child
}
}
}
}
// for loop to go through all children just created
// repeat similar process process add parent number to all respective children values
//repeat this process n number of times
Console.Read();
}
}

Categories

Resources