1

I have a simple little game that I'm working on just to get my feet wet in the designing process. I ran into a problem while trying to do collision detection for an item in a list. I have an enemy class that will spawn three enemies at a time and then those ships will each have the ability to fire three bullets at a time. Problem I'm getting is that my collision detection is tracking the ship and not each individual bullet even though the collision rect is getting the bullet position. In the shoot bullets method, I assign a Vector2 to copy the bullet position (pretty sure I have to do something with passing in the index, but I don't know where to begin with that). Any help/guidance would be much appreciated!

SpriteManager.cs

 for (int j = 0; j < enemies.Count; j++)
            {
                Enemies e = enemies[j];

                //Update Sprite
                e.Update(Game.GraphicsDevice, gameTime);

                //Check for Collision
                if (e.collisionRect.Intersects(player.collisionRect))
                {
                    lives -= 1;
                }
            }

Enemies.cs

public void ShootBullets()
    {
        Bullets newBullet = new Bullets(bulletTexture);
        newBullet.velocity.X = velocity.X - 3f;
        newBullet.position = new Vector2(position.X + newBullet.velocity.X, 
            position.Y + (texture.Height / 2) - (bulletTexture.Height / 2));

        //Test
        bulletPos = newBullet.position;

        newBullet.isVisible = true;
        if (bullets.Count() < 3)
            bullets.Add(newBullet);
    }

    public Rectangle collisionRect
    {
        get
        {
            return new Rectangle(
                (int)bulletPos.X + collisionOffset,
                (int)bulletPos.Y + collisionOffset,
                bulletTexture.Width - (collisionOffset * 2),
                bulletTexture.Height - (collisionOffset * 2));
        }
    }

Edit to add Bullets class:

    public class Bullets
    {
        // Variables
        public Texture2D texture;

        public Vector2 position;
        public Vector2 velocity;

        public bool isVisible;

        //public Rectangle boundingBox;
        //public Vector2 origin;
        //public float speed;

        // Methods

        // Constructor
        public Bullets(Texture2D newTexture)
        {
           // speed = 10;
            texture = newTexture;
            isVisible = false;
        }

        // Draw
        public void draw(SpriteBatch spritebatch)
        {
            spritebatch.Draw(texture, position, Color.White);
        }

    }
}
Paul2357
  • 39
  • 7

1 Answers1

2

Instead of just looping through the enemies, you also need to loop through each of the enemy's bullets.

Simplest modification to your code would look something like

 for (int j = 0; j < enemies.Count; j++)
            {
                Enemies e = enemies[j];

                //Update Sprite
                e.Update(Game.GraphicsDevice, gameTime);

                for (int u = 0; u < e.bullets.count; u++) {
                   Bullet b = e.bullets[u];
                   //Check for Collision
                   if (b.collisionRect.Intersects(player.collisionRect))
                   {
                       lives -= 1;
                   }
                }
            }

however, please be aware there are several things generally not recommended that you are doing here.

First of all, instead of each enemy having their own list of bullets, there should be one global list for all bullets, which each enemy adds to as they "fire" their bullets.

then you can only search through that one list, instead of looking up each enemy, then looking up again each bullet from that one enemy.

Secondly, instead of writing out custom for loops like you are

for (int j = 0; j < enemies.Count; j++) {
Enemies e = enemies[j];

consider simply doing

//same thing
foreach (var e in enemies) {

Also, please be sure when performing update logic on those bullets to delete any bullets that go out of bounds or hit other objects. There are lots of ways to optimize when objects can be destroyed and which objects you need to check for collision. Collision checks should generally be performed against as little objects as you can get away with, because they are one of the slower things you need to do in a game. Althoguh simple rectangle intersections are pretty fast, so maybe no need to worry about optimizing that part yet.

irreal
  • 2,019
  • 14
  • 20
  • 1
    A note about your comment regarding looping: From what I've seen, using a for loop is better than a foreach loop in terms of performance, and in this situation, performance is key. Source: http://stackoverflow.com/questions/365615/in-net-which-loop-runs-faster-for-or-foreach – Taegost May 06 '15 at 13:17
  • Optimizing to a for loop instead of a foreach on an array is one of the last things that will make a difference when coding a game. If you need THAT tidbit of speed to make your game not suffer with performance, you are doing something WAY more wrong elsewhere. A foreach is clearer and easier to maintain. As said, things like intesive drawing and calculations such as collision checking and physics are where you need to be careful. Bloating the code with counter variables only to load an instance from an array in the second line is really, really not necessary. – irreal May 06 '15 at 13:20
  • @irreal I see two problems given the modifications you made. One being that the list bullets is not public so it cannot be accessed outside of the class. I fixed this and made it public, not a big deal. The second thing was that bullets doesn't have a collision rect function and shoot bullets doesn't accept a parameter to go through each bullet. So it's just a little confusing. I see what you're saying though – Paul2357 May 06 '15 at 14:28
  • 1
    As said, consider not storing bullets at enemy level, but higher. For example, same where you store the enemies array. Secondly, a bullet will need it's own x and y position (or likely vector 2) as well as it's width and height, so it's easy to create a collision tectangle for it to use. You didn't show the bullet class at all, if you get stuck you can show me that class as well, I can help you make the changes. – irreal May 06 '15 at 14:39
  • @irreal Taegost is correct with regards to `foreach` vs `for`. `foreach` generally involves an enumerator object being created for each loop for each frame of your game. Generally you want to minimize memory allocation of temporary objects because it **will** lead to **noticeable random pauses** in your game during `garbage collection (GC)`, particularly on under-powered devices. It's **not** about _making the loop faster_; rather _minimizing GC_. One can generally control compute time; however one cannot predict when GC will occur. A good game allocates all memory at the start of a level – MickyD May 06 '15 at 16:19
  • @irreal added the bullets class. Really stuck on this. I see what you're saying, but the implementation has me stumped at the moment – Paul2357 Jun 01 '15 at 14:36
  • If you upload your entire project as it is right now, I'll be happy to have a look and help you out. Either add all the classes and code to the question or just upload it somewhere and msg me the link. – irreal Jun 01 '15 at 14:49