0
\$\begingroup\$

Alright, please don't scald me here haha. I'm very new to XNA, C#, and game development as a whole. I have done web-design, but that is my main experience with programming. It is a Space Invaders type-ish game.

In the code below I have a Meteor class. In this class I want to create a meteor in a random location (on the X-axis) and then have it fall. I don't care much about it doing damage - yet.

I can always get one meteor created, and falling, yet when I press 'M' to create another instance of the class it isn't creating another meteor. I could very possibly be going about this entirely wrong...please forgive me if I am.

  class Meteor
   {


    private Random randomNumber = new Random();
    private Rectangle position;
    private int fallSpeed;
    private double damage;
    private int x, y = 0;
    private int WIDTH, HEIGHT;

    // List to hold meteors created (holds instance of Meteor class)
    List<Meteor> meteors = new List<Meteor>();

    // Texture for the meteor

    private Texture2D meteor;

    /// <summary>
    /// Create the meteor and each meteor's properties
    /// </summary>
    public Meteor()
    {
        HEIGHT = randomNumber.Next(0, 60);
        WIDTH = HEIGHT;
        fallSpeed = randomNumber.Next(0, 10);
        damage = fallSpeed * 2;
        x = randomNumber.Next(0, 600); // Randomly generates where meteor will spawn on X axis                    
    }

    public void createMeteor()
    {
        meteors.Add(new Meteor());
    }

    /// <summary>
    /// Load content (graphics) relating to the meteor
    /// </summary>
    public void LoadContent(ContentManager Content)
    {
        // Load meteor texture
        meteor = Content.Load<Texture2D>("Sprites/meteor");
    }

    /// <summary>
    /// Update the meteors position
    /// </summary>
    public void Update()
    {
        //Update position of metoer (falling)
        y++;

        // Testing purposes mostly...I want meteors to be created when I press 'M'
        if (Keyboard.GetState().IsKeyDown(Keys.M))
        {
            createMeteor();
        }
    }

    /// <summary>
    /// Draw the metoer (and it's new position).
    /// </summary>
    public void Draw(SpriteBatch spriteBatch)
    {
        position = new Rectangle(x, y, HEIGHT, WIDTH);
        spriteBatch.Draw(meteor, position, Color.White);

    }

    // So I can get the damage
    public double getDamage() { return damage; }
}
}
\$\endgroup\$
6
  • \$\begingroup\$ Post the meteor class. \$\endgroup\$
    – Ben
    Nov 5, 2014 at 2:51
  • \$\begingroup\$ The above code is the meteor class. \$\endgroup\$ Nov 5, 2014 at 2:52
  • 1
    \$\begingroup\$ Then you do not want the list of meteors inside the meteor class, you want it outside. CreateMeteor would also need to be in another class. \$\endgroup\$
    – Ben
    Nov 5, 2014 at 2:53
  • \$\begingroup\$ Oh ok. I'll try that then. \$\endgroup\$ Nov 5, 2014 at 2:58
  • 1
    \$\begingroup\$ Right now you're saying that each meteor contains a list of meteors. Which isn't right. You want one meteor to contain information for one meteor, then you make a list of meteors in another class. \$\endgroup\$
    – Ben
    Nov 5, 2014 at 3:01

2 Answers 2

3
\$\begingroup\$

You seem to be confused with some OO aspects here. When you have a class such as:

class Meteor
{
}

You are describing a template for every meteor you are going to create. This will describe what a SINGLE meteor should contain. So, following that, what attributes should EACH meteor have?

class Meteor
{
    Texture2D texture;
    Rectangle bounds;
    int       fallSpeed;
    double    damage;
    // x, y, WIDTH, HEIGHT are not needed here. That information can be obtained through the 'bounds' rectangle we have declared.
    // List of meteor is not needed. Why would each meteor contain a list of meteors?
}

So, that describes what each meteor would need. We need a reference to a texture2D in order to draw each, we need a bounds to describe the rectangle that the meteor lies within, for collision and position. We have a damage for each( bigger meteors might have bigger damage. ). That's it. x, y, width, and height would be a waste of memory here, because we know those things from the bounds rectangle.

So, what does each meteor do? It can be drawn, it can be updated, and it can be constructed:

class Meteor
{
    Texture2D texture;
    Rectangle bounds;
    int       fallSpeed;
    double    damage;


    public Meteor( Rectangle meteorBounds, int meteorFallSpeed, double meteorDamage,
                   Texture2D meteorTexture )
    {
        // We want to pass the bounds in as a parameter. This means, any one constructing
        // a meteor will be able to tell us how big they want it to be.
        bounds = meteorBounds;

        // Same again, we want different meteors to have different fall speeds, so let
        // that be descided by the owner of the object.
        fallSpeed = meteorFallSpeed;

        // Once again, decide the damage based on values that are passed in to us.
        damage = meteorDamage;

        // Pass in a reference. We do NOT want each meteor to allocate their own texture.
        // We would run out of vram pretty quickly. When the level is loaded, or the game
        // is started we load the texture. Then we pass it around to each meteor. This
        // way, each meteor knows where the texture is, it doesn't have it's own copy.
        texture = meteorTexture;
    }



    public void Update()
    {
        // Move the meteor down by the fall speed given to us in the constructor.
        bounds.y += ( int )fallSpeed;

        // No check for 'm' here. Why would a meteor create another meteor when 'm' is 
        // pressed?
    }



