Ch 7. 스테이지 구현(+ Snap Settings)

Date:     Updated:

카테고리:

태그:

케이디님의 [유니티 강좌] 리듬 게임 유튜브 강의를 듣고 정리한 필기입니다. 😀
🌜 강의 들으러 가기 Click

🚀 스테이지 구현

납작한 큐브 만들어서 텍스처 입히기

✈ 머테리얼에 텍스처 입히기

image

image

머테리얼에 텍스처를 입히려면 머테리얼의 Albedo 왼쪽에 있는 조그마한 네모에 텍스처 파일을 드래그 앤 드롭 하면 된다. 이 머테리얼을 큐브에 입혀 플레이트 프리팹을 만든다.


✈ Gird and Snap Settings

image

오브젝트를 정밀하게 말고 어떤 단위로 딱딱 이동시키려면 Ctrl을 누른 상태에서 오브젝트를 이동시키면 된다. (이걸 Snap 이라고 하는 것 같다.) 위 플레이트의 길이는 1 이기 때문에 플레이트 오브젝트들을 옮겨서 배치하려고 할 떄 Ctrl을 누른 상태에서 1 씩 이동되게끔 하고 싶다면

image

Edit - Grid and Snap Settings 에서 Move 부분을 1 로 설정해주면 된다. 이제 스냅으로 오브젝트를 이동시킬 때 1 단위로 움직이게 하기 떄문에 배치하기가 편해진다.


image

  • Stage 👉 📜StageManager
    • Stage1, Stage2… 👉 📜Stage (Stage 들)
      • 각 스테이지에 속한 Plate들 👉📜BasicPlate, 태그도 “BasicPlate”


🚀 스테이지 스크립트


📜BasicPlate

public class BasicPlate : MonoBehaviour
{
    public bool flag = true;
}

이미 밟았던 플레이트라면 false로 바꿀 것.

image

첫 번째 플레이트는 시작 플레이트니까 false로.


📜Stage

public class Stage : MonoBehaviour
{
    public Transform[] plates;
}

한 스테이지마다 저장해둘 “게임 중 밟으면 활성화 상태로 바꿀” 플레이트들 plated

image


📜 StageManager

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class StageManager : MonoBehaviour
{
    [SerializeField] GameObject stage = null;
    Transform[] stagePlates;

    [SerializeField] float offsetY = -3;    // 플레이트 활성화시 밑에서 올라오게 할거라..
    [SerializeField] float plateSpeed = 10; // 플레이트 활성화시 올라오는 속도

    int stepCount = 0;
    int totalPlateCount = 0; // stepCount가 stagePlates.Length를 넘으면 안된다.(배열 인덱스 범위 초과 에러 막기 위해)

    void Start()
    {
        stagePlates = stage.GetComponent<Stage>().plates;
        totalPlateCount = stagePlates.Length;

        // 플레이트들 밑에서 올라오면서 활성화 되도록 offset 만큼 밑에 위치하도록 세팅 (현재 비활성화 상태)
        for (int i = 0; i < totalPlateCount; i++)
        {
            stagePlates[i].position = new Vector3(stagePlates[i].position.x, 
                                                  stagePlates[i].position.y + offsetY, 
                                                  stagePlates[i].position.z);
        }
    }

    public void ShowNextPlate()
    {
        if (stepCount < totalPlateCount)
            StartCoroutine(MovePlateCo(stepCount++));
    }

    // 플레이트를 활성화 하고 코루틴으로 천천히 부드럽게 위로 올라 오게 함
    IEnumerator MovePlateCo(int p_num)
    {
        stagePlates[p_num].gameObject.SetActive(true);
        Vector3 t_destPos = new Vector3(stagePlates[p_num].position.x,
                                        stagePlates[p_num].position.y - offsetY,
                                        stagePlates[p_num].position.z);
        while(Vector3.SqrMagnitude(stagePlates[p_num].position - t_destPos) >= 0.001f)
        {
            stagePlates[p_num].position = Vector3.Lerp(stagePlates[p_num].position, t_destPos, plateSpeed * Time.deltaTime);
            yield return null;
        }
        stagePlates[p_num].position = t_destPos;
    }
}

image


📜 PlayerController

public Vector3 destPos = new Vector3();

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.A) || Input.GetKeyDown(KeyCode.D) ||
            Input.GetKeyDown(KeyCode.W) || Input.GetKeyDown(KeyCode.S))
        {
            if (canMove)
            {
                Calc();

                // 판정 체크 : Perfect, Cool, Good, Bad 일 때만 True
                if (theTimingManager.CheckTiming())
                {
                    StartAction();
                }
            }
        }
    }

    void Calc()
    {
        // 큐브의 x축 -> 위 아래   큐브의 z축 -> 오른쪽, 왼쪽
        dir.Set(Input.GetAxisRaw("Vertical"), 0, Input.GetAxisRaw("Horizontal"));

        // 이동 목표값 게산
        destPos = transform.position + new Vector3(-dir.x, 0, dir.z);

        // 회전 목표값 계산
        rotDir = new Vector3(-dir.z, 0f, -dir.x);
        fakeCube.RotateAround(transform.position, rotDir, spinSpeed); //공전
        destRot = fakeCube.rotation;
    }

    void StartAction()
    {
        StartCoroutine(MoveCo());
        StartCoroutine(SpinCo());
        StartCoroutine(RecoilCo());
        StartCoroutine(theCam.ZoomCam());
    }


📜 TimingManager

    StageManager theStage;
    PlayerController thePlayer;

    theStage = FindObjectOfType<StageManager>();
    thePlayer = FindObjectOfType<PlayerController>();

    // 이 함수가 True 를 리턴할 때 플레이트를 활성화 하고 점수를 증가시킬 것!
    // 플레이어의 목표 위치에 이미 플레이트가 있다면(Raycast 걸리는게 BasicPlate라면) flag 를 True 로 만들고 true 리턴.
    bool CheckCanNextPlate()
    {
        if (Physics.Raycast(thePlayer.destPos, Vector3.down, out RaycastHit t_hitInfo, 1.1f))
        {
            if (t_hitInfo.transform.CompareTag("BasicPlate"))
            {
                BasicPlate t_plate = t_hitInfo.transform.GetComponent<BasicPlate>();
                if (t_plate.flag)
                {
                    t_plate.flag = false;
                    return true;
                }
            }
        }
        return false;
    }

    public bool CheckTiming()
    {
        //...

                    if (CheckCanNextPlate())
                    {
                        theScoreManager.IncreaseScore(j);  // 점수 증가
                        theStage.ShowNextPlate(); // 다음 플레이트 호출
                        theEffect.JudgementEffect(j);
                    }
                    else
                    {
                        // Normal 이미지 뜨게끔. 점수 반영도 X
                        theEffect.JudgementEffect(5);
                    }
                        
                    return true;
                }
            }
        }




🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우 
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄

맨 위로 이동하기

Unity Lesson 4 카테고리 내 다른 글 보러가기

댓글 남기기