I am in the process of making a farming/tower defense game and I am very new at programming. I seem to have a major problem with using Lists<> or arrays in XNA. I cannot get it to return the index that I want from the list.
The main question is inside my planting engine. I have successfully implemented a planting system that can generate a list of plants (spriteobjects) with varying properties and place them on the map. Now, I need a way to access a specific plant in the plant list based upon mouseclicking on that plant. I feel like I am very close, but I ended up with a ArgumentOutOfRangeException that I cannot solve. Here is a walkthrough of the code:
Initialization
public void Addplants()
{
switch (Mode)
{
case "Wotalemon":
NewPlant = new Plant(Texture, msRect);
NewPlant.AddAnimation("seed", 0, 16, 64, 64, 1, 0.1f);
NewPlant.AddAnimation("sprout", 64, 16, 64, 64, 1, 0.1f);
NewPlant.AddAnimation("wota", 128, 16, 64, 64, 1, 1.0f);
NewPlant.CurrentAnimation = "seed";
NewPlant.DrawOffset = new Vector2(32, 48);
NewPlant.Position = Position;
NewPlant.Type = "wotalemon";
NewPlant.Birthday = Days;
NewPlant.IsSelected = false;
plants.Add(NewPlant);
thisPlant = NewPlant;
//various plants after this
Update/Draw
I use some simple foreach loops to update and draw the plants, no problems here.
GetInfo (this method uses the spriteobject's hitbox property and a mouseRectangle)
public void GetInfo(Rectangle ms)
{
msRect = ms;
for (int i = 0; i < plants.Count; i++)
{
foreach (Plant NewPlant in plants)
{
if (NewPlant.BoundingBox.Intersects(msRect))
{
SelectedIndex = i;
NewPlant.Tint = Color.Black;
}
else
NewPlant.Tint = Color.White;
}
}
}
finally, here is the problem:
public void SelectPlant()
{
//if (SelectedIndex != null)
if (SelectedIndex > plants.Count | SelectedIndex < 0)
SelectedIndex = plants.Count;
SelectedPlant = plants[SelectedIndex];
}
The exception is thrown in this line:
SelectedPlant = plants[SelectedIndex];
The debugger shows the value as 0. I have tried various methods to try to prevent the index from being null. I feel like something in the Getinfo() method is key here. I am convinced that I am very close to success because the color test that I have inserted in there works perfectly. When I mouseover a plant, it turns black, when I remove the mouse, it returns to normal.
This is EXACTLY the type of behavior I want except that I want it to set selectedIndex to the index of the plant that I am mousing over. Any advice would be greatly appreciated.
I'll add this as a new answer since this is tackling a whole different issue. Taking a look at this code:
msRect = ms;
for (int i = 0; i < plants.Count; i++)
{
foreach (Plant NewPlant in plants) // <-- this is redundant
{
if (NewPlant.BoundingBox.Intersects(msRect))
{
SelectedIndex = i;
NewPlant.Tint = Color.Black;
}
else
NewPlant.Tint = Color.White;
}
}
You are looping through 'plants' twice inside each other! Once using an index (for (int i = 0 ...
) and then inside that again using an iterator (foreach (Plant NewPlant ...
).
Your options are to either change GetInfo
to set the right index by using a single loop:
msRect = ms;
for (int i = 0; i < plants.Count; i++)
{
Plant NewPlant = plants[i];
if (NewPlant.BoundingBox.Intersects(msRect))
{
SelectedIndex = i;
NewPlant.Tint = Color.Black;
}
else
NewPlant.Tint = Color.White;
}
Or do the same thing and short circuit the need for SelectPlant() and SelectedIndex in the first place:
msRect = ms;
foreach (Plant NewPlant in plants) // no need for indexes
{
if (NewPlant.BoundingBox.Intersects(msRect))
{
SelectedPlant = NewPlant; // this is everything you need
NewPlant.Tint = Color.Black;
}
else
NewPlant.Tint = Color.White;
}
You do however need to be careful using a 'global' variable like SelectedPlant
to capture this logic. You're better off changing the whole GetInfo
method to return the selected plant, rather than having it modify SelectedPlant
directly. That is, change the method signature to return Plant
not void
, and change SelectPlant = NewPlant
in the code above to return NewPlant
. Or for even more fun as a single line:
return plants.Where(p => p.BoundingBox.Intersects(ms))