    public void Draw( SpriteBatch spriteBatch )
    {
        // Just draw the texture we have at the rectangle x and y.
        spriteBatch.Draw( texture, new Vector2( bounds.x, bounds.y ), Color.White );
    }
}

There we go. Our meteor should be fully functional. It can be constructed( with any height, speed, damage, and texture ), it can be updated( moves downwards at it's falling speed ), and it can be drawn at it's current location.

So, how do we get a bunch of them on screen now? Well, let's go back to the Game1 class. Here we want to do a few things; load our meteor texture, make our random object, make a list of meteors, make it so we can add one when the 'm' key is pressed:

 public class Game1 : Microsoft.Xna.Framework.Game
 {
     GraphicsDeviceManager graphics;
     SpriteBatch spriteBatch;
     GraphicsDevice device;

     // Here we want our random class, so we can generate random positions for our meteors
     // just like the original code did.
     Random random = new Random();

     // Here we make the texture that will be loaded from a file somewhere. This will be
     // the only one that is loaded. All others will just be a reference to this one.
     Texture2D meteorTexture;

     // This is our list of meteors in our game.
     List<Meteor> meteors = new List<Meteor>();


     private void CreateMeteor()
     {
          int     size = random.Next( 0, 60 );
          int     fallSpeed = random.Next( 0, 10 );

          // We add a new meteor to the list. We give it a random size, randome fallSpeed,
          // and a damage based off the fall speed. The meteor texture we have already
          // loaded is passed in.
          meteors.Add( new Meteor( new Rectangle( Random.next( 0, 600 ), 0, size, size ), 
                       fallSpeed, fallSpeed * 2, meteorTexture ) );
     }

     public Game1()
     {
         graphics = new GraphicsDeviceManager(this);
         Content.RootDirectory = "Content";
     }

     protected override void Initialize()
     {

         base.Initialize();
     }

     protected override void LoadContent()
     {
         spriteBatch = new SpriteBatch(GraphicsDevice);

         device = graphics.GraphicsDevice;

         // Load our meteor texture. This is the only place in the game this should be 
         // done.
         meteorTexture = Content.Load<Texture2D>("Sprites/meteor");
     }

     protected override void UnloadContent()
     {
     }

     protected override void Update(GameTime gameTime)
     {
         if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
             this.Exit();

         if (Keyboard.GetState().IsKeyDown(Keys.M))
         {
             // If 'm' is down, we create a new meteor. Note that once this is working
             // this is going to make a lot of meteors. That's another issue, though.
             createMeteor();
         }

         // Here's something that was missing in the original code. It's not enough to 
         // update one meteor, we must update each of them.
         foreach( Meteor meteor in meteors )
         {
              meteor.Update();
         }

         base.Update(gameTime);
     }

     protected override void Draw(GameTime gameTime)
     {
         device.Clear(Color.CornflowerBlue);


         // Only call begin and end once. You never want to call this for every object you
         // have.
         spriteBatch.Begin();
         // Once again we want to draw EACH meteor.
         foreach( Meteor meteor in meteors )
         {
              // Draw every single meteor, and pass in spriteBatch.
              meteor.Draw( spriteBatch );
         }
         spriteBatch.End();


         base.Draw(gameTime);
     }
 }

Here in our Game1 class, we maintain a list of meteors. Every frame we update them ALL by looping through them. We do the same with drawing. When we construct, we pass in information that should vary between meteors.

\$\endgroup\$
1
  • \$\begingroup\$ Oh wow. This clears so much up! Thank you so much for your answer and the time you put into it. \$\endgroup\$ Nov 5, 2014 at 3:51
0
\$\begingroup\$

Welcome to the GameDev StackExchange.

For starters, as per the comments on your question, move the List of meteors out of the Meteor class, and into your base game class (by default Game1.cs) along with the createMeteor() function/

Then in Game1, modify the Update method to loop over the list of Meteors, and call update on them. Do the same for Game1.Draw

The next update is to move the meteor creation code from the Meteor's update into Game1's update method, either above or below the loop.

Next, shift the meteors LoadContent texture load call to Game1's LoadContent along with its corresponding variable. After that modify the Meteor's constructor to take a Texture2D object and store it, and use it in the draw.

In case you have having trouble following this description, I have provided a summary of the changes to help you see.

Game1.cs

List<Meteor> meteors = new List<Meteor>();

Texture2D meteorTexture;

...

public override void LoadContent()
{
    // Load meteor texture
    meteorTexture = Content.Load<Texture2D>("Sprites/meteor");

    ...
    // rest of LoadContent 
}

public override void Update(GameTime gameTime)
{
    foreach (Meteor m in meteors)
        m.Update();

    // Testing purposes mostly...I want meteors to be created when I press 'M'
    if (Keyboard.GetState().IsKeyDown(Keys.M))
    {
        createMeteor(meteorTexture);
    }

    ...
    // rest of Update 
}

public override void Draw(GameTime gameTime)
{
    foreach (Meteor m in meteors)
        m.Draw(spriteBatch);

    ...
    // rest of Draw 
}

Meteor.cs

/// <summary>
/// Create the meteor and each meteor's properties
/// </summary>
public Meteor(Texture2D meteorTexture)
{
    // set texture here
    meteor = meteorTexture;

    ...
    // rest of constructor                  
}

/// createMeteors() and LoadContent() used to live here
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .