Ameen Oumer
Ameen Oumer

Reputation: 57

Drawing tetrominos (Tetris pieces)

I am having trouble creating/drawing the tetrominos (Tetris pieces), what are my options in C++ using SFML?

I tried to draw them as a convex using switch statement and giving them numbers, which didn't work because the L and J shapes are concave.

 ConvexShape blocks;
    blocks.setTexture(&tile);

             // block generation and shape
    default_random_engine randomGenerator(time(0));
    uniform_int_distribution<int> blocktype(0,6);
    int n = blocktype(randomGenerator);
    switch (n)
    {
        case (0): blocks.setPointCount(4);
                  blocks.setPoint(0,Vector2f(0.0f,0.0f));
                  blocks.setPoint(1,Vector2f(18.0f,0.0f));
                  blocks.setPoint(2,Vector2f(18.0f,72.0f));
                  blocks.setPoint(3,Vector2f(0.0f,72.0f));
                  break;
        case (1): blocks.setPointCount(4);
                  blocks.setPoint(0,Vector2f(0.0f,0.0f));
                  blocks.setPoint(1,Vector2f(36.0f,0.0f));
                  blocks.setPoint(2,Vector2f(36.0f,36.0f));
                  blocks.setPoint(3,Vector2f(0.0f,36.0f));
                  break;
        case (2): blocks.setPointCount(8);
                  blocks.setPoint(0,Vector2f(0.0f,0.0f));
                  blocks.setPoint(1,Vector2f(18.0f,0.0f));
                  blocks.setPoint(2,Vector2f(18.0f,18.0f));
                  blocks.setPoint(3,Vector2f(36.0f,18.0f));
                  blocks.setPoint(4,Vector2f(36.0f,36.0f));
                  blocks.setPoint(5,Vector2f(18.0f,36.0f));
                  blocks.setPoint(6,Vector2f(18.0f,54.0f));
                  blocks.setPoint(7,Vector2f(0.0f,54.0f));
                  break;
        case (3): blocks.setPointCount(8);
                  blocks.setPoint(0,Vector2f(0.0f,0.0f));
                  blocks.setPoint(1,Vector2f(18.0f,0.0f));
                  blocks.setPoint(2,Vector2f(18.0f,18.0f));
                  blocks.setPoint(3,Vector2f(36.0f,18.0f));
                  blocks.setPoint(4,Vector2f(36.0f,54.0f));
                  blocks.setPoint(5,Vector2f(18.0f,54.0f));
                  blocks.setPoint(6,Vector2f(18.0f,36.0f));
                  blocks.setPoint(7,Vector2f(0.0f,36.0f));
                  break;
        case (4): blocks.setPointCount(8);
                  blocks.setPoint(0,Vector2f(0.0f,18.0f));
                  blocks.setPoint(1,Vector2f(18.0f,18.0f));
                  blocks.setPoint(2,Vector2f(18.0f,0.0f));
                  blocks.setPoint(3,Vector2f(36.0f,0.0f));
                  blocks.setPoint(4,Vector2f(36.0f,36.0f));
                  blocks.setPoint(5,Vector2f(18.0f,36.0f));
                  blocks.setPoint(6,Vector2f(18.0f,54.0f));
                  blocks.setPoint(7,Vector2f(0.0f,54.0f));
                  break;
        case (5): blocks.setPointCount(6);
                  blocks.setPoint(0,Vector2f(0.0f,54.0f));
                  blocks.setPoint(1,Vector2f(0.0f,0.0f));
                  blocks.setPoint(2,Vector2f(18.0f,0.0f));
                  blocks.setPoint(3,Vector2f(18.0f,40.0f));
                  blocks.setPoint(4,Vector2f(36.0f,36.0f));
                  blocks.setPoint(5,Vector2f(36.0f,54.0f));
                  break;
        case (6): blocks.setPointCount(6);
                  blocks.setPoint(0,Vector2f(0.0f,0.0f));
                  blocks.setPoint(1,Vector2f(54.0f,0.0f));
                  blocks.setPoint(2,Vector2f(54.0f,18.0f));
                  blocks.setPoint(3,Vector2f(36.0f,18.0f));
                  blocks.setPoint(4,Vector2f(36.0f,36.0f));
                  blocks.setPoint(5,Vector2f(18.0f,36.0f));
                  break;
    }

The L n J shape appear like this.

Upvotes: 0

Views: 1037

Answers (1)

Mario
Mario

Reputation: 36517

First of all, when using a library such as SFML, it's important to always remember that the library might provide you with convenient shortcuts (like sf::CircleShape or sf::RectangleShape), but you don't necessarily have to use them, especially if it exposes you something far more flexible, such as sf::VertexArray.

Next you'll also have to remember that there's more than one way to build your tetrominos from basic primitives.

The most obvious one here would be using triangles or quads. Let's build the T shape using quads:

sf::VertexArray quads(sf::Quads);

// Left piece
quads.append({{0, 0}, sf::Color::White});
quads.append({{95, 0}, sf::Color::Red});
quads.append({{95, 95}, sf::Color::Green});
quads.append({{0, 95}, sf::Color::Blue});

// Center piece
quads.append({{100, 0}, sf::Color::White});
quads.append({{195, 0}, sf::Color::Red});
quads.append({{195, 95}, sf::Color::Green});
quads.append({{100, 95}, sf::Color::Blue});

// Right piece
quads.append({{200, 0}, sf::Color::White});
quads.append({{295, 0}, sf::Color::Red});
quads.append({{295, 95}, sf::Color::Green});
quads.append({{200, 95}, sf::Color::Blue});

// Bottom piece
quads.append({{100, 100}, sf::Color::White});
quads.append({{195, 100}, sf::Color::Red});
quads.append({{195, 195}, sf::Color::Green});
quads.append({{100, 195}, sf::Color::Blue});

Note that sf::Quads is not supported on mobile platforms and you'd have to define triangles rather than quads. Also I've intentionally shortened lengths/widths of the quads by 5 to leave visible gaps.

The probably more elegant (and efficient) solution is to use a triangle fan. Since the T tetromino is a concave shape, you'll have to pick the correct starting point for your fan, i.e. one of the points making the shape concave. In other instances you might have to create a new (invisible) point specifically for this though, e.g. inside the shape.

sf::VertexArray triangleFan(sf::TriangleFan);

// Starting point is the bottom left corner of the center piece
triangleFan.append({{100, 100}, sf::Color::White});
triangleFan.append({{0, 100}, sf::Color::Red});
triangleFan.append({{0, 0}, sf::Color::Green});
triangleFan.append({{300, 0}, sf::Color::Blue});
triangleFan.append({{300, 100}, sf::Color::Magenta});
// The next point creates an invisible triangle just to move to the center piece
triangleFan.append({{200, 100}, sf::Color::Black});
triangleFan.append({{200, 200}, sf::Color::Cyan});
triangleFan.append({{100, 200}, sf::Color::Yellow});

Drawing these two shapes with a translation of {50, 50} or {50, 350} respectively results in two giant tetrominos on screen:

Example Screenshot

For your case you'd have to scale them properly of course.

If you're still having issues or want something to compile, run, and play around with, I've uploaded a short example on GitHub.

Upvotes: 2

Related Questions