Jump to content
  • Advertisement
ethancodes

C# assigning a property from an object in a list to a variable

Recommended Posts

1 hour ago, Scouting Ninja said:

You have to use Add and Remove to keep it dynamic.

 

Aaaahhhh...soooo using the Clear method like this: 

gridOptions.Clear();

is not going to shrink the list, just make that element null? I hadn't realized that. That still doesn't explain why it has 4 element even before it is ever populated, but I bet when I go back through the code I'll find something that it's picking up to determine the length of the List and I didn't even realize it. I'll check it tonight when I get home. Thanks to everybody for all the help on this. I really appreciate it!

Share this post


Link to post
Share on other sites
Advertisement

So I'm still having issues. I keep randomly getting this out of range exception:

ArgumentOutOfRangeException: Argument is out of range.
Parameter name: index
System.Collections.Generic.List`1[GridSquare].get_Item (Int32 index) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Collections.Generic/List.cs:633)
BoardManager.CheckBorders (Int32 currentPosition) (at Assets/Scripts/BoardManager.cs:117)
BoardManager.RandomPosition () (at Assets/Scripts/BoardManager.cs:85)
BoardManager.LayoutObjectAtRandom (UnityEngine.GameObject brick, Int32 brickCount) (at Assets/Scripts/BoardManager.cs:152)
BoardManager.SetupScene (Int32 level) (at Assets/Scripts/BoardManager.cs:169)
GameManager.InitGame () (at Assets/Scripts/GameManager.cs:27)
GameManager.Awake () (at Assets/Scripts/GameManager.cs:22)
UnityEngine.Object:Instantiate(GameObject)
LevelManager:Awake() (at Assets/Scripts/LevelManager.cs:23)

 

I'm not sure what exactly is causing this. Here is all of the code in this class with the exception of what I use to initialize the bricks simply because I know that needs some cleaning up and reworking, but I haven't done it yet.. I have gone through and added better comments so hopefully what I'm doing makes more sense. I'm still very confused as to why my gridOptions list is giving itself 4 elements before it even checks to see if it wants to put something there. 

 


		private int columns = 20;                //Number of columns in our game board.
		private int rows = 30;  				//Number of rows in our game board.
		private int currentPositionId;			//holds the Id of the current position
		private int index = 0;					//index of gridPositions as we loop through, used to set Id to each GridSquare

		public int brickCount;               //Number of bricks to spawn.


		//Define brick types to assign sprites to in editor
		public GameObject oneHitBrick;                                
		public GameObject twoHitBrick;                                  
		public GameObject threeHitBrick;                                 
		public GameObject explodingBarrel;  //temporarily represented by the unbreakable brick
		                         
		private Transform boardHolder;     //A variable to store a reference to the transform of our Board object.
		private int randomIndex;			//select index to place next brick
		private Vector3 randomPosition;		//Position at the randomIndex
		private List <GridSquare> gridPositions = new List <GridSquare> ();   //list of positions on game board
		private List<GridSquare> gridOptions = new List<GridSquare>(); //list of options to place next brick


		//Clears our list gridPositions and prepares it to generate a new board.
		void InitialiseList ()
		{
			//Clear our list gridPositions.
			gridPositions.Clear ();

			//Loop through x axis (columns).
			for(int x = 1; x < columns-1; x++)
			{
				//Within each column, loop through y axis (rows).
				//start at 18 to spawn our bricks offscreen
				for(int y = 18; y < rows-1; y++)
				{
					bool occupied = false;
					//At each index add a new Vector3 to our list with the x and y coordinates of that position.
					//index is the Id of GridSquare to allow for matching with gridOptions list later
					gridPositions.Add (new GridSquare(new Vector3(x,y,0), occupied, index));

					index++;
				}
			}
		}
	
		//RandomPosition returns a random position from our gridPositions or gridOptions list.
		Vector3 RandomPosition ()
		{
			if (gridPositions.All(c => c.IsOccupied == false)) //check if all gridPositions are unoccupied
			{
				//set randomIndex value to a random number between 0 and the count of items in our List gridPositions.
			    randomIndex = Random.Range (1, gridPositions.Count);

				//set randomPosition to the element at randomIndex in gridPOsitions list
				randomPosition = gridPositions [randomIndex].GridPosition;

				//ensures the GridSquare will not be re-used 
				gridPositions[randomIndex].IsOccupied = true;

				//sets the currentPositionId to the current GridSquare based on Id
				currentPositionId = gridPositions[randomIndex].Id;

				//Return the randomly selected Vector3 position.
				return randomPosition;
			} 
				//call CheckBorders to populate list gridOptions
				CheckBorders(currentPositionId);

				//set randomIndex value to a random number between 0 and the count of items in our List gridOptions.
				randomIndex = Random.Range (0, gridOptions.Count);

				//set randomPosition value to the entry at randomIndex from our List gridOptions.
				randomPosition = gridOptions [randomIndex].GridPosition;

				//make sure the chosen GridSquare can't be re-used
				gridOptions[randomIndex].IsOccupied = true;

				//set currentPositionid to the current GridSquare by Id.
				currentPositionId = gridOptions[randomIndex].Id;

				//Return the randomly selected Vector3 position.
				return randomPosition;	
			

		}
		//check borders is used to check above, below, left, and right of the current GridSquare to see if those options are available for next brick, and then each
		//available option is added to list gridOptions
		void CheckBorders (int currentPosition)
		{
			int count = 0; //used to track gridOptions element

			gridOptions.Clear (); //empty gridOptions list

			if (gridPositions [currentPosition].GridPosition.x != 1) { //check to make sure we are not on column 1, if not, check 1 column to 																			//the left. If available, set to gridOptions list
				if (gridPositions [currentPosition - 11].IsOccupied == false) {
					gridOptions.Add (gridPositions [currentPosition - 11]);     //As soon as this line executes, my gridOptions lists shows this
				}															//this being populated, and then 3 null elements following it.
            }																//the nulls get populated accordingly as long as they are viable 																				//positions

			if (gridPositions [currentPosition].GridPosition.x != 20) { //check to make sure we are not on column 20, if not, check 1 column to the right. If available, set to gridOptions list
				if (gridPositions [currentPosition + 11].IsOccupied == false) {
					gridOptions.Add (gridPositions [currentPosition + 11]);
				}
			}

			if (gridPositions [currentPosition].GridPosition.y != 18) { //check to make sure we are not on row 18, if not, check 1 row under. If available, set to gridOptions list
				if (gridPositions [currentPosition - 1].IsOccupied == false) {
					gridOptions.Add (gridPositions [currentPosition - 1]);
				}
			}

			if (gridPositions [currentPosition].GridPosition.y != 30) { //check to make sure we are not on row 30, if not, check 1 row up. If available, set to gridOptions list
				if (gridPositions [currentPosition + 1].IsOccupied == false) {
					gridOptions.Add (gridPositions [currentPosition + 1]);
				}
			}

			//After checking all 4 locations, remove any null elements.
			foreach (GridSquare square in gridOptions) { 
				if (gridOptions [count] == null) {
					gridOptions.Remove (square);
				}
					count++;		
			}
		}

 

I'm really hoping someone can explain what I'm doing wrong here. I'm open to any suggestions as to what I can do to get this working or what's causing the out of range exception. Or why the gridOptions.Remove is not working, etc. Thanks.

Share this post


Link to post
Share on other sites
Posted (edited)

The error says you are trying to find a index that is out of the grid. The point you are trying to find isn't in the list. This should happen when your point is near the border if the grids.

IndexError.jpg.8364d781a909fe1dd2824e77448965b1.jpg

21 hours ago, ethancodes said:

I'm still very confused as to why my gridOptions list is giving itself 4 elements before it even checks to see if it wants to put something there. 

Looks like the CheckBoarders code will add null objects when it fails. Can't really tell without testing it.

 

After seeing your code I understand why you are having so much problems. It would be easier to use a multidimensional system, instead of a one dimension list.

Think of a vector2, it has a X and a Y axis. Keeping track of each dimension is easy and finding any point is done by checking each axis on its own. So no need for so many IF statements to find the borders. I will make a example to show how it works.

 

Edited by Scouting Ninja

Share this post


Link to post
Share on other sites

I had considered using a multidimensional array, but I had some doubts whether it would work how I need it to. I'm reworking all of this code now to see if I can get a multidimensional array to work for me, but if you want to write some stuff out to help me better understand that would be a huge help. I'm definitely getting pretty confused here. 

Share this post


Link to post
Share on other sites
8 hours ago, ethancodes said:

but if you want to write some stuff out to help me better understand that would be a huge help.

I had more time than expected, as I am fixing and formating my PC, and ended up creating the complete grid:

SN2DGrid.zip

Import into your Unity, a empty new project, as a custom pack and run the test scene. It will look invisible but once you start it will look like this:

GridExampleLook.thumb.jpg.befd90ef627e10b08f3bc8d0600e69e5.jpg

This is a 20 By 20 (400 cells) grid, it will start with a 9 By 9 grid (81) grid and you can adjust it. You can also adjust how many rocks there is.

Note: I use Unity GameObject and a Mono script for this, instead of my own class, because I wanted a easy way to find what block I click on. If you use your own class you will need to ray trace or use another way to find a exact point.

Features:

Randomly finds a point at start, never selecting a point with a rock on it. Color coded. Left_Click selects the point where your mouse is. Right_Click selects a new random point. Can select points near the edge. I made a lot of comments explaining things.

Tell me if it doesn't work or if there is a problem, or if you want a step by step explanation of how something works.

Share this post


Link to post
Share on other sites

I didn't have much time to look into this tonight, but I did glance through the scene and code real quick. It's not exactly what I need, but I think it'll definitely be a huge help. I'll be back on this tomorrow evening so hopefully I'll be able to figure it all out then.

Share this post


Link to post
Share on other sites
9 hours ago, ethancodes said:

It's not exactly what I need

Was expecting this because all we did was re-created what was already there. A vector2 and vector3 is a grid and if we want to see if there is an object at a point we can do a ray trace or check the Unity object list to see what points at this grid is occupied.

In other words this system just adds a engine on top of the engine.

Share this post


Link to post
Share on other sites

Hi, ethancodes! Any luck figuring out your ArgumentOutOfRangeException? If not, I think I see what's going on.

Inside of InitializeList, when you're creating your GridSquares the maximum X value is 18 and the maximum Y value is 28.

So, your grid looks something like this.

Grid.PNG.8bec27208537f864793bcf524f46648b.PNG

In orange across the top are the "y" coordinates and across the side are the "x" coordinates. Inside each box is the index into "gridPositions", or your Id.

Inside of "CheckBoarders", you're doing the following check to ensure you're not on the final row:

if (gridPositions [currentPosition].GridPosition.x != 20)

However, since the maximum value for "x" is 18, this condition always evaluates to true. Even when you're on the last row! So, if we were to pick an Id from the last row in the grid, lets say 187, and step through that code then your check would evaluate to true. 

if (gridPositions [currentPosition/*187*/].GridPosition.x /*x == 18*/ != 20)
{
    if (gridPositions [currentPosition + 11 /*187 + 11 = 198. This is outside the bounds of gridPositions, and is throwing the exception*/].IsOccupied == false)
}

As for why gridOptions is initializing to four elements, I don't see anything that would be causing that. What are you doing to see those nulls?

I'm going to speculate here, and if I'm wrong I apologize. I *suspect* that what you're doing is looking at "gridOptions" through the debugger. Either through a watch, or the Locals window, or perhaps just hovering over "gridOptions" with your mouse. Then, you're drilling down until you see the private "_items" field and drilling down into that. If so, here is what is going on...

List<T> stores the items you add to it internally via a fixed sized array. When you add an item to an empty List<T>, it resizes the internal array to have a length of four. This is why you're seeing four items, three of which are nulls, in _items after the first item gets added (if that is indeed what you're seeing).

If you're curious why it doesn't just resize the internal array to fit exactly the number of items you're adding it's because that resize is an expensive operation. Essentially, it has to allocate a new array then copy the old array into the new one. This isn't something you want to happen every single time you add an item to the list. Incidentally, every time List<T> gets an item that exceeds its capacity, the size of the internal array doubles. If you were to add five GridSquares to "gridOptions" and look at "_items" you would see eight items. Add 9 GridSquares to "gridOptions" and look at "_items" and you would see 16 items.

This might also explain why your "Remove" isn't working... you don't actually have any nulls in "gridOptions".

Share this post


Link to post
Share on other sites

@Joshua Robinson this explains a lot actually. Now I am faced with the decision of changing my code back to using the List like I was here, or just getting it to work with the multidimensional array as I have it now. I'm pretty close with the multidimensional array, but I'm once again getting an out of range exception. Only this time, it's not even spawning bricks. The exception seems to be happening when setting up the grid. Suggestions on which to use? I personally liked using the list a lot better only because it was much easier to read for me. But if there will be a large difference in performance with using a multidimensional array, then I'll keep that. Keeping in mind that the new model also uses a List. So basically, two lists, or one multidimensional array and one list are the two options.

 

Share this post


Link to post
Share on other sites
12 hours ago, ethancodes said:

I personally liked using the list a lot better only because it was much easier to read for me.

Just pointing out that you can use multidimensional lists. Remember that a list is an array, it just has extra code attached to make it dynamic but the way this works is that the array is copied and so it does have impact on performance.

I am curious, are you trying to make marching cubes? If you explained what you want it would be easier to help you.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!