- Home /
Infinite for loop and List problem
I'm currently working on a game where the player can draw a line on the screen, on the player character will move to and along the line, removing points from the line after the character reaches them.
I'm currently trying to implement the removal part of the code, but I'm running into a problem where Unity will crash due to what I expect to be an infinite for loop. Here is the code I've got so far, and the for loop I believe is causing the problem is on line 49 of MoveOnLine.cs. Strangely however, the first time it runs through the for statement, there is no crash. Rather it only happens when the character tries to run the code at the next point that it crashes. MoveOnLine.cs
public class MoveOnLine : MonoBehaviour
{
public GameObject gameController; // Object that holds the DrawLine script
DrawLine lineInfo; // variable to use/assign to DrawLines' values
List<Vector2> newPositions = new List<Vector2>(); // List used to increment the line's values
public float speed; // Player speed
Rigidbody2D rb; // Player's Rigidbody
private void Start()
{
lineInfo = gameController.GetComponent<DrawLine>();
rb = GetComponent<Rigidbody2D>();
}
private void FixedUpdate()
{
Vector2 currentPos = new Vector2(transform.position.x, transform.position.y);
// if a line exists...
if(lineInfo.currentLine != null)
{
// Move the character towards the first point of that line
transform.position = Vector3.MoveTowards(currentPos, lineInfo.fingerPositions[0],
Time.fixedDeltaTime * speed);
// When the character position is the same as the first point's position...
// ...this block of code *should* move all the values over by one...
// ...so that fingerPositions[0] becomes fingerPositions[1], etc.
if (currentPos == lineInfo.fingerPositions[0])
{
int newPositionCount = lineInfo.fingerPositions.Count - 1;
Debug.Log(newPositionCount);
// Goes through each spot on the fingerPositions list + 1, to get the "new" finger positions
for (int i = 0; i < newPositionCount; i++)
{
newPositions.Insert(i, lineInfo.fingerPositions[i + 1]);
}
// Changes the original line's positions to the new positions, essentially removing...
// ...point 0 of fingerPositions
lineInfo.fingerPositions = newPositions;
// Repeats the process if it's the first point of a line, because each line starts...
// ...with two points (in case it's a dot)
if (lineInfo.firstPoint)
{
for (int i = 0; i < newPositionCount; i++)
{
newPositions.Insert(i, lineInfo.fingerPositions[i + 1]);
}
lineInfo.fingerPositions = newPositions;
}
}
}
}
}
DrawLine.cs (this is in charge of drawing the line of the screen, so I'm including it for the context of variables) public class DrawLine : MonoBehaviour { public GameObject linePrefab; // Line Object to Instantiate public GameObject currentLine; // Object that holds the currently Instantiated line public bool firstPoint; // Does this line still have it's first points to account for a dot?
public LineRenderer lineRenderer;
public EdgeCollider2D edgeCollider;
public List<Vector2> fingerPositions; // List to hold finger/mouse points for the line
// Update is called once per frame
void Update()
{
// Input Starts the line
if (Input.GetMouseButtonDown(0))
{
Destroy(currentLine); // if there is already a line on the screen, destroy it
CreateLine();
}
// Input Continues drawing the Line
if (Input.GetMouseButton(0))
{
Vector2 tempFingerPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
if (Vector2.Distance(tempFingerPos, fingerPositions[fingerPositions.Count - 1]) > 2f) // if previous point is further than X...
{
UpdateLine(tempFingerPos); // ... add the new finger position to the list via the method
}
}
// Allows the player to delete the current line on the screen
if (currentLine != null && Input.GetKeyDown(KeyCode.Delete))
{
Debug.Log("Destroying Line");
Destroy(currentLine);
}
// Used to see if the line still has it's first two point to account for a dot of not
if (currentLine != null && fingerPositions[0] == fingerPositions[1])
{
firstPoint = true;
} else if (currentLine != null && fingerPositions[0] != fingerPositions[1])
{
firstPoint = false;
}
}
// Method to start drawing the line
void CreateLine()
{
currentLine = Instantiate(linePrefab, Vector3.zero, Quaternion.identity); // Creates the line Prefab
lineRenderer = currentLine.GetComponent<LineRenderer>(); // Gets the Components from the Prefab
edgeCollider = currentLine.GetComponent<EdgeCollider2D>();
fingerPositions.Clear(); // Clear the list of points from the previous line
// Immediately adds two points so that a line so even if the line is a dot...
// ...it will start being drawn
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(); // Adds the Vector2 points to the list
}
// Method to continue drawing the line
void UpdateLine(Vector2 newFingerPos)
{
fingerPositions.Add(newFingerPos); // Adds a new point at the finger/mouse Pos
lineRenderer.positionCount++; // Adds a new position for the line
lineRenderer.SetPosition(lineRenderer.positionCount - 1, newFingerPos); // sets the position to the new Vector2 (the -1 is because the count starts at 0)
edgeCollider.points = fingerPositions.ToArray(); // Adds the Vector2 point to the list
}
Any help is greatly appreciated! I'm also still new to Unity Answers so if my formatting is off or that I should be adding any (or removing any useless) info please also let me know!
Answer by fleuryx · Nov 25, 2020 at 05:33 PM
Ok, it turns out I was using code I didn't fully understand (and as blaskojoz pointed out, overly complicated). List.Insert() upon reading up more on is definitely not what I thought it meant, and I ended up replacing it with List.RemoveAt() instead, which both removes the infinite loop and achieves what I was hoping. Thanks everyone for the help!
Answer by blaskojoz · Nov 25, 2020 at 04:56 PM
It's very hard to tell what went wrong here... Your solution is little bit overcomplicated. Did you get any exception?
If u want move your character along a straight line, the only thing you need is:
Vector2 StartPoint;
Vector2 EndPoint;
You can get these values from Input.GetMouseButtonDown and Input.GetMouseButtonUp
After that you can move your character by using Vector2.Lerp(StartPoint, EndPoint, t) in FixedUpdate function.
Hey, thanks for the response. I'm aware the solution is likely overcomplicated, and my only real excuse is I'm also using it to learn some more about the different parts of the code itself.
The two points solution still isn't quite what I want. Looking online for similar examples I found the game "Door Kickers", where you can draw a line from a character and the character will follow along that path (seen in the opening 10 seconds of this trailer: https://www.youtube.com/watch?v=JLXIA8AP4Lg).
I'll keep testing around with it myself to see if I can come up with something, but I'll probably end up using that Lerp method, Thanks!
Here is some basic example. https://gofile.io/d/BN$$anonymous$$lUW Attachment for some reason does not work.
BTW For custom movement i would rather use Queue data structure than List