Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

More than 3 years have passed since last update.

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

Last updated at Posted at 2019-12-11

こちらは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変換器作ってみた」は次回書きますのでおたのしみに。

ではでは。。

0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?