자바(Java)/어플(앱) 만들기

테트리스 게임 만들기

공.대.남 2019. 6. 15. 20:26
반응형

자, 우리 테트리스 게임을 만들어 보자! Unity Hub를 사용하여 새로운 Unity Project를 만듭니다. 첫째, 우리는 그것을 저장할 디렉토리를 선택하고, 2D Unity 게임 템플릿을 선택하고 생성을 클릭 합니다. 이 스크린 샷은 Unity Hub 2.x가 설치된 Windows PC에서 촬영 한 것입니다. Unity Hub가 아래에 표시된 스크린 샷과 다르게 보이면 그에 맞게 조정하십시오.

Hierarchy 에서 Main Camera  선택하면 배경색을 검정색으로 설정 하고 다음 그림과 같이 Size  Position을 조정할 수 있습니다 .

참고 : 카메라가 X = 4.5에 있어야합니다. 나중에이 장면이 우리 장면의 중심이 될 것이기 때문입니다.

블록 및 그룹 정보

우리가 무엇을 말하고 있는지 알 수 있도록 몇 가지 정의를합시다. 우리는 블록  그룹 을 가질 것 입니다. 그룹에는 원래 게임에서 "테트 로미노"라고도 알려진 몇 개의 블록이 포함되지만 기억하기 쉽도록 간단히 블록이라고 부릅니다.

Tetris에는 I , J , L , O , S , T  Z 블록  같은 여러 유형의 블록이 있습니다 .

게임 아트 만들기

위의 이미지에서 볼 수 있듯이 우리는 예술 스타일을 단순하게 유지할 것입니다. 모든 그룹은 초록색 둥근 사각형이있는 블록 유형 하나만으로 만들 수 있습니다. 


참고 : 이미지를 마우스 오른쪽 버튼으로 클릭하고 다른 이름으로 저장 ...을 선택한 다음 프로젝트의 에셋 폴더에 저장합니다.

프로젝트 영역 에서 블록 이미지를 선택한 다음 Inspector 에서 가져 오기 설정을 조정하십시오 .

참고 : Pixels to Units 속성은 게임의 크기를 지정합니다.

경계에 하나의 자산을 더 사용하여 플레이어에게 시각적 보조물을 제공합니다. 


참고 : 이미지를 마우스 오른쪽 단추로 클릭하고 다른 이름으로 저장 ...을선택한 다음 프로젝트의 자산 폴더에 저장합니다.

테두리에 대해 다음 가져 오기 설정을 사용합니다.

테두리 추가

좋아, 우리는 게임 아트의 모든 설정이 지금, 우리는 드래그 할 수 경계 로부터 프로젝트 영역  계층 구조를 두 번 :

우리의 구현에서 테트리스 장면은 정확히 10 블록 너비이고 약 20 정도 정도입니다. 따라서 블록의 좌표는 항상 (0, 0)  (9, 19) 사이에 있습니다.

참고 : 계산하면 가로 10 단위, 세로 20 단위, 0부터 시작합니다.

이제 국경은 게임의 왼쪽과 오른쪽에 있어야합니다. 그래서 그들 중 하나는 X = 0에 있고 다른 하나는 X = 9에있을 것 입니다. 간격을 추가하는 것도 좋은 생각입니다. 계층 구조 에서 한 테두리를 선택 하고 위치와 눈금을 아래와 같이 조정하십시오.

 

재생 을 누르면 테두리가 어떻게 생겼는지 보여줍니다 .

그룹 만들기

이제 I , J , L , O , S , T  Z 그룹 을 만들 차례 입니다. 좀 더 정확히 말하자면 각각 하나의 Prefab  원합니다 .

우리는 상단 메뉴에서 GameObject -> Create Empty  선택하여 빈 GameObject를 생성하는 것으로 시작 합니다. 이렇게하면 빈 GameObject가 계층 구조에 추가됩니다.

