- Home /
The question is answered, right answer was accepted
List of Lists being overwritten
Hi everyone, i'm very new to unity and was trying to create a sprouts pen and paper game for my project. I managed to draw lines and give them edge colliders, however I realized that you cannot check for collisions between 2 edge colliders, so I am trying a workaround, in my code fingerpositions is a list of vector2 points for the line, I am trying to add this list to a listofLists of type List List Vector2. The issue is that for some reason, whenever I draw another line it seems to add that line to the list and then for whatever reason also overwrites all the previous lines with the new line. So as an example my line initially has for example, (2.5, 3.5) as its 10th coordinate, the second line I draw has (3.6,7.2). When I print out the list of Lists it gives me (3.6,7.2) (3.6,7.2) as if the second line has been added to the list of Lists as well as overwritting the first one. I have tried creating a function to check if lines are overlapping coordinates called OwnCollisionDetector, but it isn't functioning correctly because of this bug. I tried copying fingerPosition list into a tempCloneList to see if that would change anything but it didn't. Here is my code below:
using System.Collections; using System.Collections.Generic; using UnityEngine;
public class DrawLine : MonoBehaviour { public GameObject linePrefab; public GameObject currentLine;
public PolygonCollider2D PolyCollider;
public LineRenderer lineRenderer;
public EdgeCollider2D edgeCollider;
public Rigidbody2D RB;
public List<Vector2> fingerPositions;
public bool DrawStatus;
public bool startedDrawing;
public bool EndedOnCircle;
public List<List<Vector2>> ListOfLists = new List<List<Vector2>>();
public List<Vector2> TempCloneList = new List<Vector2>();
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0) && DrawStatus == true)
{
CreateLine();
}
if(Input.GetMouseButtonUp(0))
{
if (EndedOnCircle == false && DrawStatus == true)
{
Debug.Log("Invalid Line");
fingerPositions.Clear();
Destroy(currentLine);
}
else if (EndedOnCircle == true && DrawStatus == true)
{
//foreach (Vector2 item in fingerPositions) { print(fingerPositions[item]); }
//fingerPositions.ForEach();
//for loop is to print out all the vector2 positions of the current line WORKING
TempCloneList.Clear();
for (int i = 0; i < fingerPositions.Count; i++) // Loop through List with for
{
TempCloneList.Add(fingerPositions[i]);
//print(fingerPositions[i]);
}
/*
//if statement below calls the function to check if a line is colliding with another and destroys
//it if it is, otherwise it is valid and adds it the list of lists
//print(edgeCollider.points[1]);
if (OwnLineCollisionDetector() == true) { Debug.Log("Current line is colliding with another"); Destroy(currentLine); } else {ListOfLists.Add(TempCloneList); } //ListOfLists.Add(TempCloneList); fingerPositions.Clear(); /* for (int w = 0; w<ListOfLists.Count; w++) { Debug.Log(ListOfLists[w][25]); } */ } DrawStatus = false; } if(Input.GetMouseButton(0) && DrawStatus == true) { Vector2 tempFingerPos = Camera.main.ScreenToWorldPoint(Input.mousePosition); if (Vector2.Distance(tempFingerPos, fingerPositions[fingerPositions.Count - 1]) > .1f); { UpdateLine(tempFingerPos); } } } //we only want to call createlIne when user has touched the screen void CreateLine() //function to create the line when the user touches the screen { currentLine = Instantiate(linePrefab, Vector3.zero, Quaternion.identity); lineRenderer = currentLine.GetComponent<LineRenderer>(); edgeCollider = currentLine.GetComponent<EdgeCollider2D>(); PolyCollider = currentLine.GetComponent<PolygonCollider2D>(); RB = currentLine.GetComponent<Rigidbody2D>(); fingerPositions.Clear(); fingerPositions.Add(Camera.main.ScreenToWorldPoint(Input.mousePosition)); fingerPositions.Add(Camera.main.ScreenToWorldPoint(Input.mousePosition)); lineRenderer.SetPosition(0, fingerPositions[0]); lineRenderer.SetPosition(1, fingerPositions[1]); edgeCollider.points = fingerPositions.ToArray(); } void UpdateLine(Vector2 newFingerPos) { fingerPositions.Add(newFingerPos); lineRenderer.positionCount++; lineRenderer.SetPosition(lineRenderer.positionCount - 1, newFingerPos); edgeCollider.points = fingerPositions.ToArray(); } bool OwnLineCollisionDetector() { if (ListOfLists != null) { if (ListOfLists.Count > 0) { for (int i = 0; i < ListOfLists.Count; i++) // loop through list of lists { for (int x = 0; x < ListOfLists[i].Count; x++) // loop through each vector2 point in a list { for (int y = 0; y < fingerPositions.Count; y++) // loop through each vector2 point in current fingerpositions list and compare them { if (fingerPositions[y] == ListOfLists[i][x]) { Debug.Log(fingerPositions[y]); Debug.Log(ListOfLists[i][x]); return true; } } } } return false; } else { return false; } } return false; }
}
Answer by Bunny83 · Mar 04, 2020 at 06:21 PM
Lists and arrays are objects. Objects never magically duplicate themselfs. When you use the new keyword you actually allocate some memory on the heap and a new object is created there. Let's see how many objects you actually create.
You create exactly two objects. One object is of type List<List<Vector2>>
and the object's reference is stored in the "ListOfLists" variable. The second object is of type List<Vector2>
and originally stored in the "TempCloneList" variable.
When you execute this line:
ListOfLists.Add(TempCloneList);
you do not somehow create a new list. You just stored a reference to your one, single TempCloneList in your ListOfLists. So in the end your ListOfLists just contains several elements all pointing to the same list. Since each step you actually clear your temp list, the content in that list will be just what you put in last.
You generally have two options here. Either create a new TemoCloneList once you stored the old one in your ListOfLists so you continue working with a new fresh list object. The second option (which is probably the simplest solution here) is to create a new List based on your temp list before you store it in your outer list.
So instead of this line:
ListOfLists.Add(TempCloneList);
you can just do
ListOfLists.Add(new List<Vector2>(TempCloneList));
This will create a new list and copy the elements from the templist into your new list. The newly created list will be the one stored in your ListOfLists.
Hi, thank you so much for this answer it really did help, but i'm wondering if you could help me with another bug, this is probably just a misunderstanding of how unity is working, but still, at the bottom you see where iv'e made my own edge detector, this bit :
bool OwnLineCollisionDetector()
{
if (ListOfLists != null)
{
if (ListOfLists.Count > 0)
{
for (int i = 0; i < ListOfLists.Count; i++) // loop through list of lists
{
for (int x = 0; x < ListOfLists[i].Count; x++) // loop through each vector2 point in a list
{
for (int y = 0; y < fingerPositions.Count; y++) // loop through each vector2 point in current fingerpositions list and compare them
{
if (fingerPositions[y] == ListOfLists[i][x])
{
Debug.Log(fingerPositions[y]);
Debug.Log(ListOfLists[i][x]);
return true;
}
}
}
}
return false;
}
else { return false; }
}
return false;
}
It worked once or twice but not often enough, even when the lines were clearly intersecting, im not sure why but iv'e got a feeling it has something to do with update going too quickly and it not having time to go through 3 loops and check all coordinates?
I call it here :
if (OwnLineCollisionDetector() == true)
{
Debug.Log("Current line is colliding with another");
Destroy(currentLine);
}
else {ListOfLists.Add(new List<Vector2>(TempCloneList)); }
This is inside the update() method
Follow this Question
Related Questions
multiple shaders per shader file 2 Answers
how do you interpret error logs? 1 Answer
How to Code? 2 Answers
Blue glow around model 1 Answer
Changing collider PhysicMaterial at run-time doesn't also change properties associated with it. 0 Answers