簡易テトリスを作る！

## 経緯
子供にUnity教える時に、テトリス作ってってよく言われるし作っとくかー

:::note warn
ブロックの回転は数学的知識が必要なのでわかりにくいかも...
:::



## URL
https://play.unity.com/mg/other/tetris-1z

# コード
できるだけObjectを少なくするように制作。ステージ、ミノは全て、一つのPrefabを使って制作した。
```c#:backGroundgenerator.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using UnityEngine.UI;


public class backGroundgenerator : MonoBehaviour
{
    private GameObject backGroundBlock;
    private GameObject block;
    private GameObject none;

    public GameObject backGround;
    public GameObject Block;

    private List<List<GameObject>> backGroundList = new List<List<GameObject>>();
    private int[,] onOff = new int[10,10];

    private List<GameObject> movingBlock = new List<GameObject>();
    private int rotationKey;

    private Color[] colorList = new Color [7]{new Color(0,1,1,1),new Color(1,0.92f,0.016f,1),new Color(0,1,0,1),new Color(1,0,0,1),new Color(0,0,1,1),new Color(1,0.6471f,0,1),new Color(1,0,1,1)};
    //水色、黄色、緑、赤、青、オレンジ、マゼンダ

    private int random;

    private int score=0;
    public Text scoreText;
    // Start is called before the first frame update
    void Start()
    {
        scoreText.text="Score: "+score.ToString();
        for(int j = 0;j<10;j++){//盤面生成
            for(int i = 0;i<10;i++){
                if(j==0 || i==0 || i==9){
                    if(i==0){
                        backGroundList.Add(new List<GameObject>());
                    }
                    onOff[i,j]=1;
                    backGroundBlock  = (GameObject)Instantiate(backGround) as GameObject;
                    backGroundBlock.gameObject.transform.position = new Vector2(-4.5f+i,-4.5f+j);
                    backGroundList[j].Add(backGroundBlock);
                }else{
                    onOff[i,j]=0;
                    backGroundList[j].Add(none);
                }
            }
        }
        StartCoroutine (main());
    }

    // Update is called once per frame
    void Update()
    {
        if(Input.GetKeyDown(KeyCode.RightArrow)){
            if(check("Right")){//右に進めるかチェック
                move("Right");//右に進める
            }
        }
        if(Input.GetKeyDown(KeyCode.LeftArrow)){
            if(check("Left")){
                move("Left");
            }
        }
        if(Input.GetKeyDown("d")){
            if(checkRotation("Right")){//右に回せるかチェック
                rotate("Right");//右に回す
            }
        }  
        if(Input.GetKeyDown("a")){
            if(checkRotation("Left")){
                rotate("Left");
            }
        } 
    }

    private IEnumerator main(){        
        while(true){    
            generate();//新しいブロック生成
            while(true){
                yield return new WaitForSeconds(1f);//一秒待つ
                if(check("Down")){//下に行けるかチェック
                    move("Down");//下に動かす
                }
                else{
                    changeToBackGround();//ブロックを動かせなくする
                    checkLine();//消せるラインがないか確認
                    break;
                }
            }
        }
    }
    private void generate(){
        random = Random.Range(0,6);
        if(random==0){//Iミノ
            for(int i=0;i<4;i++){
                block  = (GameObject)Instantiate(Block) as GameObject;
                block.gameObject.transform.position = new Vector2(-0.5f+i,4.5f);
                block.GetComponent<Renderer> ().material.color = colorList[random];
                movingBlock.Add(block);
            }
            rotationKey=1;
        }else if (random==1){//Oミノ
            for(int i=0;i<2;i++){
                for(int j=0;j<2;j++){
                    block  = (GameObject)Instantiate(Block) as GameObject;
                    block.gameObject.transform.position = new Vector2(-0.5f+i,4.5f-j);
                    block.GetComponent<Renderer> ().material.color = colorList[random];
                    movingBlock.Add(block);
                }
            }  
            rotationKey=3;
        }else if (random==2){//Sミノ
            for(int i=0;i<2;i++){
                for(int j=0;j<2;j++){
                    block  = (GameObject)Instantiate(Block) as GameObject;
                    block.gameObject.transform.position = new Vector2(-0.5f+i-j,4.5f-j);
                    block.GetComponent<Renderer> ().material.color = colorList[random];
                    movingBlock.Add(block);
                }           
            }
            rotationKey=3;
        }else if(random==3){//Zミノ
            for(int i=0;i<2;i++){
                for(int j=0;j<2;j++){
                    block  = (GameObject)Instantiate(Block) as GameObject;
                    block.gameObject.transform.position = new Vector2(-0.5f+i+j,4.5f-j);
                    block.GetComponent<Renderer> ().material.color = colorList[random];
                    movingBlock.Add(block);
                }           
            }   
            rotationKey=1;
        }else{//J,L,Tミノ
            //random4,5,6
            block  = (GameObject)Instantiate(Block) as GameObject;
            block.gameObject.transform.position = new Vector2(-0.5f+random-4,4.5f);                    
            block.GetComponent<Renderer> ().material.color = colorList[random];
            movingBlock.Add(block);
            for(int i=0;i<3;i++){
                block  = (GameObject)Instantiate(Block) as GameObject;
                block.gameObject.transform.position = new Vector2(-0.5f+i,3.5f);
                block.GetComponent<Renderer> ().material.color = colorList[random];
                movingBlock.Add(block);           
            }
            rotationKey=2;
        }
    }
    private bool check(string str){
        foreach(GameObject stock in movingBlock){
            int i=(int)(stock.gameObject.transform.position.x+4.5);
            int j=(int)(stock.gameObject.transform.position.y+4.5);
            if(str=="Right"){
                if(onOff[i+1,j]==1){
                    return false;
                }
            }
            else if(str=="Left"){
                if(onOff[i-1,j]==1){
                    return false;
                }
            }
            else if (str=="Down"){
                if(onOff[i,j-1]==1){
                    return false;
                }
            }
        }
        return true;
    }
    private bool checkRotation(string str){
        GameObject center = movingBlock[rotationKey];
        int centerX=(int)(center.gameObject.transform.position.x+4.5);
        int centerY=(int)(center.gameObject.transform.position.y+4.5);
        foreach(GameObject stock in movingBlock){
            int i=(int)(stock.gameObject.transform.position.x+4.5);
            int j=(int)(stock.gameObject.transform.position.y+4.5);
            if(str=="Right"){
                if(centerX-centerY+j<0|centerX-centerY+j>9|centerX+centerY-i<0|centerX+centerY-i>9){
                    return false;
                }
                if(onOff[centerX-centerY+j,centerX+centerY-i]==1){
                    return false;
                }
            }
            else if(str=="Left"){
                if(centerX+centerY-j<0|centerX+centerY-j>9|-centerX+centerY+i<0|-centerX+centerY+i>9){
                    return false;
                }
                if(onOff[centerX+centerY-j,-centerX+centerY+i]==1){
                    return false;
                }
            }
        }
        return true;
    }
    private void move(string str){
        foreach(GameObject stock in movingBlock){
            if(str=="Right"){
                stock.gameObject.transform.Translate(new Vector2(1,0));
            }
            else if(str=="Left"){
                stock.gameObject.transform.Translate(new Vector2(-1,0));
            }
            else if (str=="Down"){
                stock.gameObject.transform.Translate(new Vector2(0,-1));
            }
        }
    }
    private void rotate(string str){
        GameObject center = movingBlock[rotationKey];
        int centerX=(int)(center.gameObject.transform.position.x+4.5);
        int centerY=(int)(center.gameObject.transform.position.y+4.5);
        foreach(GameObject stock in movingBlock){
            int i=(int)(stock.gameObject.transform.position.x+4.5);
            int j=(int)(stock.gameObject.transform.position.y+4.5);
            if(str=="Right"){
                stock.gameObject.transform.position = new Vector2(-4.5f+centerX-centerY+j,-4.5f+centerX+centerY-i);
            }
            else if(str=="Left"){
                stock.gameObject.transform.position = new Vector2(-4.5f+centerX+centerY-j,-4.5f+-centerX+centerY+i);
            }
        }
    }
    private void changeToBackGround(){
        foreach(GameObject stock in movingBlock){
            int i=(int)(stock.gameObject.transform.position.x+4.5);
            int j=(int)(stock.gameObject.transform.position.y+4.5);
            onOff[i,j]=1;
            backGroundBlock  = (GameObject)Instantiate(backGround) as GameObject;
            backGroundBlock.gameObject.transform.position = new Vector2(-4.5f+i,-4.5f+j);
            backGroundBlock.GetComponent<Renderer> ().material.color = colorList[random];
            backGroundList[j][i]=backGroundBlock;
            Destroy(stock);
        }
        movingBlock.Clear();
    }
    private void checkLine(){
        int[] goodLine = new int[10]{1,0,0,0,0,0,0,0,0,0};
        for(int j=1;j<10;j++){
            int sum = 0;
            for(int i=1;i<9;i++){
                sum+=onOff[i,j];
            }
            if(sum==8){
                goodLine[j]=1;
            }
        }
        if(goodLine.Sum()>1){
            destroyLine(goodLine);
        }
    }
    private void destroyLine(int[] x){
        GameObject stock;
        int value = 1000;
        for(int j=1;j<10;j++){
            for(int i=1;i<9;i++){
                stock = backGroundList[j][i];
                backGroundList[j][i] = none;
                onOff[i,j]=0;
                if(x[j]==1){
                    Destroy(stock);
                    if(i==1){
                        score+=value;
                        value+=1000;
                        scoreText.text="Score: "+score.ToString();
                    }
                }else if (stock != none){
                    int downValue=-1;
                    for(int k=0;k<j;k++){
                        downValue+=x[k];
                    }
                    stock.gameObject.transform.Translate(new Vector2(0,-downValue));
                    backGroundList[j-downValue][i] = stock;
                    onOff[i,j-downValue]=1;
                }
            }
        }
    }


}

```
### 今後の課題
* 下ボタンを押せるようにするとバグるので追加しなかった。
=>そもそもの仕組みを変える必要があるかも？