MajorAnonymous
MajorAnonymous

Reputation: 137

How can I make sure the figures fall into the playfield in Tetris?

I am making Tetris in C#. I have now created a playfield and the figures with their possible rotations. I am making it in Winforms. The playfield has a 2d-array and the figures too. The playfield is standard filled with the values 0, what means that it is empty. The figures are filled with the values 1 what means it is filled and 0. In this way I can create figures. The labels are the visual part of the game. This is my code so far:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TetrisTest
{
    public partial class Form1 : Form
    {
        private Label label;
        
        public Form1()
        {
            InitializeComponent();
            this.WindowState = FormWindowState.Maximized;
            int[,] figureI = {{1, 0, 0, 0},
                              {1, 0, 0, 0},
                              {1, 0, 0, 0},
                              {1, 0, 0, 0}};

            int[,] figureL = {{1, 0, 0},
                              {1, 0, 0},
                              {1, 1, 0}};

            int[,] figureJ = {{0, 1, 0},
                              {0, 1, 0},
                              {1, 1, 0}};

            int[,] figureT = {{1, 1, 1},
                              {0, 1, 0},
                              {0, 0, 0}};

            int[,] figureO = {{1, 1},
                              {1, 1}};

            int[,] figureS = {{0, 1, 1},
                              {1, 1, 0},
                              {0, 0, 0}};

            int[,] figureZ = {{1, 1, 0},
                              {0, 1, 1},
                              {0, 0, 0}};

            var figureI2 = RotateRight(figureI);
            var figureL2 = RotateRight(figureL);
            var figureL3 = RotateRight(figureL2);
            var figureL4 = RotateRight(figureL3);
            var figureJ2 = RotateRight(figureJ);
            var figureJ3 = RotateRight(figureJ2);
            var figureJ4 = RotateRight(figureJ3);
            var figureT2 = RotateRight(figureT);
            var figureT3 = RotateRight(figureT2);
            var figureT4 = RotateRight(figureT3);
            var figureS2 = RotateRight(figureS);
            var figureS3 = RotateRight(figureS2);
            var figureS4 = RotateRight(figureS3);
            var figureZ2 = RotateRight(figureZ);
            var figureZ3 = RotateRight(figureZ2);
            var figureZ4 = RotateRight(figureZ3);
        }
        
        private void Form1_Load(object sender, EventArgs e)
        {
            for (int i = 0; i < 10; i++)
            {
                for (int j = 0; j < 20; j++)
                {
                    label = new Label();
                    label.AutoSize = false;
                    label.Name = "label" + j.ToString() + i.ToString();
                    label.TabIndex = 0;
                    label.Text = "[" + j.ToString() + "]" + "[" + i.ToString() + "]";
                    label.Visible = true;
                    this.Controls.Add(label);
                    label.Location = new Point(Size.Width / 2 - (5 - i) * 50, Size.Height / 2 - (11 - j) * 30);
                    label.Size = new Size(50, 30);
                    label.BackColor = Color.White;
                    if (i % 2 == 0)
                    {
                        label.BackColor = Color.Blue;
                    }                    
                }
            }
            int valueNone = 0;
            int[,] playField = new int[10, 20];
            foreach (int b in playField)
            {
                playField[b, b] = valueNone;
                Console.WriteLine(playField[b, b]);
            }
        }
        static int[,] RotateRight(int[,] arr)
        {
            int size = arr.GetLength(0);
            int[,] rotated = new int[size, size];

            for (int j = 0; j < size; j++)
                for (int i = size - 1; i >= 0; i--)
                    rotated[j, size - i - 1] = arr[i, j];

            return rotated;
        }

        private void startGame_Click(object sender, EventArgs e)
        {

        }
    }
}

I am a bit stuck now. I know I need a timer, because the figures need to move down automatically over time. But what I don't know is firstly: how I can get the figures in the playfield. And secondly: make sure the figures stop as soon as the value 1 in the figures-array hits the value 1 in the playfield-array. In this way I can create the game. I hope someone can help me with this, because I have no idea.

Upvotes: 0

Views: 109

Answers (1)

Victor
Victor

Reputation: 2371

Well, this is a whole project. I'm going to give you my impressions and some keys about how I do a project like this. First of all, you need do a previous review of the entire project and try to get all your actors.

For example, you need a class for the Board with the array and properties like Width/Height. If you need some statistics (like number of figures...) you can have a list of Figures. If not, you may use a byte value, with the index of color or directly the color itself. We choose the last option, the easier one. The board has an array of Colors, black at first.

You need also a Figure, with an array like your example and a Color. It has also an X, Y property (position of upper left array). This class can have methods like Rotate, GetWidth and GetHeight because the array may be bigger than the figure (figureI in vertical, for example, has 1 of width but 4 in the array to allow the rotation) and you need work with the figure when you move in the board and check collision with other figures.

Add a Game class with a Board and a Figure (the current figure). Add a TryMoveFigure(bool right) that return true if you can move the current figure in that direction. You have access to the board and the current figure. Simply check if values of figure (filtering black positions) moved in that direction are inside the board and not overlap previous figures (the color in the board is black in this zone). If figure may move, you update it's X property.

Add a TryMoveDown() to try move figure down (update Y property).

And you need a method to know when the figure can't move anymore. IsFigureStopped return true in this case.

The game may have a Draw method (Draw(Graphics g)) in which you invoke Draw of board and draw of current figure. In all cases you are going to invoke g.FillRectangle with each cell of the board. The board has the color of any cell, simply get the coordinates and draw it. The figure is similar: you know the position of its array and (filtering blacks items) draw each position.

And for the logic:

  • You need a random value to select the next figure to create. Use Random class. If you have a list of arrays (one for each kind of figure, like in your question) you can select one item of this list to select the figure. Same (an array) to select the color. So if you get a random number 1, you clone your figureL array (in position 1 in your array of available kind of figures) and the color at position 1 (all figures os same shape has always same color).
  • Set the X,Y position of the new figure on top of the board.
  • In each timer, move down your figure.
  • In each left/right from user, try to move the figure.
  • After any movement, check if IsFigureStopped: when stopped, copy figure colors (without blacks) in that positions of the board. After this, the board will paint that figure. Create a new figure.
  • Check also if the game is finished after stop a figure.

You can draw everything using a Panel, for example, in the Paint event. Remember invoke Invalidate of your Panel each time that your image change (you move a figure, for example) to indicate to Windows that you want redraw the panel.

Let me know if you want to develop it in this way and need some help.

Upvotes: 2

Related Questions