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

Author Topic: Removing Full Lines in A Tetris Clone?  (Read 2372 times)

0 Members and 1 Guest are viewing this topic.

Midou35000

  • Newbie
  • *
  • Posts: 4
    • View Profile
    • Email
Removing Full Lines in A Tetris Clone?
« on: February 23, 2018, 08:16:48 pm »
Hello,

Before I begin, I just wanna thank whoever took his time to read this code carefully and understood how it works.

So I have this tetris clone where everything works except that I couldn't find a way to implement a function that removes a full line AND shifts the shapes above down, I have tried changing the color to Black but that did not work. I would love if I could get some help with this as am really struggling with it.

#include <SFML/Graphics.hpp>
#include <cmath>
#include <cstdlib>
#include <iostream>

using namespace std;

//
// Tetris
//
class Shape
{
public:
    sf::Color tiles[4][4];
    sf::Vector2i pos;

        // times since last downward movement
    float time;

    Shape();

        // reinitialise the shape: move to top and change shape
    void init();

        // move downwards once per second
    void update(float dt);

        // render the shape
    void draw(sf::RenderWindow& w);
   
        // rotate the shape
        void rotateLeft();
    void rotateRight();
};

void Shape::rotateLeft()
{
    sf::Color tmp[4][4];
    for(int i = 0; i < 4; i++) {
        for(int j = 0; j < 4; j++) {
            tmp[i][j]=tiles[j][3-i];
        }
    }
    for(int i = 0; i < 4; i++) {
        for(int j = 0; j < 4; j++) {
            tiles[i][j]=tmp[i][j];
        }
    }
}

void Shape::rotateRight()
{
    rotateLeft();
    rotateLeft();
    rotateLeft();
}

Shape::Shape()
{
    init();
}

void Shape::init()
{
        // move to top and reset timer
    pos.y = 0;
    pos.x = 4;
        time = 0.0f;

        // fill with black tiles
    for(int i = 0; i < 4; i++) {
        for(int j = 0; j < 4; j++) {
            tiles[i][j] = sf::Color::Black;
        }
    }


        // two hardcoded shapes
    switch(rand() % 2) {

    case 0:
        tiles[2][0] = sf::Color::Red;
        tiles[2][1] = sf::Color::Red;
        tiles[2][2] = sf::Color::Red;
        tiles[2][3] = sf::Color::Red;
        break;

    case 1:
        tiles[0][2] = sf::Color::Blue;
        tiles[1][2] = sf::Color::Blue;
        tiles[1][1] = sf::Color::Blue;
        tiles[2][1] = sf::Color::Blue;
        break;

    }

}

void Shape::update(float dt)
{
    time += dt;
    if(time > 1) {
        time = 0;
        pos.y += 1;
    }
}

void Shape::draw(sf::RenderWindow& w)
{
    sf::CircleShape s;
    s.setRadius(8);
    s.setOrigin(8,8);
    for(int i = 0; i < 4; i++) {
        for(int j = 0; j < 4; j++) {
            if(tiles[i][j] != sf::Color::Black) {
                s.setFillColor(tiles[i][j]);
                s.setPosition(sf::Vector2f(pos.x * 16 + 16 * i + 100, pos.y * 16 + 16 * j + 100));
                w.draw(s);
            }
        }
    }
}

class Board
{
public:
    sf::Color tiles[12][20];

    Board();

        // add a shape to the board
    void add(Shape& shape);  

        // check if a shape intersects with the board
    bool intersect(Shape& shape);

        // ******************* REMOVE FULL LINES ******************
    void reduce();

        // render board
    void draw(sf::RenderWindow& w);
};


void Board::reduce()
{
   
}

bool Board::intersect(Shape& shape)
{
    bool intersect = false;
    for(int i = 0; i < 4; i++) {
        for(int j = 0; j < 4; j++) {
            if(tiles[i+shape.pos.x][j+shape.pos.y] != sf::Color::Black &&
               shape.tiles[i][j] != sf::Color::Black)
               intersect = true;
        }
    }
    return intersect;
}

void Board::draw(sf::RenderWindow& w)
{
    sf::CircleShape s;
    s.setRadius(8);
    s.setOrigin(8,8);
    for(int i = 0; i < 12; i++) {
        for(int j = 0; j < 20; j++) {
            s.setFillColor(tiles[i][j]);
            s.setPosition(sf::Vector2f(16 * i + 100, 16*j + 100));
            w.draw(s);
        }
    }
}

void Board::add(Shape& shape)
{
    for(int i = 0; i < 4; i++) {
        for(int j = 0; j < 4; j++) {

            if(shape.tiles[i][j] != sf::Color::Black) {
                tiles[i + shape.pos.x][j + shape.pos.y] = shape.tiles[i][j];

                }

            }

        }


}





Board::Board()
{
        // fill with black
    for(int i = 0; i < 20; i++) {
        for(int j = 0; j < 12; j++) {
            tiles[j][i] = sf::Color::Black;
        }
    }

        // boundary
    for(int i = 0; i < 12; i++) {
        tiles[i][19] = sf::Color::Red;
    }
    for(int i = 0; i < 19; i++) {
        tiles[0][i] = sf::Color::Red;
        tiles[11][i] = sf::Color::Red;
    }
}


