This post is Private. Only a writer or those who know its URL can access this post.

Article information
Show article in Markdown
Report article
Help us understand the problem. What is going on with this article?

高校の課題研究「3Dテトリス」が発掘された話(限定公開)

こちらはITRC Advent Calendar 2019 12日目の記事です。

経緯

よ〜し!Rustのプログラムかくぞ〜!

ん?ここなんでエラー出てるんだろ?
ん?なおらんぞ?
ここを直せば!
直った?いや、エラーが増えた!?
やばい日付かわった。。

締め切りが...

おわらーーーーーーーーーん!!!!!!!

ということでこんにちは!@saba383810です。元々書こうと思っていたrustの記事が間に合いませんでした。ゴメンナチャイ(;ω;)
埋め合わせで何か書くことあるかな〜と探していた時に家のメインPCから高校の課題研究(完成前のデータ)を発掘!そこで、サークルのメンバーに私が高校時代どんなプログラムを書いていたかということも踏まえて限定公開で記事を書けばいいんじゃね?と思いこの記事を書き始めたとさ。

環境

  • unity 2017.3.17f
  • UnityC#
  • monodevelop
  • win 10

3Dテトリス

どんなゲームか完結に説明すると

「3D世界」と「ポリゴン世界」を移動できる主人公が
二つのフィールドを行き来しながらフィールドにいる女の子(NPC)とテトリスバトルをする

というゲームです。
え?つまんなそうだって??

うん。おもしろいゲームだって信じてる...


今回全て紹介すると記述量がやばくなるので2Dテトリスの一部のソースコードを紹介します。

デバック時の動画

タイトル〜フィールド

3Dテトリス1.gif

こんな感じでフィールドを移動できます。ジャンプ機能もあります。
フィールドにいる「F」(ウネウネしたやつ)は友達のオリジナルキャラを入れて欲しい言われてしょうがなく配置したキャラなのであまり気にせずに。。

2Dテトリス画面

3Dテトリス11.gif

ミノもちゃんときえます。
Tスピンならできる。Lスピンは実装できなかった。

ソースコード

2Dテトリスに関するプログラムです。