블록 이미지를 빈 GameObject로 4 번 드래그하여 4 개의 블록을 자식으로 만들 수 있습니다.

이제 트릭은 블록을 배치하여 O 그룹 이되도록하는 것입니다 .

다음은 네 개의 블록에 대해 사용한 좌표입니다. 첫 번째 GameObject에서 시작하여 차례대로 진행하십시오.

  • X = 0 Y = 0
  • X = 0 Y = 1
  • X = 1 Y = 0
  • X = 1 Y = 1

참고 : 테트리스는 2D이기 때문에 Z 축에 대해 걱정하지 않아도됩니다. 이것이 위의 위치에 Z  이없는 이유 입니다.

블록 크기가 항상 정확한 1x1 이고 블록이 항상 1 단위 씩 이동 하기 때문에 1.1 대신 1 과 같은 반올림 된 좌표를 사용하는 것이 중요합니다 . 따라서 1.1  같은 블록 크기를 사용 하고 1 만큼 이동하면 다른 블록 내부에있을 수있는 2.1 과 같은 좌표로 끝납니다 .

또는 다른 말로하면, 우리는 둥근 좌표를 사용하는 한 괜찮을 것입니다.

좋아, Inspector 에서 GameObject를 GroupO  바꾸자 . GameObject를 선택하고 Windows에서 F2를 눌러 이름 바꾸기를 하거나 마우스 오른쪽 버튼을 클릭하고 나타나는 팝업 메뉴에서 이름 바꾸기  선택하면 됩니다. 이것은 Hierarchy 에서 다음과 같이 보입니다 .

이제 ProjectArea 로 드래그 하여 프리 팹 을 만들 수 있습니다 .

우리는에 필요하지 않은 계층 구조 이상, 그래서 우리는 할 수 있습니다 삭제 계층 구조에서 그것을 선택하고 눌러서 삭제 우리의 키보드 또는 마우스 오른쪽 클릭에 키를 나타나는 팝업 메뉴에서 삭제를 선택.

나머지 그룹에 대해서도 동일한 작업 흐름을 반복합니다.

Tetromino Spawner

다른 빈 GameObject를 만들고 Spawner 라는 이름을 붙이고 Scene의 맨 위에 위치 시키십시오.

Spawner는 필요할 때 임의의 그룹을 생성하는 spawnNext 함수를 제공 합니다. Project Area 에서 마우스 오른쪽 버튼을 클릭하고 Create -> C # Script를 선택 하고 Spawner 라고 이름을 지어 봅시다 . 먼저 모든 그룹을 나중에 Inspector로 드래그 할 수 있는 public GameObject [] 배열을 추가합니다 .

using UnityEngine;
using System.Collections;

public class Spawner : MonoBehaviour {

    // Groups
    public GameObject[] groups;
}

참고 : 배열이란 하나뿐 아니라 GameObjects 전체를 의미합니다.

이제 우리는 instantiate 를 사용하여 groups 배열 에서 무작위 요소를 선택하고 그것을 세계에 던지는 spawnNext 함수를 만들 수 있습니다 :

public void spawnNext() {
    // Random Index
    int i = Random.Range(0, groups.Length);

    // Spawn Group at current Position
    Instantiate(groups[i],
                transform.position,
                Quaternion.identity);
}

참고 : transform.position은 Spawner의 위치이며, Quaternion.identity가 기본 회전입니다.

Spawner는 게임이 시작 되 자마자 임의의 그룹을 생성해야합니다. 이것은 무엇을 시작 기능을위한 것입니다 :

void Start() {
    // Spawn initial Group
    spawnNext();
}

참고 : 시작 기능은 게임 장면이로드되고 Spawner 스크립트가 시작될 때 Unity에 의해 자동으로 호출됩니다.

여태까지는 그런대로 잘됐다. 의이 선택할 수 Spawner를을  계층 구조다음을 클릭 추가 구성 요소 > - 스크립트 -> Spawner를  경위 . 그 다음 프로젝트 영역의 그룹을 그룹 슬롯 으로 드래그 합니다.