int main()
{
    sf::RenderWindow window(sf::VideoMode(512, 512), "Tetris");

    sf::Clock clock;
    clock.restart();   

    Shape shape;

    Board board;

    // run the program as long as the window is open
    while (window.isOpen())
    {
        // check all the window's events that were triggered since the last iteration of the loop
        sf::Event event;

        while (window.pollEvent(event))
        {
            // "close requested" event: we close the window
            if (event.type == sf::Event::Closed)
                window.close();


            if (event.type == sf::Event::KeyPressed) {
                if(event.key.code == sf::Keyboard::Left) {
                    shape.pos.x -= 1;
                                        if (board.intersect(shape)) {
                                                shape.pos.x += 1;
                                                cout << "intersect left" << endl;
                                        }
                }
                if(event.key.code == sf::Keyboard::Right) {
                    shape.pos.x += 1;
                    if(board.intersect(shape)) {
                                                shape.pos.x -= 1;
                                                cout << "intersect right" << endl;
                                        }
                }
                if(event.key.code == sf::Keyboard::Down) {
                    shape.pos.y += 1;
                    if(board.intersect(shape)) {
                                                shape.pos.y -= 1;
                                                cout << "intersect down" << endl;
                                        }
                }
                if(event.key.code == sf::Keyboard::Up) {
                    shape.rotateLeft();
                    if(board.intersect(shape)) {
                                                shape.rotateRight();
                                                cout << "intersect rotate" << endl;
                                        }
                }
            }
        }

                float dt = clock.restart().asSeconds();
               
        shape.update(dt);

        if(board.intersect(shape)) {
            shape.pos.y -= 1;
            board.add(shape);
            board.reduce();
            shape.init();
            if(board.intersect(shape)) {
                cout << "GAME OVER" << endl;
            }
        }

        window.clear(sf::Color::Black);

        board.draw(window);
        shape.draw(window);

        window.display();
    }

    return 0;
}

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: Removing Full Lines in A Tetris Clone?
« Reply #1 on: February 24, 2018, 11:13:08 am »
With your current setup, if I understood the code right, you'd simply have to iterate over your board color matrix, check if there's a line that's full and then move all the above lines one line down.

So with what exactly are you stuck?
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Midou35000

  • Newbie
  • *
  • Posts: 4
    • View Profile
    • Email
Re: Removing Full Lines in A Tetris Clone?
« Reply #2 on: February 24, 2018, 07:53:47 pm »
With your current setup, if I understood the code right, you'd simply have to iterate over your board color matrix, check if there's a line that's full and then move all the above lines one line down.

So with what exactly are you stuck?

Thank you for your reply,

Yes you did understand the code right, I just couldn't find a way to make it check if a line is full.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: Removing Full Lines in A Tetris Clone?
« Reply #3 on: February 24, 2018, 07:57:13 pm »
You have a matrix so you have x and y. To check if a line is full you simply iterate for each line (for each y) all the elements (all the x) and if all of them are colored, the line is full.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Midou35000

  • Newbie
  • *
  • Posts: 4
    • View Profile
    • Email
Re: Removing Full Lines in A Tetris Clone?
« Reply #4 on: February 24, 2018, 11:13:05 pm »
You have a matrix so you have x and y. To check if a line is full you simply iterate for each line (for each y) all the elements (all the x) and if all of them are colored, the line is full.

This is what I reached so far (it doesn't work of course):

void Board::reduce(Board& board)
{
        bool fullLine = false;
        for (int i = 0; i < 20; i++) //for every y
        {
                for (int j = 0; j < 12; j++) //for every x in y
                {
                        if (board.tiles[j][i] != sf::Color::Black )
                        {
                                cout << "Line is full";
                        }
                }
        }
}
It's checking for the board tiles in every x in y...
Any comments?

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: Removing Full Lines in A Tetris Clone?
« Reply #5 on: February 25, 2018, 01:02:14 am »
Something like this :)

void Board::reduce(Board& board)
{
        bool fullLine = false;
        for (int i = 0; i < 20; i++) //for every y
        {
                bool line_not_full = true;
                for (int j = 0; j < 12; j++) //for every x in y
                {
                        if (board.tiles[j][i] == sf::Color::Black )
                        {
                                line_not_full = false;
                                break;
                        }
                }
                if(!line_not_full)
                {
                        // ...
                }
        }
}
« Last Edit: February 25, 2018, 01:04:14 am by eXpl0it3r »
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Midou35000

  • Newbie
  • *
  • Posts: 4
    • View Profile
    • Email
Re: Removing Full Lines in A Tetris Clone?
« Reply #6 on: February 25, 2018, 12:04:34 pm »
I added a
cout <<"line is full";
to see when the program thinks the line is full, so I compiled it and this is what I get (Attached)

Apparently my argument in
if (board.tiles[j][i] != sf::Color::Black );
is checking whenever a new tile spawns and couts line is full multiple times. This is really driving me crazy, any tips?

 

anything