tetrimino.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Tetrimino : MonoBehaviour
{
    private float t = 0;
    private float t2 = 0;
    private float fallSpeed = 0.5f;
    float fall = 0;
    public bool allowRotation = true;
    public bool limitRotation = false;

    void Update ()
    {
        CheckUserInput ();
    }

    void CheckUserInput ()
    {
        t += Time.deltaTime;
        t2 += Time.deltaTime;
        ///right
        if (t > 0.1f) {
            if (Input.GetAxis ("DDF2") > 0) {
                transform.position += new Vector3 (1, 0, 0);
                t = 0;
                if (CheckIsValidPosition ()) {
                    FindObjectOfType<Game> ().UpdateGrid (this);
                } else {
                    transform.position += new Vector3 (-1, 0, 0);
                }
            }
        ///Left
            else if (Input.GetAxis ("DDF2") < 0) {
                transform.position += new Vector3 (-1, 0, 0);
                t = 0;
                if (CheckIsValidPosition ()) {
                    FindObjectOfType<Game> ().UpdateGrid (this);    
                } else {
                    transform.position += new Vector3 (1, 0, 0);
                }
            } 
        ///Down
            else if (Input.GetAxis ("DDF1") < 0 || Time.time - fall >= fallSpeed) {
                transform.position += new Vector3 (0, -1, 0);
                fall = Time.time;
                t = 0;
                if (CheckIsValidPosition ()) {
                    FindObjectOfType<Game> ().UpdateGrid (this);
                } else {
        //object生成
                    transform.position += new Vector3 (0, 1, 0);
                    FindObjectOfType<Game> ().DeleateRow ();
                    if (FindObjectOfType<Game> ().CheckIsAboveGrid (this)) {
                        FindObjectOfType<Game> ().GameOver();
                    }
                    enabled = false;
                    FindObjectOfType<Game> ().SpownNextTetrimino ();
                }

            } else if (t2 > 0.2f) {
        //回転
                if (Input.GetKey (KeyCode.JoystickButton0)) {
                    if (allowRotation) {
                        if (limitRotation) {
                            if (transform.rotation.eulerAngles.z >= 90) {
                                transform.Rotate (0, 0, -90);
                                t2 = 0;
                            } else {
                                transform.Rotate (0, 0, 90);
                                t2 = 0;
                            }
                        } else {
                            transform.Rotate (0, 0, 90);
                            t2 = 0;
                        }
                        if (CheckIsValidPosition ()) {
                            FindObjectOfType<Game> ().UpdateGrid (this);
                        } else {
                            if (limitRotation) {
                                if (transform.rotation.eulerAngles.z >= 90) {
                                    transform.Rotate (0, 0, -90);
                                    t2 = 0;
                                } else {
                                    transform.Rotate (0, 0, 90);
                                    t2 = 0;
                                }
                            } else {
                                transform.Rotate (0, 0, -90);
                                t2 = 0;
                            }
                        }
                    }
                } 
        //回転
                else if (Input.GetKey (KeyCode.JoystickButton1)) {
                    if (allowRotation) {
                        if (limitRotation) {
                            if (transform.rotation.eulerAngles.z >= 90) {
                                transform.Rotate (0, 0, -90);
                                t2 = 0;
                            } else {
                                transform.Rotate (0, 0, 90);
                                t2 = 0;
                            }
                        } else {
                            transform.Rotate (0, 0, -90);
                            t2 = 0;
                        }
                        if (CheckIsValidPosition ()) {
                            FindObjectOfType<Game> ().UpdateGrid (this);
                        } else {
                            if (limitRotation) {
                                if (transform.rotation.eulerAngles.z >= 90) {
                                    transform.Rotate (0, 0, -90);
                                    t2 = 0;
                                } else {
                                    transform.Rotate (0, 0, 90);
                                    t2 = 0;
                                }
                            } else {
                                transform.Rotate (0, 0, 90);
                                t2 = 0;
                            }
                        }
                    }
                }
            }
        }
    }

    bool CheckIsValidPosition ()
    {

        foreach (Transform mino in transform) {
            Vector2 pos = FindObjectOfType<Game> ().Round (mino.position);
            if (FindObjectOfType<Game> ().CheckIsInsideGrid (pos) == false) {
                return false;
            }
            if (FindObjectOfType<Game> ().GetTransformAtGridPosition (pos) != null && FindObjectOfType<Game> ().GetTransformAtGridPosition (pos).parent != transform) {
                return false;
            }
        }
        return true;
    }
}