Play  누르면 Spawner가 첫 번째 그룹을 어떻게 생성하는지 볼 수 있습니다.

플레이 필드 클래스

자극

오리지날 Tetris 게임에서 볼 수있는 나머지 게임 플레이 기능을 구현하려면 다음과 같은 몇 가지 도우미 기능이 필요합니다.

  • 모든 블록이 테두리 사이에 있는지 확인하십시오.
  • 모든 블록이 y = 0 위에 있는지 확인하십시오.
  • 그룹이 특정 위치로 이동할 수 있는지 확인하십시오.
  • 행이 블록으로 가득 차 있는지 확인하십시오.
  • 행 삭제
  • 행의 y 좌표를 줄입니다.

Unity에서 다른 블록으로 물건을 확인 하는 확실한 방법은 FindGameObjectsWithTag 를 사용하는  입니다. 성능 문제 외에도이 기능의 주요 문제점은 주어진 위치에 블록이 있는지를 실제로 확인할 수 없다는 것입니다. 대신 우리는 항상 모든 블록을 반복하고 위치를 확인해야합니다.

데이터 구조

이 문제를 해결하는 솔루션은 그리드 를 구현하는 것입니다. 즉, 2 차원 배열 (또는 행렬)입니다. 학교에서 수학 수업을 들었을 수도 있습니다. 데이터 구조는 다음과 매우 유사합니다.

___|_0_|_1_|_2_|...
 0 | o | x | x |...
 1 | o | x | o |...
 2 | x | x | o |...
...|...|...|...|...

X는 블록이 있다는 의미의 O는 어떤 블록이 없다는 것을 의미한다. 따라서 좌표 (0,0) 에는 블록이없고, (0,1) 에는 블록 등이 있습니다.

다음은 특정 위치의 블록에 얼마나 쉽게 접근 할 수 있는지입니다.

// Is there a block at (3,4)?
if (grid[3,4] != null) {
    // Do Stuff...
}

이제 우리는 우리 문제에 대한 해답을 알고 있습니다. 불행하게도 새로운 스크립트 그리드를 호출 하면 같은 이름의 내부 Unity 클래스와 충돌이 발생할 수 있습니다. 이제 C # 스크립트를 새로 만들고 Playfield 라는 이름을 지정해 보겠습니다 . 그리드 자체와 그리드와 함께 작업 할 수있는 몇 가지 유용한 기능을 저장합니다. 다음은 C #에서 2 차원 배열을 정의하는 방법입니다.

Playfield 스크립트 만들기

using UnityEngine;
using System.Collections;

public class Playfield : MonoBehaviour {
    // The Grid itself
    public static int w = 10;
    public static int h = 20;
    public static Transform[,] grid = new Transform[w, h];
}

진정해? 그리드는 GameObject 유형일 수도 있지만, Transform 유형으로 만듦으로써 우리는 항상 무언가  변환 할 필요가 없습니다 . 모든 GameObject에는 Transform이 있기 때문에 정상적으로 작동합니다.

roundVec2 도우미 함수

우리의 첫 번째 도우미 함수는 것이다 라운드 벡터를. 예를 들어, (1.0001, 2) 와 같은 벡터  (1, 2)가 됩니다. 회전으로 인해 좌표가 더 이상 둥글지 않을 수 있기 때문에이 함수가 필요합니다. 어쨌든, 여기에 함수가 있습니다 :

public static Vector2 roundVec2(Vector2 v) {
    return new Vector2(Mathf.Round(v.x),
                       Mathf.Round(v.y));
}

참고 : 공용 정적 함수는 다른 스크립트에서도 액세스 할 수 있습니다. 헬퍼 / 유틸리티 기능에 매우 유용합니다.

insideBorder 헬퍼 함수

