이번 팀과제는 리듬게임을 하기로 했다.

휴일이 길어서 그동안 간단하게 공부할 것들을 정하고 게임의 방향성과 계획을 짰다.

 

<필수 구현 계획>

노래에 맞게 노트 생성(JSON을 통해 실시간으로 직접 노트를 찍거나 단순히 BPM에 맞게 노트 생성)

노트 타격 판정

타격에 따른 애니메이션

콤보 및 점수

 

<선택 구현 계획>

사용자 모드(사용자가 원하는 노래 추가 및 노트 생성)

일정 콤보가 되면 피버 타임 구현

음량 조절

 

전체적으로 8Bit 컨셉으로 노래 또한 8Bit로 몇 가지 만들 생각이다. 에셋은 각자 원하는 것을 하나씩 가져와서 상의 후 결정하기로 했다.

주말에 이론강의 + 수준별 강의를 정주행하고 하고 개인 과제 때 오브젝트 풀에 대해 정확히 이해하지 못하고 사용한 것 같아서 좀 더 공부해야겠다. 개인과제에서 전체적인 설계가 많이 무너졌기 때문에 초기에 설계를 확실히 짜고, 특히 이전 강의에 나왔던 애니메이션과 FSM의 스크립트 구조를 공부해볼 생각이다.

유니티에서 게임 오브젝트를 활성화하거나 비활성화 할 때, enable과 SetActive를 주로 사용한다.

 

enable

enable로 활성/비활성화 하면 특정 컴포넌트만 활성/비활성화 된다.

gameObject.enabled = false;

 

SetActive

SetActive로 활성/비활성화 하면 해당 게임 오브젝트의 하위 오브젝트도 활성/비활성화 된다.

gameObject.SetActive(false);

 

 

아래는 리듬게임 노트의 이미지를 비활성화하는 메서드로, 스페이스바를 누르면 HideImage 메서드를 호출하여 이미지를 비활성화 하고 일정 범위를 벗어나면 노트 오브젝트를 파괴하고 싶었다.

private Image noteImage;

public void HideImage()
{
    noteImage.gameObject.SetActive(false);
}

 

그런데 SetActive를 사용했더니 이미지 뿐만 아니라 오브젝트 자체를 비활성화하여 일정 범위가 벗어나도 복제되고 있는 노트들이 파괴되지 않고 계속해서 쌓이는 문제가 있었다.

 

enable을 사용하여 게임 오브젝트 전체가 아닌 이미지만 비활성화하여 해결했다.

public void HideImage()
{
    noteImage.enabled = false;
}

 

 

오른쪽에서 왼쪽으로 오는 노트를 스페이스로 리듬에 맞춰 누르면 플레이어가 헤엄치는 간단한 리듬게임을 기획했다.

 

Note 구현

빈 캔버스에 노트 컨테이너 UI를 만든다.

 

일단 노트가 오른쪽에서 왼쪽으로 지나가도록 하기 위해 캔버스에 스크립트를 추가한다.

public class Note : MonoBehaviour
{
    private float noteSpeed = 500f;

    private void Update()
    {
        transform.localPosition += Vector3.left * noteSpeed * Time.deltaTime;
    }
}

좌표를 local로 한 이유는 캔버스 내의 좌표에서 생성되어야하기 때문이다. position으로 하면 월드좌표에 생성되기 때문에 엉뚱한 곳에 생성될 것이다.

 

노트의 충돌을 감지하기 위해 Rigidbody와 Collider를 붙여준다.

충돌로 인한 물리 효과는 필요 없기 때문에 Is Trigger를 체크하고 Dynamic이 아닌 Kinematic을 선택한다. 노트는 계속해서 생성할 것이기 때문에 Prefab으로 뺀다.

 

유니티에서 노트를 생성할 Transform을 지정하는 오브젝트를 만들어준 뒤, 비트 당 시간마다 노트를 생성시킨다.

현재 시간을 0으로 초기화하지 않는 이유는 float나 doubl은 부동 소수점 표현 방식을 사용하기 때문에 오차가 발생하여 60 / bpm을 빼줌으로써 오차를 줄이는 것이다.

