views:

713

answers:

4

I am using XNA for a 2D project. I have a problem and I don't know which way to solve it. I have a texture (an image) that is drawn to the screen for example:

|+++|+++|
|---|---|
|+++|+++|

Now I want to be able to destroy part of that structure/image so that it looks like:

|+++|
|---|---|
|+++|+++|

so that collision now will work as well for the new image.

Which way would be better to solve this problem:

  1. Swap the whole texture with another texture, that is transparent in the places where it is destroyed.
  2. Use some trickery with spriteBatch.Draw(sourceRectangle, destinationRectangle) to get the desired rectangles drawn, and also do collision checking with this somehow.
  3. Split the texture into 4 smaller textures each of which will be responsible for it's own drawing/collision detection.
  4. Use some other smart-ass way I don't know about.

Any help would be appreciated. Let me know if you need more clarification/examples.

EDIT: To clarify I'll provide an example of usage for this. Imagine a 4x4 piece of wall that when shot at, a little 1x1 part of it is destroyed.

A: 

Check out this article at Ziggyware. It is about Deformable Terrain, and might be what you are looking for. Essentially, the technique involves settings the pixels you want to hide to transparent.

Joe
It's interesting and seems like something I can use, but I can't figure it out, as it is a bit complicated. I am not sure how he is accomplishing the effect.
drozzy
In a nutshell he is using per-pixel collision to find what pixels are overlapping. He then sets those pixels to transparent giving the feeling that the ground was deformed. Keep in mind that this can be an expensive operation.
Joe
Thanks, but that's a bit too complicated for my needs.
drozzy
+1  A: 

I'll take the third option:

3 - Split the texture into 4 smaller textures each of which will be responsible for it's own drawing/collision detection.

It's not hard do to. Basically it's just the same of TileSet struct. However, you'll need to change your code to fit this approach. Read a little about Tiles on: http://www-cs-students.stanford.edu/~amitp/gameprog.html#tiles Many sites and book said about Tiles and how to use it to build game worlds. But you can use this logic to everything which the whole is compost from little parts.

Let me quick note the other options:

1 - Swap the whole texture with another texture, that is transparent in the places where it is destroyed.

No.. have a different image to every different position is bad. If you need to change de texture? Will you remake every image again?

2- Use some trickery with spriteBatch.Draw(sourceRectangle, destinationRectangle) to get the desired rectangles drawn, and also do collision checking with this somehow.

Unfortunately it's don't work because spriteBatch.Draw only works with Rectangles :(

4 Use some other smart-ass way I don't know about.

I can't imagine any magic to this. Maybe, you can use another image to make masks. But it's extremely processing-expensive.

Gustavo Cardoso
A: 

Option #3 will work.

A more robust system (if you don't want to be limited to boxes) would use per-pixel collision detection. The process basically works as follows:

  1. Calculate a bounding box (or circle) for each object
  2. Check to see if two objects overlap
  3. For each overlap, blit the sprites onto a hidden surface, comparing pixel values as you go. If a pixel is already set when you try to draw the pixel from the second sprite, you have a collision.

Here's a good XNA example (another Ziggyware article, actually): 2D Per Pixel Collision Detection

Some more links:

Can someone explain per-pixel collision detection

XNA 2-d per-pixel collision

Steven Richards
Thanks, but as Joe's solution this is more then I require at the moment.
drozzy
A: 

I ended up choosing option 3. Basically I have a Tile class that contains a texture and dimention. Dimention n means that there are n*n subtiles within that tile. I also have an array that keeps track of which tiles are destroyed or not. My class looks like this in pseudo code:

 class Tile
     texture
     dimention
     int [,] subtiles; //0 or 1 for each subtile

     public Tile() // constructor
         subtiles = new int[dimention, dimention];
         intialize_subtiles_to(1);

     public Draw() // this is how we know which one to draw
        //iterate over subtiles
        for(int i..
          for(int j ...)
             if(subtiles[i,j] == 1)
                Vector2 draw_pos = Vector2(i*tilewidth,
                                      j*tileheight)                       
                spritebatch.Draw(texture, draw_pos)

In a similar fashion I have a collision method that will check for collision:

   public bool collides(Rectangle rect)
       //iterate over subtiles 
       for i...
          for j..
              if(subtiles[i,j]==0) continue;

              subtile_rect = //figure out the rect for this subtile
              if(subtile_rect.intersects(rect))
                   return true;

       return false;

And so on. You can imagine how to "destroy" certain subtiles by setting their respective value to 0, and how to check if the whole tile is destroyed. Granted with this technique, the subtiles will all have the same texture. So far I can't think of a simpler solution.

drozzy