다음 기능은 아주 쉽습니다. 국경 사이에 특정 좌표가 있는지 또는 국경 밖에 있는지 알아 보는 데 도움이됩니다.

public static bool insideBorder(Vector2 pos) {
    return ((int)pos.x >= 0 &&
            (int)pos.x < w &&
            (int)pos.y >= 0);
}

0 과 격자 폭 w 사이에 있어야 하는 x 위치를 먼저 테스트 한  y 위치가 여전히 양수인지를 확인합니다.

참고 : 그룹이 실제로는 위쪽으로 이동하지 않기 때문에 pos.y <h 인지 확인하지 않습니다 . 일부 회전은 예외입니다.

deleteRow 도우미 함수

다음 함수는 특정 행의 모든 ​​블록을 삭제합니다. 플레이어가 연속으로 모든 항목을 채우는 것이 도움이 될 때 유용합니다 (삭제되는 경우).

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

이 함수는 playfield에서 삭제되어야하는 행인 y 매개 변수를 사용합니다. 그런 다음 해당 행의 모든 ​​블록을 반복 하고 게임에서 Destroy를 삭제하고 표 항목을 null 로 설정하여 참조를 지 웁니다 .

reduceRow 헬퍼 함수

행이 삭제 될 때마다 위의 행은 한 단위로 아래쪽으로 떨어집니다. 다음 함수는이를 처리합니다.

public static void decreaseRow(int y) {
    for (int x = 0; x < w; ++x) {
        if (grid[x, y] != null) {
            // Move one towards bottom
            grid[x, y-1] = grid[x, y];
            grid[x, y] = null;

            // Update Block position
            grid[x, y-1].position += new Vector3(0, -1, 0);
        }
    }
}

앞의 함수와 마찬가지로이 함수는 행의 y 값을 매개 변수로 사용하여 for루프 내의 해당 행에있는 모든 블록을 통과 한 다음 한 단위를 맨 아래로 이동합니다. 그러나 여기서 우리가 염두에 두어야 할 것은 블록의 세계 위치를 업데이트해야한다는 것입니다. 그렇지 않으면 블록이 올바른 그리드 항목에 할당되지만 게임 세계의 이전 위치에있는 것처럼 보이기 때문에 원치 않는 시각적 결함이 발생합니다.

블록의 월드 위치는 Vector (0, -1, 0)  추가하여 수정됩니다 . 즉, 블록  y 좌표를 1 줄입니다.

reduceRowsAbove 함수

다음 함수는 이전의 reduceRow 함수를 사용하여 행이 삭제 될 때마다 하나가 아닌 모든  을 줄이기 때문에 특정 인덱스 위의 모든 행에서 사용합니다 .

public static void decreaseRowsAbove(int y) {
    for (int i = y; i < h; ++i)
        decreaseRow(i);
}

이전과 마찬가지로 함수는 행인 y 매개 변수를 사용 합니다. 그런 다음 사용하여 모든 행을 상기 루프 I가 , 시작 Y 하면서 반복 난 H를 < (즉, 우리는 루프 상태  보다 작은 시간 ).

isRowFull 함수

이전에 행이 블록으로 가득 찼을 때 삭제되어야한다고 언급했습니다. 그럼 바로 그 부분으로 넘어 가서 행이 블록으로 가득 차 있는지를 알아내는 함수를 만듭니다.

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

이 기능은 다소 쉽습니다. 행 매개 변수 y 를 사용하여 모든 모눈 항목을 반복하고 모눈 항목에 블록이 없으면 false  반환합니다 . for 루프가 끝나고 여전히 false를 반환하지 않으면 행은 블록으로 가득 차 있어야하며,이 경우 우리 는 true  반환합니다 .

deleteFullRows 함수

이제 모든 것을 정리하고 모든 전체 행 을 삭제 하고 항상 위 행의 y 좌표를 1 씩 줄이는 함수를 작성해야합니다 . 우리가 도우미 기능을 모두 갖췄으니 이제는 더 이상 힘들지 않습니다.