game.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class Game : MonoBehaviour {

    public static int gridWidth = 10;
    public static int gridHeight = 20;
    public static bool [] Judege = new bool[7]{true,true,true,true,true,true,true};
    int CountA,count;
    public static Transform[,] grid = new Transform[gridWidth,gridHeight];

    void Start () {
        SpownNextTetrimino ();  
    }
    public bool CheckIsAboveGrid (Tetrimino tetrimino){
        for (int x = 0; x < gridWidth; ++x) {
            foreach (Transform mino in tetrimino.transform) {
                Vector2 pos = Round (mino.position);
                if (pos.y > gridHeight - 1) {
                    return true;
                }
            }
        }
        return false;
    }

    public bool IsFullRowAt (int y){
        for (int x = 0; x < gridWidth; ++x) {
            if (grid [x, y] == null) {
                return false;
            }
        }
        return true;
    }

    public void DeleateMinoAt (int y){
        for (int x = 0; x < gridWidth; ++x) {
            Destroy (grid [x, y].gameObject);
            grid [x, y] = null;
        }
    }

    public void MoveRowDown (int y){
        for (int x = 0; x < gridWidth; ++x) {
            if (grid [x, y] != null) {
                grid [x, y - 1] = grid [x, y];
                grid [x, y] = null;
                grid [x, y - 1].position += new Vector3 (0, -1, 0);
            }
        }
    }

    public void MoveAllRowsDown (int y){
        for (int i = y; i < gridHeight; ++i) {
            MoveRowDown (i);
        }
    }

    public void DeleateRow () {
        for (int y = 0; y < gridHeight; ++y) {
            if (IsFullRowAt (y)) {
                DeleateMinoAt (y);
                MoveAllRowsDown (y + 1);
                --y;
            }
        }
    }

    public void UpdateGrid (Tetrimino tetrimino){
        for (int y = 0; y < gridHeight; ++y) {
            for (int x = 0; x < gridWidth; ++x) {
                if(grid[x,y] != null){
                if (grid [x, y].parent == tetrimino.transform) {
                        grid [x, y] = null;
                    }
                }
            }
        }
        foreach (Transform mino in tetrimino.transform) {
            Vector2 pos = Round (mino.position);
            if (pos.y < gridHeight) {
                grid [(int)pos.x, (int)pos.y] = mino;
            }
        }
    }

    public Transform GetTransformAtGridPosition(Vector2 pos){
        if (pos.y > gridHeight - 1) {
            return null;
        } else {
            return grid [(int)pos.x, (int)pos.y];
        }
    }

    public void SpownNextTetrimino () {

        GameObject nextTetrimino = (GameObject)Instantiate(Resources.Load (GetRandomTetrimino (), typeof(GameObject)), new Vector2 (5.0f, 19.0f), Quaternion.identity);

    }

    public bool CheckIsInsideGrid (Vector2 pos){

        return ((int)pos.x >= 0 && (int)pos.x < gridWidth && (int)pos.y >= 0);

    }

    public Vector2 Round (Vector2 pos){

        return new Vector2 (Mathf.Round (pos.x), Mathf.Round (pos.y));
    }

    //次に出てくるミノを計算する。

    string GetRandomTetrimino(){    
        string randomTetriminoName = "Prefabs/Tetrimino_T";
        while (true) {
            int randomTetrimino = Random.Range (1, 8);
            if (Judege [randomTetrimino - 1] == true) {
                switch (randomTetrimino) {
                case 1:
                    randomTetriminoName = "Prefabs/Tetrimino_T";
                    break;
                case 2:
                    randomTetriminoName = "Prefabs/Tetrimino_I";
                    break;
                case 3:
                    randomTetriminoName = "Prefabs/Tetrimino_O";
                    break;
                case 4:
                    randomTetriminoName = "Prefabs/Tetrimino_J";
                    break;
                case 5:
                    randomTetriminoName = "Prefabs/Tetrimino_L";
                    break;
                case 6:
                    randomTetriminoName = "Prefabs/Tetrimino_S";
                    break;
                case 7:
                    randomTetriminoName = "Prefabs/Tetrimino_Z";
                    break;
                }
                Judege [randomTetrimino - 1] = false;
                return randomTetriminoName;
            } else {
                for (count = 0; count < 7; count++) {
                    if (Judege [count] == false) {
                        CountA = CountA + 1;
                    }
                }
                if (CountA == 7) {
                    for (int i = 0; i < 7; i++) {
                        Judege [i] = true;
                    }
                } else {
                    CountA = 0;
                }
            }
        }
    } 
    public void GameOver(){

        SceneManager.LoadScene ("GameOver");
    }
}

tetrimino.csは主にテトリスのミノを回したり表示させたり動かしたりするプログラムです。
game.csはミノが揃った時に消える判定です。このコードには書いてないのですがスコア判定もここで行いました。
こんな感じで高校時代にunityでゲームをつくっていました。当時は楽しいと思う反面イライラしながら作っていました。なつかしいですね〜〜。

まとめ

どうでしたか?
高校時代に書いたソースなので綺麗なコードではないですが動いていたので多めに見いていただけると嬉しいです。

今回書く予定だった「Rustでwhitespace変換器作ってみた」は次回書きますのでおたのしみに。

ではでは。。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした