0
\$\begingroup\$

I am trying to make my own tetris clone. I have actually got very far into it without running into major problems, but I am now stuck and can't find the answer after searching.

Basically I have used Input.GetAxis("Vertical") so that when player is holding down on controls the piece drops rapidly (else it goes back to normal drop speed). It all works great but in my memory of Tetris after the block is frozen at the bottom, even when the player is holding down on controls it still doesn't make the new block move fast until they let go of the down key and then press it again.

I have some ideas on how to do it, but i think i might have to delete much of my code and to be honest, I'm scared of breaking it. I am kinda hoping there is some nice elegant solution that I just don't know about yet.

I am posting the code now in case you'd like to look through it all. Its all in one big messy file, but I actually felt maybe making more class files would be unnecessary (perhaps when I am finished I will attempt to encapsulate it all properly and section it into logical classes as another exercise for myself):

using UnityEngine;
using System.Collections.Generic;

public class GameBoard : MonoBehaviour
{
const ushort CELL_COUNT_X = 10;
const ushort CELL_COUNT_Y = 24; 
const ushort CELL_SIZE = 1;

GameObject brick;
List<GameObject> bricks = new List<GameObject>();
private Sprite brickSprite;
private Sprite wallSprite;
GameObject[] debugWallBricks = new GameObject[CELL_COUNT_X * CELL_COUNT_Y];
TetrisPiece fallingPiece;
const ushort BLOCKTYPE_COUNT = 7;

const short DEFAULT_POSITION_X = CELL_COUNT_X / 2 - 2;
const short DEFAULT_POSITION_Y = CELL_COUNT_Y - 4;

//bool[,] frozenCells = new bool[CELL_COUNT_X, CELL_COUNT_Y]; // ill use this to store record of all fixed/settled blocks no longer falling
FrozenPiece[,] frozenCells = new FrozenPiece[CELL_COUNT_X, CELL_COUNT_Y];
List<GameObject> frozenCellBricks = new List<GameObject>();

float dropTimer = 0f;
float dropTimerBaseSpeed = 1f;
float dropTimerSuperSpeed = 15f;
float dropDelay = 0.7f;
float moveTimer = 0f;
float moveToDropSpeedFactor = 5f;
float moveDelay; // this value depends on what value the dropDelay is and is set in Update
float rotTimer = 0f;
float rotDelay = 0.15f;


private void Start()
{
    brickSprite = Resources.Load<Sprite>("Tex/tetris_brick");
    wallSprite = Resources.Load<Sprite>("Tex/border_rounded");

    CreateDebugWall();
    MakeNewFallingPiece();

    for (int y = 0; y < frozenCells.GetLength(1); y++)
    {
        for (int x = 0; x < frozenCells.GetLength(0); x++)
        {
            FrozenPiece f = new FrozenPiece(Color.grey, false);
            f.isFilled = false;
            frozenCells[x,y] = f;
        }
    }
}

// i clear the visual board every frame and re-create a new brick, spriterenderer etc every frame (probably a shit way !) todo
void ClearBoard()
{
    foreach (GameObject go in bricks)
        Destroy(go);
    foreach (GameObject go in frozenCellBricks)
        Destroy(go);

}

void CreateDebugWall()
{
    int i = 0;
    for (int x = 0; x < CELL_COUNT_X; x++)
    {
        for (int y = 0; y < CELL_COUNT_Y; y++)
        {
            brick = new GameObject();
            brick.name = "Debug_Wall_Brick";
            brick.AddComponent<SpriteRenderer>();
            brick.GetComponent<SpriteRenderer>().sprite = wallSprite;
            brick.transform.position = new Vector2(x * CELL_SIZE, y * CELL_SIZE);
            brick.GetComponent<SpriteRenderer>().color = Color.grey;
            debugWallBricks[i] = brick;

        }
    }
}

void MakeNewFallingPiece()
{
    TetrisPiece.BlockType blockType = (TetrisPiece.BlockType)Random.Range(0, BLOCKTYPE_COUNT);
    dropTimer = 0f;
    fallingPiece = new TetrisPiece(blockType, DEFAULT_POSITION_X, DEFAULT_POSITION_Y);
    DrawFallingPiece();
}

void DropDown()
{
    // check cell directly below a block:
    for (int y = 0; y < fallingPiece.GetCurrentOrientation().orientations.GetLength(0); y++)
    {
        for (int x = 0; x < fallingPiece.GetCurrentOrientation().orientations.GetLength(0); x++)
        {
            if (fallingPiece.GetCurrentOrientation().orientations[y, x] == 1)
            {
                if (fallingPiece.pos_y + y == 0)
                {
                    Debug.Log("HIT FLOOR!");
                    ConvertFallingPieceToFrozenBricks();
                    return;
                }
                if (frozenCells[fallingPiece.pos_x + x, fallingPiece.pos_y + y - 1].isFilled == true)
                {
                    Debug.Log("HIT FROZEN CELLS!");
                    ConvertFallingPieceToFrozenBricks();
                    return;
                }
            }
        }
    }
    fallingPiece.pos_y--;
}

void MoveLeft()
{
    // check cell directly to left of a block:
    for (int y = 0; y < fallingPiece.GetCurrentOrientation().orientations.GetLength(0); y++)
    {
        for (int x = 0; x < fallingPiece.GetCurrentOrientation().orientations.GetLength(0); x++)
        {
            if (fallingPiece.GetCurrentOrientation().orientations[y, x] == 1)
            {
                if (fallingPiece.pos_x + x == 0)
                {
                    Debug.Log("hit side wall");
                    return;
                }
                if(frozenCells[fallingPiece.pos_x - 1 + x, fallingPiece.pos_y + y].isFilled == true) 
                {
                    Debug.Log("tried moving left but there was a frozen brick");
                    return;
                }
            }
        }
    }
    fallingPiece.pos_x--;
}

void MoveRight()
{
    // check cell directly to left of a block:
    for (int y = 0; y < fallingPiece.GetCurrentOrientation().orientations.GetLength(0); y++)
    {
        for (int x = 0; x < fallingPiece.GetCurrentOrientation().orientations.GetLength(0); x++)
        {
            if (fallingPiece.GetCurrentOrientation().orientations[y, x] == 1)
            {
                if (fallingPiece.pos_x + x == CELL_COUNT_X - 1)
                {
                    Debug.Log("hit side wall");
                    return;
                }
                if (frozenCells[fallingPiece.pos_x + 1 + x, fallingPiece.pos_y + y].isFilled == true) 
                {
                    Debug.Log("tried moving right but there was a frozen brick");
                    return;
                }
            }
        }
    }
    fallingPiece.pos_x++;
}

void RotatePositive()
{
    for (int y = 0; y < fallingPiece.GetCurrentOrientation().orientations.GetLength(0); y++)
    {
        for (int x = 0; x < fallingPiece.GetCurrentOrientation().orientations.GetLength(0); x++)
        {
            if (fallingPiece.GetNextOrientation().orientations[y, x] == 1)
            {
                if (fallingPiece.pos_x + x < 0)
                {
                    Debug.Log("tried rotation but hit a wall");
                    return;
                }
                if (fallingPiece.pos_x + x >= CELL_COUNT_X)
                {
                    Debug.Log("tried rotation but hit a wall");
                    return;
                }
                if (fallingPiece.pos_y + y == 0)
                {
                    Debug.Log("tried rotation but hit floor");
                    return;
                }
            }
        }
    }
    fallingPiece.GotoNextOrientation();
}

void ConvertFallingPieceToFrozenBricks()
{
    for (int y = 0; y < fallingPiece.GetCurrentOrientation().orientations.GetLength(0); y++)
    {
        for (int x = 0; x < fallingPiece.GetCurrentOrientation().orientations.GetLength(0); x++)
        {
            if (fallingPiece.GetCurrentOrientation().orientations[y,x] == 1)
                frozenCells[fallingPiece.pos_x + x, fallingPiece.pos_y + y] = new FrozenPiece(fallingPiece.color, true);
        }
    }
    fallingPiece = null;
}

void DrawFallingPiece()
{
    if (fallingPiece == null)
        return;

    for (int y = 0; y < fallingPiece.GetCurrentOrientation().orientations.GetLength(0); y++)
    {
        for (int x = 0; x < fallingPiece.GetCurrentOrientation().orientations.GetLength(0); x++)
        {
            if (fallingPiece.GetCurrentOrientation().orientations[y, x] == 1)
            {
                brick = new GameObject();
                brick.name = "TetrisPiece_" + fallingPiece.blockType;
                brick.AddComponent<SpriteRenderer>();
                brick.GetComponent<SpriteRenderer>().sprite = brickSprite;
                brick.transform.position = new Vector2((fallingPiece.pos_x + x) * CELL_SIZE, (fallingPiece.pos_y + y) * CELL_SIZE);
                brick.GetComponent<SpriteRenderer>().color = fallingPiece.color;
                bricks.Add(brick);
            }
        }
    }
}

void DrawFrozenBricks()
{
    for (int x = 0; x < frozenCells.GetLength(0); x++)
    {
        for (int y = 0; y < frozenCells.GetLength(1); y++)
        {
            if (frozenCells[x, y].isFilled == true) 
            {
                brick = new GameObject();
                brick.name = "Frozen Cell Brick";
                brick.AddComponent<SpriteRenderer>();
                brick.GetComponent<SpriteRenderer>().sprite = brickSprite;
                brick.transform.position = new Vector2(x * CELL_SIZE, y * CELL_SIZE);
                brick.GetComponent<SpriteRenderer>().color = frozenCells[x,y].color;
                frozenCellBricks.Add(brick);
            }
        }
    }
}

void HandleMovementAndBlockCreation()
{
    float input_x = Input.GetAxis("Horizontal");
    float input_y = Input.GetAxis("Vertical");
    bool rotateButton = Input.GetButtonDown("Rotate_Positive");
    moveDelay = dropDelay / moveToDropSpeedFactor;

    moveTimer += Time.deltaTime;
    rotTimer += Time.deltaTime;

    if (fallingPiece != null)
    {
        if (input_y < 0)
            dropTimer += dropTimerSuperSpeed * Time.deltaTime;
        else
            dropTimer += dropTimerBaseSpeed * Time.deltaTime;


        if (dropTimer >= dropDelay)
        {
            DropDown();
            dropTimer = 0f;
        }
        else
        {
            if (moveTimer >= moveDelay)
            {
                moveTimer = 0f;

                if (input_x < 0)
                    MoveLeft();
                else if (input_x > 0)
                    MoveRight();
            }
            if (rotateButton)
                RotatePositive();
        }
    }
    else
    {
        MakeNewFallingPiece();
    }
}

private void Update()
{
    ClearBoard();

    HandleMovementAndBlockCreation();



    DrawFallingPiece();
    DrawFrozenBricks();

}
}

public class TetrisPiece
{
public enum BlockType { A, B, C, D, E, F, G };
public BlockType blockType;
private Orientation[] possibleOrientations;
private int currentOrientationIndex = 0;
public short pos_x, pos_y;
public Color color;

public TetrisPiece(BlockType blockType, short PosX, short PosY)
{
    pos_x = PosX;
    pos_y = PosY;

    this.blockType = blockType;
    switch (blockType)
    {
        case BlockType.A:
            color = Color.red;
            possibleOrientations = new Orientation[2];
            possibleOrientations[0] = new Orientation(new int[4, 4] { { 0, 1, 0, 0 }, { 0, 1, 0, 0 }, { 0, 1, 0, 0 }, { 0, 1, 0, 0 } });
            possibleOrientations[1] = new Orientation(new int[4, 4] { { 0, 0, 0, 0 }, { 1, 1, 1, 1 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } });
            break;
        case BlockType.B:
            color = Color.blue;
            possibleOrientations = new Orientation[1];
            possibleOrientations[0] = new Orientation(new int[4, 4] { { 0, 0, 0, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 0, 0, 0 } });
            break;
        case BlockType.C:
            color = Color.green;
            possibleOrientations = new Orientation[4];
            possibleOrientations[0] = new Orientation(new int[4, 4] { { 0, 0, 0, 0 }, { 0, 1, 0, 0 }, { 1, 1, 1, 0 }, { 0, 0, 0, 0 } });
            possibleOrientations[1] = new Orientation(new int[4, 4] { { 0, 0, 0, 0 }, { 0, 1, 0, 0 }, { 1, 1, 0, 0 }, { 0, 1, 0, 0 } });
            possibleOrientations[2] = new Orientation(new int[4, 4] { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 1, 1, 1, 0 }, { 0, 1, 0, 0 } });
            possibleOrientations[3] = new Orientation(new int[4, 4] { { 0, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 1, 1, 0 }, { 0, 1, 0, 0 } });
            break;
        case BlockType.D:
            color = Color.cyan;
            possibleOrientations = new Orientation[2];
            possibleOrientations[0] = new Orientation(new int[4, 4] { { 0, 0, 0, 0 }, { 0, 0, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 0, 0 } });
            possibleOrientations[1] = new Orientation(new int[4, 4] { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 1, 1, 0, 0 }, { 0, 1, 1, 0 } });
            break;
        case BlockType.E:
            color = ColorTools.Color255(128f, 41f, 11f); // brown
            possibleOrientations = new Orientation[2];
            possibleOrientations[0] = new Orientation(new int[4, 4] { { 0, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 1, 1, 0 }, { 0, 0, 1, 0 } });
            possibleOrientations[1] = new Orientation(new int[4, 4] { { 0, 0, 0, 0 }, { 0, 0, 1, 1 }, { 0, 1, 1, 0 }, { 0, 0, 0, 0 } });
            break;
        case BlockType.F:
            color = ColorTools.Color255(255f, 255f, 0f); // yellow
            possibleOrientations = new Orientation[4];
            possibleOrientations[0] = new Orientation(new int[4, 4] { { 0, 0, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 1, 1, 0 } });
            possibleOrientations[1] = new Orientation(new int[4, 4] { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 1, 1, 1 }, { 0, 0, 0, 1 } });
            possibleOrientations[2] = new Orientation(new int[4, 4] { { 0, 0, 0, 0 }, { 0, 1, 1, 0 }, { 0, 1, 0, 0 }, { 0, 1, 0, 0 } });
            possibleOrientations[3] = new Orientation(new int[4, 4] { { 0, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 1, 1, 1}, { 0, 0, 0, 0 } });
            break;
        case BlockType.G:
            color = ColorTools.Color255(128f, 0f, 128f); // purple
            possibleOrientations = new Orientation[4];
            possibleOrientations[0] = new Orientation(new int[4, 4] { { 0, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 1, 0, 0 }, { 0, 1, 1, 0 } });
            possibleOrientations[1] = new Orientation(new int[4, 4] { { 0, 0, 0, 0 }, { 0, 0, 1, 0 }, { 1, 1, 1, 0 }, { 0, 0, 0, 0 } });
            possibleOrientations[2] = new Orientation(new int[4, 4] { { 0, 0, 0, 0 }, { 1, 1, 0, 0 }, { 0, 1, 0, 0 }, { 0, 1, 0, 0 } });
            possibleOrientations[3] = new Orientation(new int[4, 4] { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 1, 1, 1, 0 }, { 1, 0, 0, 0 } });
            break;
    }
}


public Orientation GetCurrentOrientation()
{
    return possibleOrientations[currentOrientationIndex];
}

public Orientation GetNextOrientation()
{
    Debug.Log("index = " + currentOrientationIndex);
    if (possibleOrientations.Length == 1)
        return possibleOrientations[0];
    if (currentOrientationIndex == possibleOrientations.Length - 1)
        return possibleOrientations[0];
    else
        return possibleOrientations[currentOrientationIndex + 1];
}

public void GotoNextOrientation()
{
    currentOrientationIndex++;
    if (currentOrientationIndex >= possibleOrientations.Length)
        currentOrientationIndex = 0;
}
}

 public struct Orientation
 {
public int[,] orientations;

public Orientation(int[,] Orientations)
{
    orientations = Orientations;
}
}

public class FrozenPiece
{
public Color color;
public bool isFilled = false;

public FrozenPiece(Color Color, bool IsFilled)
{
    color = Color;
    isFilled = IsFilled;
}
}

public static class ColorTools
{
public static Color Color255(float r, float g, float b)
{
    return new Color(r / 255f, g / 255f, b / 255f);
}
public static Color Color255_Alpha(float r, float g, float b, float a)
{
    return new Color(r / 255f, g / 255f, b / 255f, a / 255f);
}
}
\$\endgroup\$
  • \$\begingroup\$ I have kind of fixed it, by using Input.GetKeyDown(KeyCode.S) and setting a bool on the fallingPiece to say that 'S' has been pressed down during its lifetime. \$\endgroup\$ – Big T Larrity Jun 19 '19 at 4:11
1
\$\begingroup\$

You can use a boolean flag. Whenever a new piece spawns, set it to true and in the update method, check if the down key is pressed and if it isn't, set the flag to false.

This way you'll have a boolean, that'll only become false after a new piece, when the down key gets released. If the boolean is true, don't speed the falling up.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.