public static void deleteFullRows() {
    for (int y = 0; y < h; ++y) {
        if (isRowFull(y)) {
            deleteRow(y);
            decreaseRowsAbove(y+1);
            --y;
        }
    }
}

참고 --y 감소 Y를 행이 삭제 될 때마다 하나씩. for 루프의 다음 단계가 올바른 인덱스에서 계속되는지 확인하는 것입니다. 행을 삭제했기 때문에 하나씩 줄여야합니다.

그리드 클래스에 필요한 모든 것입니다. 우리가 여기서 한 것은 Bottom-Up Programming 입니다. 우리는 가장 쉬운 기능으로 시작하여 이전에 생성 된 기능을 사용하는 점점 더 많은 기능을 만들었습니다.

이 개발 기법의 이점은 우리의 마음 속에 너무 많은 역 추적을 할 필요가 없기 때문에 우리 삶을 좀 더 쉽게 만들어 준다는 것입니다.

그룹 스크립트

스크립트 만들기

마침내 Unity Tetris 클론에 게임 플레이를 추가 할 때입니다. 새로운 C # 스크립트를 만들고 이름을 지정해 봅시다 . Group :

using UnityEngine;
using System.Collections;

public class Group : MonoBehaviour {

    // Use this for initialization
    void Start () {
    
    }
    
    // Update is called once per frame
    void Update () {
    
    }
}

도우미 함수 만들기

처음에는 두 가지 더 많은 헬퍼 함수를 ​​추가 할 것입니다. 하나의 GameObject에 여러 블록을 넣고 그룹이라고 부르는 것을 기억하십니까? 각 하위 블록의 위치를 ​​확인하는 데 도움이되는 함수가 필요합니다.

bool isValidGridPos() {        
    foreach (Transform child in transform) {
        Vector2 v = Playfield.roundVec2(child.position);

        // Not inside Border?
        if (!Playfield.insideBorder(v))
            return false;

        // Block in grid cell (and not part of same group)?
        if (Playfield.grid[(int)v.x, (int)v.y] != null &&
            Playfield.grid[(int)v.x, (int)v.y].parent != transform)
            return false;
    }
    return true;
}

이 기능은 이해하기 쉽습니다. 처음에 foreach 를 사용하여 모든 자식을 반복 한 다음 변수에 둥근 위치를 저장합니다. 그 다음에는 해당 위치가 경계 안에 있는지 알아 낸 다음 동일한 격자 항목에 이미 블록이 있는지 알아냅니다.

우리가 너무 많이 나아 가기 전에, 우리가 여기에서 돌봐야 할 한 가지 경우가 있습니다. 같은 그룹 내의 블록간에 교차를 허용하여 일부 순환 게재 및 번역이 유효하지 않은 것으로 확인되지 않도록해야 합니다. 예를 들어 I그룹이 하나의 유닛을 아래쪽으로 이동하면 그 그룹 내의 대부분의 블록은 아래 그림과 같이 서로 교차합니다. 여기서 a 는 첫 번째 위치이고 b 는 두 번째 위치입니다.

a
a b <- intersection
a b <- intersection
a b <- intersection 
  b

위에서처럼 블록의 부모 Transform과 현재 변환 을 비교하여 이러한 종류의 교차를 피할 수 있습니다 .

자, 마지막 헬퍼 함수를 ​​만들어 보자. 그룹의 위치가 변경된 경우 그리드에서 모든 이전 블록 위치를 제거하고 모든 새 블록 위치를 그리드에 추가해야합니다.

void updateGrid() {
    // Remove old children from grid
    for (int y = 0; y < Playfield.h; ++y)
        for (int x = 0; x < Playfield.w; ++x)
            if (Playfield.grid[x, y] != null)
                if (Playfield.grid[x, y].parent == transform)
                    Playfield.grid[x, y] = null;

    // Add new children to grid
    foreach (Transform child in transform) {
        Vector2 v = Playfield.roundVec2(child.position);
        Playfield.grid[(int)v.x, (int)v.y] = child;
    }        
}

