Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Getting boundaries of non-rectangular sprite?  (Read 9095 times)

0 Members and 2 Guests are viewing this topic.

wh1t3crayon

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
Getting boundaries of non-rectangular sprite?
« on: September 16, 2014, 04:49:46 pm »
Say I have a sprite that's not a rectangle, like a "squiggly" Tetris piece for instance. How do I get the exact boundaries of that sprite, and not just a rectangle shaped boundary of its widest points?

Jesper Juhl

  • Hero Member
  • *****
  • Posts: 1405
    • View Profile
    • Email
Re: Getting boundaries of non-rectangular sprite?
« Reply #1 on: September 16, 2014, 04:57:34 pm »
Either you pre-calculate that data upfront and store it somewhere alongside your image data (what I'd do). Or you calculate it at run-time by analyzing the individual pixels and use an edge-detection algorithm.
SFML has no build-in functionality (that I know of) to do that job for you. You have to do all the image analysis and calculations yourself.

Edit: why do you need this? What problem are you trying to solve?
« Last Edit: September 16, 2014, 05:09:40 pm by Jesper Juhl »

wh1t3crayon

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
Re: Getting boundaries of non-rectangular sprite?
« Reply #2 on: September 16, 2014, 05:27:02 pm »
@Jesper Juhl, What do you mean by storing it with my image data? And I'm trying to create a tetris clone for my second sfml project, hence my example.

Jesper Juhl

  • Hero Member
  • *****
  • Posts: 1405
    • View Profile
    • Email
Re: Getting boundaries of non-rectangular sprite?
« Reply #3 on: September 16, 2014, 05:41:01 pm »
I meant; if you have a spritesheet with 3 sprite images, then you could have an accompanying data file that contains the coordinates for a bounding polygon for each sprite. Like:
 Sprite1: x1,y1 x2,y2 x3,y3
 Sprite2: x1,y1 x2,y2 ...
 Sprite3: x1,y1 ...
Etc.

For a tetris clone you can do it a lot simpler.
Each tetramino is made up of 4 squares. Just generate 4 images for each tetramino for each of its rotations with transparency for the parts of the image not taken up by the tetramino. Then all you need to know for each image is; the dimension of the squares making up tetraminos in general, the x,y coordinate on each image grid occupied by a tetramino square for each rotation (that's just 4 indexes into a 1d representation of a 2d grid for each image).

I hope that makes sense. I'm on my phone right now, so long messages are a pain. If you still need help tomorrow evening I can (maybe find the time to) write a more detailed reply with images and code examples if needed.
« Last Edit: September 16, 2014, 07:39:16 pm by Jesper Juhl »

wh1t3crayon

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
Re: Getting boundaries of non-rectangular sprite?
« Reply #4 on: September 23, 2014, 12:41:39 am »
I meant; if you have a spritesheet with 3 sprite images, then you could have an accompanying data file that contains the coordinates for a bounding polygon for each sprite. Like:
 Sprite1: x1,y1 x2,y2 x3,y3
 Sprite2: x1,y1 x2,y2 ...
 Sprite3: x1,y1 ...
Etc.

For a tetris clone you can do it a lot simpler.
Each tetramino is made up of 4 squares. Just generate 4 images for each tetramino for each of its rotations with transparency for the parts of the image not taken up by the tetramino. Then all you need to know for each image is; the dimension of the squares making up tetraminos in general, the x,y coordinate on each image grid occupied by a tetramino square for each rotation (that's just 4 indexes into a 1d representation of a 2d grid for each image).

I hope that makes sense. I'm on my phone right now, so long messages are a pain. If you still need help tomorrow evening I can (maybe find the time to) write a more detailed reply with images and code examples if needed.
Well, words such as spritesheet really had me lost, so I'll try your second method. So you're saying to use pixel detection for each tetrimino? If so, I won't bother you with asking for an explanation, but I'd just like to know what to type into google

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: Getting boundaries of non-rectangular sprite?
« Reply #5 on: September 23, 2014, 01:11:16 am »
"axis-aligned bounding box" and "pixel-perfect collision" are the most searchable terms I can think of, though I don't think they're what you want.

I think what Jesper's trying to tell you is that tetronimos are extremely simple shapes, so you can simply write down the edges and vertices making up those polygons (perhaps as constants in your code, or as a separate file to read from, or some other form), and rotate them internally alongside rotating the sprites that you actually draw to the screen.  Testing for collisions between arbitrary sets of vertices is slightly non-trivial, but for tetronimos it won't be that hard.  I believe searching "Separating Axis Theorem" will get you much of the details.

wh1t3crayon

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
Re: Getting boundaries of non-rectangular sprite?
« Reply #6 on: September 23, 2014, 01:52:51 am »
so you can simply write down the edges and vertices making up those polygons (perhaps as constants in your code, or as a separate file to read from, or some other form), and rotate them internally alongside rotating the sprites that you actually draw to the screen.
Precisely what I had in mind actually. Now, is there a way to create one polygon using vertices or do I have to (tediously) create a bunch of sf::floatrects and position them accordingly?

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: Getting boundaries of non-rectangular sprite?
« Reply #7 on: September 23, 2014, 08:20:22 am »
Assuming you won't be passing this polygon to any SFML functions (since you have sprites elsewhere that you'll use for drawing) it's essentially up to you how you represent them.  You should probably pick whatever format makes the collision code easiest to write.

wh1t3crayon

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
Re: Getting boundaries of non-rectangular sprite?
« Reply #8 on: September 23, 2014, 02:50:58 pm »
Assuming you won't be passing this polygon to any SFML functions (since you have sprites elsewhere that you'll use for drawing) it's essentially up to you how you represent them.  You should probably pick whatever format makes the collision code easiest to write.
This is my first program using collision, so nothing is necessarily "easiest" just yet. Would this model work:
void GamePiece::SetShape(){
        //int temp = rand() % 7;
        int temp = 0;
        //create four rectangles to make up tetrimino bounds
        for(int i = 0; i < 4; i++){
                sf::RectangleShape rect;
                pieceRectangles_.push_back(rect);
        }

        switch(temp){
        case 0:
                pieceShape.setTexture(imgr.GetImage("line.png"));
                for(int i = 0; i < 4; i++){
                        sf::RectangleShape rect;
                        rect.setPosition(pieceShape.getPosition().x, i * 10);
                }
                break;
        case 1:
                pieceShape.setTexture(imgr.GetImage("llblock.png"));
                for(int i = 0; i < 4; i++){
                        sf::RectangleShape rect;
                        if(i <= 3)
                                rect.setPosition(pieceShape.getPosition().x, i * 10);
                        else{
                                rect.setPosition(pieceShape.getPosition().x + 10, (i - 1) * 10);
                        }
                        pieceRectangles_.push_back(rect);
                }
                break;
        case 2:
                pieceShape.setTexture(imgr.GetImage("rlblock.png"));
                for(int i = 0; i < 4; i++){
                        sf::RectangleShape rect;
                        if(i < 3)
                                rect.setPosition(pieceShape.getPosition().x + 10, i * 10);
                        else{
                                rect.setPosition(pieceShape.getPosition().x, (i - 1) * 10);
                        }
                        pieceRectangles_.push_back(rect);
                }
                break;
        case 3:
                pieceShape.setTexture(imgr.GetImage("square.png"));
                for(int i = 0; i < 2; i++){
                        sf::RectangleShape rect;
                        if(i < 2)
                                rect.setPosition(pieceShape.getPosition().x, i * 10);
                        if(i >= 2)
                                rect.setPosition(pieceShape.getPosition().x + 10, (i - 2) * 10);
                }
                break;
        case 4:
                pieceShape.setTexture(imgr.GetImage("lsquiggly.png"));
                for(int i = 0; i < 4; i++){
                        sf::RectangleShape rect;
                }
                break;
        case 5:
                pieceShape.setTexture(imgr.GetImage("rsquiggly.png"));
                for(int i = 0; i < 4; i++){
                        sf::RectangleShape rect;
                }
                break;
        case 6:
                pieceShape.setTexture(imgr.GetImage("tblock.png"));
                for(int i = 0; i < 4; i++){
                        sf::RectangleShape rect;
                }
                break;
        }
        width = pieceShape.getLocalBounds().width / 4;
}

So each tetrimino sprite has four sf::RectangleShapes. Upon checking for collision (so many times per second, which is what worries me), I'll create four sf::FloatRects for each sprite on the board, and set their position to the sprites' sf::rectangleshapes' positions. That's a  lot of elements which worries me, but I'm pretty sure that will get the job done right?
« Last Edit: September 23, 2014, 02:55:42 pm by Laurent »

didii

  • Full Member
  • ***
  • Posts: 122
    • View Profile
Re: Getting boundaries of non-rectangular sprite?
« Reply #9 on: September 23, 2014, 04:54:12 pm »
Searching for Tetris collision detection gives you this article: http://gamedevelopment.tutsplus.com/tutorials/implementing-tetris-collision-detection--gamedev-852
This is a grid-based tetris, not sure if that's what you want.

But in any case, you can diminish the amount of rectangles easily to a maximum of 2 (green rectangles):

Of course the line and the square blocks can be reduced to 1 single rectangle. Or you could use an AABB (axis-aligned bounding box) to simplify the collisions at first. If the AABB's collide, then go into a more detailed collision check. But I don't think that's necessary for a tetris clone.

wh1t3crayon

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
Re: Getting boundaries of non-rectangular sprite?
« Reply #10 on: September 23, 2014, 11:01:13 pm »
So slightly off topic but I'd hate to start a third thread for the same problem: How do I get the potential movement of a sf::RectangleShape? Here is my code/problem:
sf::FloatRect fr = level.GetGamePieces().at(temp - 1).GetPieceRectangles()[i].getGlobalBounds();
This creates a sf::FloatRect exactly where the sf::RectangleShapes lie that make up the sprite. What I want is to create my FloatRects where the sprite will be, not where it currently is. However, calling move() in that long line of functions produces an "expression must have class type" error. How do I get where the sprite will be on th next movement?

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: Getting boundaries of non-rectangular sprite?
« Reply #11 on: September 23, 2014, 11:15:35 pm »
So each tetrimino sprite has four sf::RectangleShapes. Upon checking for collision (so many times per second, which is what worries me), I'll create four sf::FloatRects for each sprite on the board, and set their position to the sprites' sf::rectangleshapes' positions. That's a  lot of elements which worries me, but I'm pretty sure that will get the job done right?

That's a very tiny number of elements compared to what your computer can handle.  Do not worry about it.  The collision checks may be a problem, but considering these are just tetronimos, I don't think it'll be an issue anytime soon.

The more serious problem with that sample is it's not very good coding style.  Specifically, it doesn't separate data from code at all.  The shapes of each piece should be data, and the code that processes those shapes should be completely from them.  That's more flexible and less error-prone.

Like a lot of general programming advice, that probably sounded incredibly vague and unactionable, so here's some hastily-written pseudocode that shows what I mean:
const SQUARE_SIZE = 10;

struct Tetronimo {
   std::string texture_file,
   sf::Vertex2i[4] squares
   // write a constructor taking a string and four vertices
};

const line = Tetronimo("line.png", {0,0}, {0,1}, {0,2}, {0,3});

const square = Tetronimo("square.png", {0,0}, {0,1}, {1,0}, {1,1});

...

void GamePiece::SetShape(Tetronimo type){
   ...
   pieceShape.setTexture(imgr.GetImage(type.texture_file));
   for(int i = 0; i < 4; i++){
      sf::RectangleShape rect;
      sf::Vertex2i current_square = type.squares[i];
      rect.setPosition(pieceShape.getPosition().x + current_square.x * SQUARE_SIZE,
                             current_square.y * SQUARE_SIZE);
      pieceRectangles_.push_back(rect);
   }
   // ^ now you only need to write this part once!
}
 

Hopefully that made sense.


Edit: "expression must have class type" usually means you called a method on something that is not a class.  So you probably put the move() in entirely the wrong place.  Also, FloatRect doesn't have a move() method.
« Last Edit: September 23, 2014, 11:17:15 pm by Ixrec »

wh1t3crayon

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
Re: Getting boundaries of non-rectangular sprite?
« Reply #12 on: September 23, 2014, 11:27:44 pm »
Yes that actually made a lot of sense. I realized too late that I needed to have a const int for the square size. So how do I predict the movements of the FloatRects to test for collision if they do not have a move() function?

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: Getting boundaries of non-rectangular sprite?
« Reply #13 on: September 23, 2014, 11:34:59 pm »
The Rect itself doesn't have any way of easily doing a move(), but the RectangleShape has a move() function, so I assume you could just copy the shape, move() the copy then get its bounds.

wh1t3crayon

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
Re: Getting boundaries of non-rectangular sprite?
« Reply #14 on: September 23, 2014, 11:46:01 pm »
Copy the shape? How so?