본문 바로가기
Development/C#

[멋쟁이사자처럼 부트캠프 TIL 회고] Unity 게임 개발 3기 9일차

by Mobics 2024. 11. 30.

 

목차


    [실습] Flappy Bird 2D_02

    Title 꾸미기

    : 폰트의 Material 수정하기

    Button

    : Image + Button + Text

     

    >> 만드는 법

     

    >> 버튼 크기 조절

    : Scale 말고 Width와 Height로 하기

     

    >> 버튼에 이미지 넣고 해상도 맞추기

    Set Native Size : Image 해상도 맞추기

    만든 Intro를 하나로 그룹화 하기

    : Intro UI 안에 자식으로 Image, Title, Button 넣기 --> UI는 Hierarchy에 있는 순서가 중요

    >> Start를 눌렀을 때 한꺼번에 Off하기 위해

     

    ※ 그룹화 및 Anchor, Position 설정

    UI를 그리는 Object Canvas Create Empty하면 자동으로 UIGameObject가 만들어짐 --> Transform Rect Transform으로 생긴 모습 / Button도 마찬가지

     

    OnClick()

    : Button을 눌렀을 때의 기능

     

    >> IntroUI 끄게 만들기

     

    Main

    Background 추가 및 배경 무한 루프 만들기

    1. Project에서 Hierarchy로 Background 파일 드래그하여 추가

    2. Camera 설정 --> 거리감 없애기

    3. Background를 총 4장 만들어서 X Position 변경

    >> 각각 -8, -2, 4, 10

    ※ Sprite는 Hierarchy에 있는 순서가 중요하지 않음

     

    Order in Layer : 그리는 순서 --> 0부터 순서대로 그림, 따라서 Bird 1로 설정하면 Bird를 나중에 그리기 때문에 배경 앞에 나타남

     

    4. Script 작성

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class LoopMap : MonoBehaviour
    {
        private SpriteRenderer sp;
        public float offsetSpeed = 0.5f; // Map이 움직이는 속도
    
        void Start()
        {
            sp = GetComponent<SpriteRenderer>();
            // sp가 private라 Inspector에서 넣어줄 수 없기 때문에 선언
        }
    
        void Update()
        {
            float offsetVal = offsetSpeed * Time.deltaTime;
            sp.material.SetTextureOffset("_MainTex", sp.material.mainTextureOffset + new Vector2(offsetVal, 0f));
            // material에 있는 shader에 접근해서 offset을 변경
        }
    }

    ※ offset : Image의 기준점

     

    5. Material 수정

    : 기존 background에 있는 material은 수정이 불가능하기 때문에, 새로 material 생성

    >> 3D가 아니기 때문에, shaderUnlit – Texture로 수정 후, 오른쪽 빈 칸에 background image 추가

     

    6. 배치한 Background에 만든 material 적용 및 Script 추가

    Bird 구현

    1. Character Animation 추가

    >> Animation 창으로 가서 보면 상세하게 볼 수 있음

     

    2. Bird에 Rigidbody 2D 넣기

     

    3. Script 작성 --> Space Bar를 눌렀을 때, 위로 날아오르는 기능

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
     
    public class BirdMovement : MonoBehaviour
    {
        private Rigidbody2D myRigid;
        public float flyPower = 10f;
      
        void Start()
        {
            myRigid = GetComponent<Rigidbody2D>();
        }
     
        void Update()
        {
            if (Input.GetKeyDown(KeyCode.Space))
            {
                myRigid.AddForce(Vector2.up * flyPower, ForceMode2D.Impulse); // 위쪽으로 힘을 가함
            }
        }
    }

     

    4. Bird에 Script 추가

     

    5. Space를 연속으로 누르면 가하는 힘이 중첩되어 높게 튀어오르는 문제 해결

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
     
    public class BirdMovement : MonoBehaviour
    {
        private Rigidbody2D myRigid;
        public float flyPower = 10f;
     
        public float limitSpeed = 5f;
     
        void Start()
        {
            myRigid = GetComponent<Rigidbody2D>();
        }
     
        void Update()
        {
            if (Input.GetKeyDown(KeyCode.Space))
            {
                myRigid.AddForce(Vector2.up * flyPower, ForceMode2D.Impulse); // 위쪽으로 힘을 가함
                
                // 속도 체크
                if (myRigid.velocity.y > limitSpeed) // 새의 y축 속도가 제한 속도보다 큰가?
                {
                    // 속도 재조정
                    myRigid.velocity = new Vector2(myRigid.velocity.x, limitSpeed);
                }
            }
        }
    }

     

    Pipe 제작

    1. Project에서 Pipe Hierarchy에 끌어오기 --> Position 수정 (X : 10, Y : -2)

     

    2. Pipe 이동시키는 Script 작성

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
     
    public class RandomPipe : MonoBehaviour
    {
        public GameObject pipe;
        public float pipeSpeed = 5f;
     
        void Update()
        {
            pipe.transform.position -= pipeSpeed * Time.deltaTime * Vector3.right;
        }
    }

     

    3. Pipe Object에 Script 넣고 Pipe 할당

     

    4. Pipe의 충돌/감지를 위해 Script 작성

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
     
    public class PipeEvent : MonoBehaviour
    {
        public void OnTriggerEnter2D(Collider2D collision)
        {
            if (collision.CompareTag("Player"))
            {
                Debug.Log("Game Over");
            }
        }
    }

    >> 이후 Bird "Player" Tag 추가

     

    ※ 코드가 작동하려면 양쪽 다 Collider가 있어야 하고 최소 한 쪽은 Rigidbody가 있어야 함

     

    5. Bird Circle Collider 2D 추가

    Circle Collider : 2D에서 가장 최적화된 Collider

    3D에서는 Box Collider가 가장 최적화됨

     

    6. Pipe Box Collider 2D 추가 및 Is Trigger 체크 그리고 Script 추가

     

    End UI 제작

    1. UI Object 만들기 --> Canvas 우클릭 – Create Empty --> Anchor Position 수정

     

    2. Image 2개 생성

    >> 순서 매우 중요

     

    3. [Image]Background의 Anchor Position 수정하고, Color에서 Alpha 0으로 수정 및 검은색으로 변경

     

    4. [Image]GameOver에 GameOver Image 삽입 후 Set Native Size

     

    5. End UI를 선택하여 애니메이션 생성

     

    6. 녹화 버튼 누르고 1:00 선택 후, [Image]Background 선택하여 Color Alpha 255로 수정한 뒤 녹화 종료

     

    7. 다시 녹화 버튼 누르고 GameOver를 선택하고 0:00으로 옮긴 뒤, Scale 0, 0, 0으로 수정, 다음으로 1:00으로 옮긴 뒤, Scale 2, 2, 2로 변경한 뒤 녹화 종료

     

    8. Fade in이 먼저 되고 글씨가 나오게 하기 --> dope 옮기기

     

    너무 빠르면 전체 선택한 뒤 늘려주기

     

    9. Project의 Animation으로 가서 GameOver Loop 끄기

     

    10. Pipe에 부딪혔을 때 End UI 실행되게 하기

    : Script 수정 후 End UI 할당 (End UI Active 끄기)

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
     
    public class PipeEvent : MonoBehaviour
    {
        public GameObject endUI;
        public void OnTriggerEnter2D(Collider2D collision)
        {
            if (collision.CompareTag("Player"))
            {
                endUI.SetActive(true); // End UI가 켜지는 기능
                Debug.Log("Game Over");
            }
        }
    }

     

    Main 세팅

    1. 우선 Main Active 끄고 Intro Active 켜기

    2. Intro에서 GameStart를 눌러야 Main이 실행되도록 Intro에 있는 Button에서 OnClick()에 하나 더 추가하고 Main 넣고 GameObject -SetActive 체크하기


    Pipe를 랜덤으로 생성하기 위해 Code 배우기

    배열과 List

    • 배열 : 개수가 바뀌지 않을 때 사용
    • List : 개수가 바뀔 때 사용

    Indexer

    : 순서로 접근할 수 있는 방법 --> 0부터 시작


    Pipe 구현

    1. Pipe가 하나 밖에 없어서 이전처럼 만든 것, 다시 'Pipe'의 Inpector에서 'Random Pipe' Script 삭제

     

    2. Pipe 복사해서 위에도 배치

    : Y Position 수정

    >> Flip 기능 활용해서 뒤집기

     

    3. Pipe 두개를 중간으로 배치 후, Main을 우클릭하여 Create Empty, Group을 만들어 묶고 거기에 'RandomPipe' Script 추가

     

    4. RandomPipe Script 수정

    >> GameObject를 배열로 변경

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
     
    public class RandomPipe : MonoBehaviour
    {
        public GameObject[] pipes; //GameObject 배열
        public float pipeSpeed = 5f;
     
        void Update()
        {
            pipes[0].transform.position -= pipeSpeed * Time.deltaTime * Vector3.right;
            pipes[1].transform.position -= pipeSpeed * Time.deltaTime * Vector3.right;
        }
    }

     

    5. Pipe Group Inspector에서 Pipe 할당

     

    6. Script에 Enum 추가 (PIPE_TYPE)

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
     
    public class RandomPipe : MonoBehaviour
    {
        public enum PIPE_TYPE { TOP, BOTTOM, ALL } // pipe가 랜덤하게 켜질 때, 경우의 수
        public PIPE_TYPE pipeType;
     
        public GameObject[] pipes; //GameObject 배열
        public float pipeSpeed = 5f;
     
        void Start()
        {
            // 처음 시작할 때, Pipe Type 설정
            switch (pipeType) // 수업에선 if, else if로 작성
            {
                case PIPE_TYPE.TOP:
                    pipes[0].SetActive(true);
                    pipes[1].SetActive(false);
                    break;
                case PIPE_TYPE.BOTTOM:
                    pipes[0].SetActive(false);
                    pipes[1].SetActive(true);
                    break;
                case PIPE_TYPE.ALL:
                    pipes[0].SetActive(true);
                    pipes[1].SetActive(true);
                    break;
            }
        }
     
        void Update()
        {
            pipes[0].transform.position -= pipeSpeed * Time.deltaTime * Vector3.right;
            pipes[1].transform.position -= pipeSpeed * Time.deltaTime * Vector3.right;
        }
    }

     

    7. Pipe Group을 총 4개까지 복사

    : X Position 0, 5, 10, 15 으로 설정

     

    8. Script Random 추가하여 pipeType 랜덤 설정

    • Random.Range(0, 10) --> int, 0 <= x < 10
    • Random.Range(0, 10f) --> float, 0 <= x <= 10f / 소수점 포함 7자리수까지 나옴
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
     
    public class RandomPipe : MonoBehaviour
    {
        public enum PIPE_TYPE { TOP, BOTTOM, ALL } // pipe가 랜덤하게 켜질 때, 경우의 수
        public PIPE_TYPE pipeType;
     
        public GameObject[] pipes; //GameObject 배열
        public float pipeSpeed = 5f;
     
        void Start()
        {
            // 처음 시작할 때, Pipe Type 설정
            int ranInt = Random.Range(0, 3); // 0, 1, 2 중 랜덤하게 설정
            pipeType = (PIPE_TYPE)ranInt; // 형변환하여 pipeType 설정
     
            switch (pipeType) // 수업에선 if, else if로 작성
            {
                case PIPE_TYPE.TOP:
                    pipes[0].SetActive(true);
                    pipes[1].SetActive(false);
                    break;
                case PIPE_TYPE.BOTTOM:
                    pipes[0].SetActive(false);
                    pipes[1].SetActive(true);
                    break;
                case PIPE_TYPE.ALL:
                    pipes[0].SetActive(true);
                    pipes[1].SetActive(true);
                    break;
            }
        }
     
        void Update()
        {
            pipes[0].transform.position -= pipeSpeed * Time.deltaTime * Vector3.right;
            pipes[1].transform.position -= pipeSpeed * Time.deltaTime * Vector3.right;
        }
    }

     

    9. Script로 pipe 재활용 설정 + 반복문 사용

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class RandomPipe : MonoBehaviour
    {
        public enum PIPE_TYPE { TOP, BOTTOM, ALL } // pipe가 랜덤하게 켜질 때, 경우의 수
        public PIPE_TYPE pipeType;
    
        public GameObject[] pipes; //GameObject 배열
        public float pipeSpeed = 5f;
    
        void Start()
        {
            RandomPipeType();
        }
    
        void Update()
        {
            foreach (GameObject pipe in pipes)
            {
                pipe.transform.position -= pipeSpeed * Time.deltaTime * Vector3.right;
    
                // pipes가 일정 거리 이상 벗어나면 다시 재활용 + pipeType 재설정
                if (pipe.transform.position.x <= -10f)
                {
                    RandomPipeType();
                    pipe.transform.position = new Vector3(10f, pipe.transform.position.y, pipe.transform.position.z);
                    // position의 특정 축 1개만 바꿀 수 없기 때문에 전체 다 작성하여 보내야 함
                }
            }
        }
    
        private void RandomPipeType()
        {
            // 처음 시작할 때, Pipe Type 설정
            int ranInt = Random.Range(0, 3); // 0, 1, 2 중 랜덤하게 설정
            pipeType = (PIPE_TYPE)ranInt; // 형변환하여 pipeType 설정
    
            switch (pipeType) // 수업에선 if, else if로 작성
            {
                case PIPE_TYPE.TOP:
                    pipes[0].SetActive(true);
                    pipes[1].SetActive(false);
                    break;
                case PIPE_TYPE.BOTTOM:
                    pipes[0].SetActive(false);
                    pipes[1].SetActive(true);
                    break;
                case PIPE_TYPE.ALL:
                    pipes[0].SetActive(true);
                    pipes[1].SetActive(true);
                    break;
            }
        }
    }

     

    10. pipe y position 랜덤 배치

    : Pipe Group y position 0이기 때문에 Pipe Group에 대해 Random으로 y position 설정 (지금 프로젝트 기준 최대 : 3.5 / 최소 : -1.5)

    >> 딱 정해진 것이 아니라 자유롭게 나오도록 float타입으로 Random 적용

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class RandomPipe : MonoBehaviour
    {
        public enum PIPE_TYPE { TOP, BOTTOM, ALL } // pipe가 랜덤하게 켜질 때, 경우의 수
        public PIPE_TYPE pipeType;
    
        public GameObject[] pipes; //GameObject 배열
        public float pipeSpeed = 5f;
    
        void Start()
        {
            RandomPipeType();
        }
    
        void Update()
        {
            foreach (GameObject pipe in pipes)
            {
                pipe.transform.position -= pipeSpeed * Time.deltaTime * Vector3.right;
    
                // pipes가 일정 거리 이상 벗어나면 다시 재활용 + pipeType 재설정
                if (pipe.transform.position.x <= -10f)
                {
                    RandomPipeType();
                    pipe.transform.position = new Vector3(10f, pipe.transform.position.y, pipe.transform.position.z);
                    // position의 특정 축 1개만 바꿀 수 없기 때문에 전체 다 작성하여 보내야 함
                }
            }
        }
    
        private void RandomPipeType()
        {
            // 처음 시작할 때, Pipe Type 설정
            int ranInt = Random.Range(0, 3); // 0, 1, 2 중 랜덤하게 설정
            pipeType = (PIPE_TYPE)ranInt; // 형변환하여 pipeType 설정
    
            switch (pipeType) // 수업에선 if, else if로 작성
            {
                case PIPE_TYPE.TOP:
                    pipes[0].SetActive(true);
                    pipes[1].SetActive(false);
                    break;
                case PIPE_TYPE.BOTTOM:
                    pipes[0].SetActive(false);
                    pipes[1].SetActive(true);
                    break;
                case PIPE_TYPE.ALL:
                    pipes[0].SetActive(true);
                    pipes[1].SetActive(true);
                    break;
            }
    
            // 높이를 랜덤하게 바꾸는 기능
            float ranFloat = Random.Range(-1.5f, 3.5f);
            transform.position = new Vector3(transform.position.x, ranFloat, transform.position.z);
        }
    }

     

    Audio

    : 소리 출력을 위해 필요한 3가지

    1. 스피커

    2. 헤드셋 : Camera에는 무조건 Audio Listener가 있음

    3. 음원 : Audio 파일은 Ogg 타입이 가장 최적화된 파일

    ※ 파일 클릭하자마자 바로 실행하기

     

    Audio 넣기

    1. Script를 활용하여 사운드 재생하기

    >> 헤드셋은 Camera가 알아서 할 테니, 스피커와 음원만 다루면 됨

    ※ 스피커가 하나기 때문에 음원을 바꿔도 겹치는 게 아니라 넘어감

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class SoundManager : MonoBehaviour
    {
        private AudioSource audioSource; // 스피커
        public AudioClip[] clips; // 음원
        // 0. 인트로, 1. 메인, 2. 점프, 3. 충돌
    
        void Start()
        {
            audioSource = GetComponent<AudioSource>();
    
            OnIntroBGM(); // 게임을 시작하면 어차피 Intro기 때문에 바로 시작
        }
    
        // 외부에서 사운드 함수를 실행해야함
        public void OnIntroBGM() // BGM --> 반복 실행
        {
            audioSource.clip = clips[0];
            audioSource.loop = true; // Inspector 에서도 수정 가능
            audioSource.Play();
            // Play() : 스피커가 소리파일을 잡고 실행
        }
    
        public void OnMainBGM()
        {
            audioSource.clip = clips[1];
            audioSource.loop = true;
            audioSource.Play();
        }
    
        public void OnJumpSound() // Sound --> 필요할 때 한번 실행
        {
            audioSource.PlayOneShot(clips[2]);
            // PlayOneShot() : 스피커에서 나오는 소리와 상관없이 잠깐 한번 실행 --> 노래 끊김 X
        }
    
        public void OnCollisionSound()
        {
            audioSource.PlayOneShot(clips[3]);
        }
    }

    게임을 시작하면 바로 Intro가 나오기 때문에 Start() OnIntroBGM() 추가

     

    2. 추가한 Audio Source Script 넣고 순서에 맞춰서 음원 넣기

    >> AudioClip[] 배열에 해당

     

    3. ButtonOnClick() Sound Manager 넣고 OnMainBGM 설정

    >> 버튼을 클릭하면 Main으로 넘어가기 때문에

     

    4. Jump Sound 추가

    : BirdMovement Script Sound 관련 변수 및 함수 추가, Bird Inspector에 할당

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class BirdMovement : MonoBehaviour
    {
        public SoundManager soundManager; // SoundManager 타입의 변수
    
        private Rigidbody2D myRigid;
        public float flyPower = 10f;
    
        public float limitSpeed = 5f;
    
        void Start()
        {
            myRigid = GetComponent<Rigidbody2D>();
        }
    
        void Update()
        {
            if (Input.GetKeyDown(KeyCode.Space))
            {
                myRigid.AddForce(Vector2.up * flyPower, ForceMode2D.Impulse); // 위쪽으로 힘을 가함
                
                // 속도 체크
                if (myRigid.velocity.y > limitSpeed) // 새의 y축 속도가 제한 속도보다 큰가?
                {
                    // 속도 재조정
                    myRigid.velocity = new Vector2(myRigid.velocity.x, limitSpeed);
                }
    
                // Jump Sound 재생
                soundManager.OnJumpSound();
            }
        }
    }

     

    5. GameOver Sound 추가

    : PipeEvent Script Sound 관련 변수 및 함수 추가, 모든 Pipe Inspector에 할당

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class PipeEvent : MonoBehaviour
    {
        public SoundManager soundManager; // SoundManager 타입의 변수
        public GameObject endUI;
        
        public void OnTriggerEnter2D(Collider2D collision)
        {
            if (collision.CompareTag("Player"))
            {
                endUI.SetActive(true); // End UI가 켜지는 기능
                Debug.Log("Game Over");
        
                // Game Over Sound 재생
                soundManager.OnCollisionSound();
            }
        }
    }

     

    Trigger --> Collision

    : Pipe에 부딪혀도 Bird가 Pipe를 통과하며 끝나는 것을 개선

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class PipeEvent : MonoBehaviour
    {
        public SoundManager soundManager; // SoundManager 타입의 변수
        public GameObject endUI;
        
        // Trigger
        //public void OnTriggerEnter2D(Collider2D collision)
        //{
        //    if (collision.CompareTag("Player"))
        //    {
        //        endUI.SetActive(true); // End UI가 켜지는 기능
        //        Debug.Log("Game Over");
        //
        //        // Game Over Sound 재생
        //        soundManager.OnCollisionSound();
        //    }
        //}
    
        // Collision
        public void OnCollisionEnter2D(Collision2D collision)
        {
            if (collision.gameObject.CompareTag("Player"))
            {
                endUI.SetActive(true); // End UI가 켜지는 기능
                Debug.Log("Game Over");
    
                // Game Over Sound 재생
                soundManager.OnCollisionSound();
            }
        }
    }

     

    완성 영상

     

    추후 추가 개선점

    1. Game Over가 돼도 노래가 멈추지 않음

     

    2. Game Over 후, Retry가 없음

    : Bird velocity 0으로, 혹시 회전이 있다면 회전속도를 0으로, pipe x position 초기화

    >> 처음 Start() 할 때 Reset되는 값들을 저장해두면 편함

     

    3. 몇 개를 통과했는지 또는 얼마나 오래 버텼는지 점수가 없음

    >> 타이머

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
     
    public class TimerEvent : MonoBehaviour
    {
        private float timer = 0f;
        public float wantTime = 10f; // 원하는 시간
     
        void Update()
        {
            timer += Time.deltaTime; // 타이머 기능
     
            if (timer >= wantTime)
            {
                Debug.Log("타이머 알람");
            }
        }
    }

     

    4. Game Over 됐을 때, 메인화면 진행이 멈추지 않음

    : Pipe가 계속 이동

    >> 다른 사람이 공유해준 방법 (대신 Bird는 계속 떨어짐)

     

    5. Bird의 상승/하강에 따른 회전이 없음


    Unity에서 제공하는 게임 화면 녹화

    https://contents-studio.tistory.com/134

     

    [Unity] Unity 게임 화면 녹화하는 방법: Unity Recorder

    팀 프로젝트를 하다보면 내가 어디까지 개발했는지를 팀원들하고 공유해야할 때가 있다. 이전 프로젝트에서는 맥북 화면 녹화를 사용했는데, 이전에는 로우폴리로 작업을 했어서 큰 불편함을

    contents-studio.tistory.com


    Coroutine

    : Update()와 별개로 서브로 반복시킴

     

    >> 실행 방법

    1. StartCoroutine(함수()); --> 함수명으로 호출하는 방식

    2. StartCoroutine(“함수명”) --> 함수로 호출하는 방식

     

    >> 종료 방법

    1. StopCoroutine(함수());

    2. StopCoroutine(“함수명”);

     

    ※ IEnumerator : Coroutine Type

    ※ yield return new WaitForSeconds(1f);

    : 1초씩 대기함 (1초에 한번만 호출됨)

    ※ yield break;

    : coroutine에서 while break

      yield return null;

    : coroutine에서 while return, 1프레임 대기 --> while (true) 안에 없으면 프로젝트 터짐

     

     예시

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class CoroutineEx : MonoBehaviour
    {
        public int endTimer = 10;
        private bool isCancel = false;
    
        void Start()
        {
            StartCoroutine(BombTimer(endTimer));
        }
    
        IEnumerator BombTimer(int t)
        {
            int i = t;
            while (i > 0)
            {
                Debug.Log(i + "초 남았습니다.");
                yield return new WaitForSeconds(1f);
                i--;
    
                if (isCancel)
                {
                    Debug.Log("폭탄이 해제됐습니다.");
                    yield break;
                }
            }
    
            Debug.Log("폭탄이 터졌습니다.");
        }
    
        void Update()
        {
            if (Input.GetKeyDown(KeyCode.Space))
            {
                isCancel = true;
            }
        }
    }