public class NoteManager : MonoBehaviour
{
    public float bpm;
    private double currentTime; // 오차를 줄이기 위해서 double로 선언

    [SerializeField] Transform noteCreate;
    [SerializeField] GameObject note;

    private void Update()
    {
        currentTime += Time.deltaTime;

        if (currentTime >= 60 / bpm) // 1beat 당 시간
        {
            GameObject touchNote = Instantiate(note, noteCreate.position, Quaternion.identity); // 노트 생성
            touchNote.transform.SetParent(this.transform); // 부모인 UI 캔버스 내에서 생성
            currentTime -= 60 / bpm;
        }
    }

    private void OnTriggerEnter(Collider other) // 오브젝트 간 충돌 감지
    {
        if (other.tag == "Note")
        {
            Destroy(other.gameObject); // 카메라 밖의 Collider와 만나면 파괴
        }
    }
}

노트가 계속해서 생성되고 파괴되기 때문에 나중에 오브젝트 풀 방식으로 바꿔줄 예정이다.

 

노트가 나오면 음악이 나오도록 임시로 오디오 소스를 넣는다. 자동으로 재생하지 않도록 Play On Awake를 꺼준다.

 

오디오 소스가 붙은 오브젝트에 스크립트를 추가한다. 첫 오브젝트가 바의 Collider와 충돌하면 음악이 재생된다.

public class Audio : MonoBehaviour
{
    private AudioSource audio;

    private bool isMusicStart;

    private void Start()
    {
        audio = GetComponent<AudioSource>();
    }

    private void OnTriggerEnter2D(Collider2D other)
    {
        if (!isMusicStart)
        {
            if (other.tag == "Note")
            {
                audio.Play();
                isMusicStart = true;
            }
        }
    }
}

 

그런데 노트가 Collider와 충돌하면 파괴되도록 했는데 왜 바와 충돌해도 파괴되지 않을까?

 

OnTriggerEnter 같은 이벤트 함수들은 자신->자식 순서로 이벤트가 일어나는지 확인 후, 상호작용하기 때문에 자식에 Collider가 붙어있어도 이미 자기 자신에 Collider가 붙어있기 때문에 파괴되지 않는 것이라고 예상하고 있다. 자세한건 테스트 해봐야겠다.

 

 

유니티에서 작업한 프로젝트를 Windows와 Android로 실행할 수 있는 파일로 변환하는 빌드 작업을 해볼 것이다.

 

빌드 과정(Windows편)

  1. File - Build Settings
  2. Platform - Windows 선택 후, Switch Platform 클릭
  3. Scenes in Build에 원하는 씬 추가
  4. Player Settings에서 게임 설정 변경(회사 이름, 게임 아이콘, 해상도 등)
  5. Build 파일을 따로 만들어서 Build 하기

Player Setting

 

 

빌드 과정(Android편)

  1. File - Build Settings
  2. Platform - Android 선택 후, Switch Platform 클릭
  3. Scenes in Build에 원하는 씬 추가
  4. Player Settings에서 게임 설정 변경(회사 이름, 게임 아이콘 등)
  5. Minimun API Level과 Target API Level 설정
  6. Build을 따로 만들어서 Build 하기

 

 

윈도우와 안드로이드 등 빌드할 때 플러그인을 추가했다면 호완성 이슈가 발생할 수 있다. 안드로이드의 경우 JDK나 Android SDK가 기본적으로 설치 되어있는지 확인해야한다. 스마트폰은 해상도가 다양하기 때문에 UI를 구성할 때 Pivot이나 Anchor 등을 잘 설정해야한다.

 

 

Windows Build 화면 크기(해상도) 오류

윈도우를 빌드 할 때 창모드로 진행하는 경우가 많은데, 창모드로 진행하고 저장했을 때 해상도와 위치 또한 저장되기 때문에 다음에 빌드할 때 화상도를 저장해도 적용되지 않는 경우가 있다.

레지스트리편집기에서 HKCU\Software\[회사명]\[제품명] 검색 후 설정된 해상도 값을 수정하거나 삭제하면 된다.

 

 

+ Recent posts