Yellowman94
Yellowman94

Reputation: 57

C# XNA Space Invaders Array

So this is my first ever XNA project, ie I'm a complete noob. I'm making a basic Space Invaders game, but I can't make heads nor tails of how to make a rectangular array for the invaders; the code I currently have just draws them in one long line I've looked at other answers but none seem to be working so far.

I have this initialized:

    InvaderArray = new Invader[5, 11];
    int XPos = 200;
    for (int rows = 0; rows < 5; rows++)
        for (int cols = 0; cols < 11; cols++)
        {
             InvaderArray[rows, cols] = new Invader();
             InvaderArray[rows, cols].SetXPos(XPos);
             InvaderArray[rows, cols].SetYPos(100);

             XPos = XPos + 50;
        }

And this in the Draw() method:

 for (int rows = 0; rows < 5; rows++)
     for (int cols = 0; cols < 11; cols++)
     {
         spriteBatch.Draw(Invader, InvaderArray[rows, cols].GetPos(), Color.White);
     }

I am using an 'Invader' class, if that helps:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace SpaceInvaders
{
    class Invader
   {
        Vector2 InvaderPos;

        public Invader()
        {
            InvaderPos = new Vector2();

            InvaderPos.X = 0;
            InvaderPos.Y = 0;
        }

        public void MoveHorizontal(int amount)
        {
            InvaderPos.X = InvaderPos.X + amount;
        }

        public void MoveVertical(int amount)
        {
            InvaderPos.Y = InvaderPos.Y + amount;
        }

        public void SetXPos(int pos)
        {
            InvaderPos.X = pos;
        }

        public int GetXPos()
        {
            return (int)InvaderPos.X;
        }

        public void SetYPos(int pos)
        {
            InvaderPos.Y = pos;
        }

        public int GetYPos()
        {
            return (int)InvaderPos.Y;
        }

        public Vector2 GetPos()
        {
            return InvaderPos;
        }
    }
}

Any help is really appreciated.

Upvotes: 0

Views: 510

Answers (2)

Doug Lampe
Doug Lampe

Reputation: 1466

Eric J already answered the specific bug with your code, but I would like to address why this problem happened in the first place. Basically you are trying to create a certain geometry inside of 2 loops and there are several ways to do this. There are several approaches to choose but you have to be careful to follow the same logic regardless of your approach. I will share some possible approaches. First I will use the approach you shared and add comments for some critical pieces you were missing:

int YPos = 100; // Set the initial Y position
for (int rows = 0; rows < 5; rows++)
{
    int XPos = 200; // Set the initial X position at the beginning of each row
    for (int cols = 0; cols < 11; cols++)
    {
         InvaderArray[rows, cols] = new Invader();
         InvaderArray[rows, cols].SetXPos(XPos);
         // Your code used 100 here so every invader had a Y position of 100:
         InvaderArray[rows, cols].SetYPos(YPos); 

         XPos = XPos + 50;
    }
    YPos = YPos + 50; // Increment the Y position after each row
}

In this example, you are looping across rows and columns and keeping a running position in terms of X and Y.

Another option that is a little more mathematically complex is to use an equation for the X and Y positions which is a little more concise but does require a little more computation due to the multiplication and addition:

for (int rows = 0; rows < 5; rows++)
{
    for (int cols = 0; cols < 11; cols++)
    {
         InvaderArray[rows, cols] = new Invader();
         InvaderArray[rows, cols].SetXPos(200 + 50 * cols);
         InvaderArray[rows, cols].SetYPos(100 + 50 * rows);
    }
}

One advantage here is that there are less "moving parts" since you don't have to have variables to store the X and Y positions, but you have to do the math and the processor also has to do the multiplication which is minor in this case but it does make a difference.

If you replace your 2-dimensional array of invaders with a generic list like this:

List<Invader> InvaderList = new List<Invader()

Your loops could be written like this:

for (int y = 100; y <= 300; y += 50)
{
    for (int X = 200; x <= 700; x += 50)
    {
        Invader invader = new Invader();
        InvaderList.Add(invader);
        invader.SetXPos(x);
        invader.SetYPos(y);
    }
}

Then in your draw method:

foreach (Invader invader in InvaderList)
{
    spriteBatch.Draw(invader, invader.GetPos(), Color.White);
}

This is nice and concise since it only uses 2 variables (x and y). You do have to do the math up front, but it is fairly obvious what you are doing. There is no extra computation or extra variables. An added bonus is that by using a generic list, your draw method is simplified as well. Also, if you wanted to have other arrangements of ships besides a rectangle, you could draw them with the same method since your draw method no longer cares how many rows or columns of ships you have - it will just draw each ship at its given position.

Upvotes: 1

Eric J.
Eric J.

Reputation: 150138

They are in a long line because this code

InvaderArray[rows, cols].SetYPos(100);

gives every single one of them the same Y position. Perhaps set it to something like

InvaderArray[rows, cols].SetYPos(100 + row * 50);

Also, you will want to reset XPos to its initial value of 200 after drawing each row.

for (int rows = 0; rows < 5; rows++)
{ 
    XPos = 200;
    for (int cols = 0; cols < 11; cols++)

Upvotes: 5

Related Questions