- Home /
Level alignment script crashing after a few iterations
Hi,
I'm working on a script which aligns sections of various shapes one after the other to create a level/path. The 5 sections are initially laid in the scene but 'out of the way' - we'll call this the Parking Lot (thanks Fattie for the idea ;) ) so they can be positioned into the level when required. These sections are held in a public Transform List called 'ParkLotSectionList' with indices (0 to 4)and dragged into their slots via the Inspector.
Each section has its pivot at one end (the start) and an empty object at the other (the end-point to which each section bolts onto).
The idea behind the script is to initially have 2 sections of the level sitting in the scene. A random number is passed to the script which selects an index of ParkLotSectionList (ie. a section) to add next. Now, in order to always have one of each section in the Parking Lot at all times, I have Instantiated one in its place at the same time. Therefore, I have created another List called 'PrefabSectionList' to hold each of the 5 section prefabs. So for example, if the random number is 1 (section2), then a section2 will be Instantiated on top of the one in the Parking Lot then section2 will be positioned at the end of the level. This all works fine and I can add sections one after the other correctly.
However, I am also trying to destroy the sections from the very start as each new one is added to the end. So, if we have section1 + section2 initially, then, if section3 is added to section2, I would like section1 to be destroyed, and so on. In order to achieve this, I created a List to keep track of which sections are currently in the level - called 'CurrentlyLaidSectionList'. This is public and initially made of size 2 in the Inspector to hold the first 2 sections in the scene (section1 and section2) which were dragged into the slots. The new section is added to 'CurrentlyLaidSectionList', then the first element is removed (the first section in level), and finally the section is removed (Destroyed) from the scene. Now, this seems to go as planned up to a point and usually around 4 iterations (sections added and destroyed), so the first thing that springs to mind is that one of the Lists is over-flowing somewhere, not sure where or which, though. :s
When this does go wrong, if looking at the List's contents in the Inspector, they show the following (sorry, not very specific) errors. The 'ParkLotSectionList' shows missing sections, usually starting with just one, then more as the iterations continue. The 'CurrentlyLaidSectionList' begins to have empty slots too. All of the missing slots vary each time.
Note, to control the rate at which the sections are added, I am using a key press - 'A', in Update().
The script is shown below;
Any help with this would be fantastic! Please ask any questions.
//---------------
public class SectionAssembler : MonoBehaviour
{
// Array of Strings used to keep track of whether a Section is used or not
// private List<string> SectionList = new List<string>();
// The array of sections in the Parking Lot
public List<Transform> ParkLotSectionList = new List<Transform>();
// List of the prefabs of the sections to use in case one does not exist in the scene
public List<Transform> PrefabSectionList = new List<Transform>();
// The currently laid sections in the scene - not the parking lot sections
public List<Transform> CurrentlyLaidSectionList = new List<Transform>();
// The positions of the sections in the parking lot - should not change
private List<Transform> ParkLotParkingSpotList = new List<Transform>();
// The End-point of the first section in the scene that we will add onto
// Added in Inspector
public Transform StartingSectionEndpoint;
// Used to select which section to add to position in the scene next
// This is a random number passed in from the LevelAlign script
// private int SectionSelected;
// Obj ref to the Track Assembler empty object containing LevelAlign script
private GameObject TrackAssemObj;
// Used to keep track of the End-point to add to
private Transform endPointMarker;
// Flag used to only call something once
private bool firstSection = true;
void Start()
{
// Find Track Assembler object
TrackAssemObj = GameObject.Find("Track Assembler");
ParkLotParkingSpotList = ParkLotSectionList;
}
void Update()
{
if (Input.GetKeyDown("a"))
{
// Get the random number between 0 and 4
int RandIndex = GetComponent<RandomNumberGen>().RandomNum;
Debug.Log("RandIndex = " + RandIndex);
// Debug.Log("Section 1 Endpoint = " + EndP.position);
Transform newSection = Instantiate(PrefabSectionList[RandIndex], ParkLotParkingSpotList[RandIndex].position, ParkLotParkingSpotList[RandIndex].rotation) as Transform;
AlignSections(RandIndex);
}
}
//-----------------------------------------------------
// Used to receive the random number as the SectionIndex - ie. to select
// which section to use next
void AlignSections(int ChosenIndex)
{
// Set nextTrans to reference the chosend section
Transform nextTrans = ParkLotSectionList[ChosenIndex];
// If nextTrans does not yet have a value - ie this is the first section we are adding,
// then assign it the StartingSectionEndpoint values.
if (firstSection)
{
// Set the position of nextTrans to the same as the section's End-point
nextTrans.position = StartingSectionEndpoint.position;
// Set the rotation of nextTrans to the same as the section's End-point
nextTrans.rotation = StartingSectionEndpoint.rotation;
// Add the new section to the end of the CurrentlyLaidSectionList List
CurrentlyLaidSectionList.Add(nextTrans);
// Pass the current section to the setLastEndpoint method to keep track of the endpoint
setLastEndpoint(ChosenIndex);
// Set the flag to false as the following sections will not be the first
firstSection = false;
}
// Otherwise, assign it the End-point values for the following sections
else
{
// Call the getLastEndpoint method which returns the End-point of the last Section/Transform
// Get its position and set to nextTrans
nextTrans.position = getLastEndpoint().position;
// Get its rotation and set to nextTrans
nextTrans.rotation = getLastEndpoint().rotation;
// Add the new Section to the end of the CurrentlyLaidSectionList List
CurrentlyLaidSectionList.Add(nextTrans);
// Pass the current section to the setLastEndpoint method to keep track of the endpoint
setLastEndpoint(ChosenIndex);
Debug.Log("CurrentlyLaidSectionList[0] = " + CurrentlyLaidSectionList[0]);
// Remove section at back from the scene
Destroy(CurrentlyLaidSectionList[0].gameObject);
// Remove the first element in the list (first section in level)
CurrentlyLaidSectionList.RemoveAt(0);
}
}
//-----------------------------------------------------
// Keeps track of the last section to be added.
// Finds its end-point and assigns it to endPointMarker
void setLastEndpoint(int sectionIndex)
{
endPointMarker = ParkLotSectionList[sectionIndex].GetComponent<EndpointFinder>().EndPoint;
}
//-----------------------------------------------------
// Returns the End-Point of the last section to be added
Transform getLastEndpoint()
{
return endPointMarker;
}
}
Hi,
The crash is in the editor, Working on Windows (Windows and $$anonymous$$ac standalone) No hanging, freezing / beach ball
The crash in the console is: $$anonymous$$issingReferenceException: The object of type 'Transform' has been destroyed but you are still trying to access it. Your script should either check if it is null or you should not destroy the object. UnityEngine.Transform.get_position ()
Will do some checking for null now :)
Thanks
Answer by whydoidoit · Jun 20, 2012 at 07:44 PM
You aren't creating a copy of the prefab - so they are just getting destroyed. Unity overrides a bunch of operators to return null when the object is destroyed (you can tell because in the debugger it appears as (null) ).
I'd suggest this:
//-----------------------------------------------------
// Used to receive the random number as the SectionIndex - ie. to select
// which section to use next
void AlignSections(int ChosenIndex)
{
// Set nextTrans to reference the chosend section
Transform nextTrans = Instantiate(ParkLotSectionList[ChosenIndex]) as Transform;
Hi $$anonymous$$ike,
Well, changed the line you mentioned and no more crashes, so that's good :)
However, what it does now is add the first section onto the initial 2 as planned, but then it begins adding them to the sections in the Parking lot. Not one after the other, but after one of them then the next will be after another, which is beside it :s
So Ok - well what is happening with the transform you create from the prefab list? It doesn't appear to be added to any of the other lists...
Ah, I think you may have spotted a problem..
The line in Update();
Transform newSection = Instantiate(PrefabSectionList[RandIndex], ParkLotParkingSpotList[RandIndex].position, ParkLotParkingSpotList[RandIndex].rotation) as Transform;
makes a copy of the section and places it in the same location as the original in the Parking Lot - So that there is always one available in the scene to position. I guess this would have to be added to the ParkLotParkingSpotList List ?
That would be my guess yes - you aren't tracking it in one of your lists - that might be the thing you want to do ins$$anonymous$$d of my answer - I can't quite get my head around it. It feels like you don't have to do that bit actually - ugh, your code is well laid out, I'm just having a bad thinking day ;)
Answer by forestj · Jun 20, 2012 at 07:37 PM
Is this a crash in the editor, or in the built player? On what platform is it crashing? Is it an infinite hang (beach ball)? Does it generate an error log (check the console)?
Perhaps you need to check for null in some place where you are iterating through your list. Maybe you need to manually Remove items from the list before you destroy them.
Your answer
Follow this Question
Related Questions
A node in a childnode? 1 Answer
List problem? 2 Answers
How to return index of List element? 1 Answer
Query with C# arrays and List<> 2 Answers
Spawn an object every time i=+5 1 Answer