이전에 여러 번했듯이, 우리는 그리드를 반복 한 다음 블록 (있는 경우)이 상위 속성 을 사용하여 그룹의 일부인지 확인 했습니다. 블록의 부모가 현재 그룹의 변환과 같으면 해당 그룹의 하위입니다. 그런 다음 모든 자식을 다시 반복하여 격자에 추가합니다.

이동 및 추락

자, 이제 우리는 몇 가지 게임 플레이를 추가 할 수 있습니다. 곧 그것은 모두 의미가있을 것입니다 ...

왼쪽 화살표 키로 시작하여 키 누름을 확인하도록 업데이트 기능을 수정합니다.

void Update() {
    // Move Left
    if (Input.GetKeyDown(KeyCode.LeftArrow)) {
        // Modify position
        transform.position += new Vector3(-1, 0, 0);
        
        // See if it's valid
        if (isValidGridPos())
            // It's valid. Update grid.
            updateGrid();
        else
            // Its not valid. revert.
            transform.position += new Vector3(1, 0, 0);
    }
}

이것은 우리의 도우미 기능이 모두 도움이되는 곳입니다. 그룹을 왼쪽으로 이동시키기 위해해야 ​​할 일은 다음과 같습니다.

  • 키 누름을 기다리다
  • 그것을 왼쪽으로 옮기다.
  • 그 위치가 여전히 유효한지 알아 내라.
    • 그렇다면 새 위치로 그리드를 업데이트하십시오.
    • 그렇지 않다면 오른쪽으로 다시 이동하십시오.

다음은 우리가 오른쪽으로 이동할 수있는 방법입니다.

// Move Right
else if (Input.GetKeyDown(KeyCode.RightArrow)) {
    // Modify position
    transform.position += new Vector3(1, 0, 0);
    
    // See if valid
    if (isValidGridPos())
        // It's valid. Update grid.
        updateGrid();
    else
        // It's not valid. revert.
        transform.position += new Vector3(-1, 0, 0);
}

다음은 우리가 회전하는 방법입니다.

// Rotate
else if (Input.GetKeyDown(KeyCode.UpArrow)) {
    transform.Rotate(0, 0, -90);
    
    // See if valid
    if (isValidGridPos())
        // It's valid. Update grid.
        updateGrid();
    else
        // It's not valid. revert.
        transform.Rotate(0, 0, 90);
}

어떻게 항상 똑같은 작업 흐름인지 확인하십시오.

그리고 아래쪽으로 어떻게 움직일 수 있을까요?

// Fall
else if (Input.GetKeyDown(KeyCode.DownArrow)) {
    // Modify position
    transform.position += new Vector3(0, -1, 0);

    // See if valid
    if (isValidGridPos()) {
        // It's valid. Update grid.
        updateGrid();
    } else {
        // It's not valid. revert.
        transform.position += new Vector3(0, 1, 0);

        // Clear filled horizontal lines
        Playfield.deleteFullRows();

        // Spawn next Group
        FindObjectOfType<Spawner>().spawnNext();

        // Disable script
        enabled = false;
    }
}

이번에는 더 많은 일이 일어나고 있습니다. 블록을 아래쪽으로 이동 시켰을 때 새로운 위치가 더 이상 유효하지 않으면 이동을 비활성화하고 모든 전체 행을 삭제하고 다음 블록 그룹을 생성해야합니다. 우리는 모든 것을 도우미 기능을 가지고 있기 때문에 모든 것이 짧고 쉽습니다.

그룹은 자동으로 1 초에 한 번씩 아래로 내려와야합니다. 마지막 낙하 시간을 추적하는 변수를 먼저 생성하여이 작업을 수행 할 수 있습니다.

// Time since last gravity tick
float lastFall = 0;

그리고 플레이어가 아래쪽 화살표 버튼을 눌렀을 때가 아니라 1 초에 한 번 트리거되도록 아래쪽 이동 기능  수정 합니다.

// Move Downwards and Fall
else if (Input.GetKeyDown(KeyCode.DownArrow) ||
         Time.time - lastFall >= 1) {
    // Modify position
    transform.position += new Vector3(0, -1, 0);

    // See if valid
    if (isValidGridPos()) {
        // It's valid. Update grid.
        updateGrid();
    } else {
        // It's not valid. revert.
        transform.position += new Vector3(0, 1, 0);

        // Clear filled horizontal lines
        Playfield.deleteFullRows();

        // Spawn next Group
        FindObjectOfType<Spawner>().spawnNext();

        // Disable script
        enabled = false;
    }

    lastFall = Time.time;
}

다음은 그룹 스크립트 의 최종 업데이트 기능입니다.

void Update() {
    // Move Left
    if (Input.GetKeyDown(KeyCode.LeftArrow)) {
        // Modify position
        transform.position += new Vector3(-1, 0, 0);
        
        // See if valid
        if (isValidGridPos())
            // It's valid. Update grid.
            updateGrid();
        else
            // It's not valid. revert.
            transform.position += new Vector3(1, 0, 0);
    }

    // Move Right
    else if (Input.GetKeyDown(KeyCode.RightArrow)) {
        // Modify position
        transform.position += new Vector3(1, 0, 0);
        
        // See if valid
        if (isValidGridPos())
            // It's valid. Update grid.
            updateGrid();
        else
            // It's not valid. revert.
            transform.position += new Vector3(-1, 0, 0);
    }

    // Rotate
    else if (Input.GetKeyDown(KeyCode.UpArrow)) {
        transform.Rotate(0, 0, -90);
        
        // See if valid
        if (isValidGridPos())
            // It's valid. Update grid.
            updateGrid();
        else
            // It's not valid. revert.
            transform.Rotate(0, 0, 90);
    }

    // Move Downwards and Fall
    else if (Input.GetKeyDown(KeyCode.DownArrow) ||
             Time.time - lastFall >= 1) {
        // Modify position
        transform.position += new Vector3(0, -1, 0);

        // See if valid
        if (isValidGridPos()) {
            // It's valid. Update grid.
            updateGrid();
        } else {
            // It's not valid. revert.
            transform.position += new Vector3(0, 1, 0);

            // Clear filled horizontal lines
            Playfield.deleteFullRows();

            // Spawn next Group
            FindObjectOfType<Spawner>().spawnNext();

            // Disable script
            enabled = false;
        }

        lastFall = Time.time;
    }
}

정말 쉽습니다!

우리가주의해야 할 것이 하나 더 있습니다. 새로운 그룹이 생성되어 즉시 다른 그룹과 충돌하면 게임이 종료됩니다.

void Start() {
    // Default position not valid? Then it's game over
    if (!isValidGridPos()) {
        Debug.Log("GAME OVER");
        Destroy(gameObject);
    }
}

거의 끝났어. Project Area 에서 만든 각 조립식에 대해 조립품 을 클릭하고 Inspector 에서 "Open Prefab"버튼을 클릭하십시오 . 아래의 스크린 샷을 참조하십시오.


이 목록에서 첫 번째 그룹 스크립트를 선택하거나 스크립트 -> 그룹 에서 찾을 수 있습니다 . 조립식 검사관에 나타납니다.

마지막으로 뒤로 화살표를 클릭하면이 프리 팹 편집기 모드가 종료됩니다. 조립식 변경 사항은 자동으로 저장됩니다.

참고 : 우리가 만든 다른 모든 블록 조립식에 대해 이것을 반복해야합니다. 그렇지 않으면 연주 시간에 오류가 발생합니다.

우리가 플레이를 누르면 우리는 이제 테트리스의 멋진 라운드를 즐길 수 있습니다 :

728x90
반응형