241224

lililllilillll·2024년 12월 23일

개발 일지

목록 보기
30/350

✅ 오늘 한 일


  • Project Etude


🎮 Project Etude


판정 로직 이론 정리

bpm은 60초에 몇 박자가 있는지에 대한 값
60bpm이면 1초에 1박을 간다
bpm이 빨라지면 1박에 필요한 숫자는 반비례하여 작아지고
속도는 그에 비례하여 증가한다

유니티는 Time.deltaTime을 통해 1프레임 동안 지난 시간을 제공한다
fps는 1초에 몇 프레임이 있는지에 대한 값
60fps면 1초에 60프레임이 뿌려진다

60bpm은 1초에 1박을 가므로,
60bpm, 60fps이고 Time.deltaTime을 기반으로 이동한다면
1박을 60개로 쪼개면 1프레임 당 움직이는 모습을 분석할 수 있다

위 그림의 선들이 bpm당 1박에 담기는 프레임들을 의미한다.

유니티는 프레임 단위로 입력을 받으므로,
최악의 경우 플레이어의 입력은 1프레임만큼 딜레이가 생길 수 있다.

위 그림의 파란색 영역이 최악의 입력 딜레이의 길이다.

240bpm일 때 1/4박 안에는 4프레임밖에 들어오지 않는다는 걸 확인할 수 있다.

각 판정 영역이 어떻게 나눠지는지 알아보자.
16분음표(1/4박) 정중앙 네모에 플레이어의 박자선이 들어올 때 입력하면
완벽 판정을 받는다고 가정하겠다.

➀, ➁ :: 틀린 구간 : 누른 위치 틀림, 판정 탈락
➂ :: 아! 눌렀는데! 구간 : 누른 위치 맞음, 판정 탈락
➃ :: 맞은 구간 : 누른 위치 맞음, 판정 합격
➄ :: 뽀록 구간 : 누른 위치 틀림, 판정 합격

정리하고 보니까 240bpm, 16분음표, 완벽 판정이라는 극단적 환경에서도
어마어마하게 불합리하진 않은 것 같다.
일단 데모 올려서 게임이 검증되고 나면 그때 edge case에서의 문제를 해결하면 될듯.
아무도 안 즐길 수도 있는 게임에 극소수의 유저나 신경쓸 기능 공들여봐야 무슨 의미가?

박자 오프셋 구현

인풋 오프셋 측정

인풋 렉이 얼마나 되는지 테스트
10번 정도 테스트하고 평균 내면 될듯
맨 처음과 실패한 건 제외 (웹에서 테스트해본 뒤 오프셋 너무 크면 collider 늘리기)

    private void HitSuccess()
    {
        // Debug.Log("HitSuccess : missionBlockIndex = " + missionBlockIndex);
        missionBlockScript.DisableCollider();
        missionBlockIndex++;
        TurnWithNewPos();
        keyInput = 0;
        isInBox = false;
        if (OffsetTestMode && game_ongoing) OffsetTest(); // 오프셋 계산할때만 작동, 게임 맨 처음 시작할 땐 작동 안 함.
        game_ongoing = true;
        Debug.Log("Success");
    }

    private void OffsetTest()
    {
        {
            if (missionBlockIndex == 2)
            {
                WakeUpAllBlocks();
                missionBlockIndex = 0;
            }

            offsetTest.GetOneOffset(distanceToCenter);
        }
    }

Bar_Judgement_Movement.cs

    public void GetOneOffset(float offset)
    {
        offsetText.text = "Offset: " + offset * 60 / 85 + "s";
        offset_avg += offset;
        offset_count++;
        if (offset_count == 10)
        {
            offset_avg /= 10;
            offsetText.text = "";
            Debug.Log("Offset Average: " + offset_avg);
            // TODO :: 오프셋 어딘가에 저장해야됨
            player.GetComponent<Bar_Judge_Movement>().enabled = false;
            StartCoroutine(StartDriector.StartGame());
        }
    }

OffsetTest.cs

60초에 85박이 들어가는 상황
1초에 85/60박이 들어간다
1박은 1유니티 유닛이다
1박에 걸리는 시간은 60/85초
1유니티 유닛에 걸리는 시간 역시 60/85초
n유니티 유닛에 걸리는 시간은 n * 60/85초
1초는 1000ms

판정할 때 오프셋만큼 보정해줘야한다
키를 더 빨리 눌렀다고 가정하고 raycast를 앞으로 땡겨줘야 함

raycast local offset 파업

분명 멀쩡하게 sprite renderer 기준으로 앞뒤 잘 쏘고 있었는데
input offset 적용해보려고 했더니 갑자기 폭이 좁아짐
내가 뭔가 계산을 잘못한건가 싶어서 일단 되돌린 후에 다시 확인해봤더니
또 폭이 좁아져있음

git 기록으로 뭘 바꿨었나 확인해봤더니 아무것도 바꾼게 없음.
한동안 gizmo 끄고 테스트 돌려서 raycast가 어떻게 되는지 확인한 적은 없었음.
아마 연출을 위해 sprite의 속성값을 변경하는 과정에서 이렇게 되지 않았나 추측.

float boundSize = transform.localScale.x;를 시도해봤는데 안됨.
sprite renderer 크기를 괜히 곱했던건 아니니까.

startdirector에서 스크립트를 나중에 enable해주는 것 때문에 그런가 해서
start를 onenable로 바꿔줬는데도 안됨. 이게 문제일리는 없긴 했음.

MapEditor 씬으로 가봤더니 망가져 있어서 역시 뭔가 잘못됐구나 했는데,
Map1 씬으로 가봤더니 여전히 내가 의도했던 간격은 아닌데 살짝 더 벌어짐.
??? 상황이 더 이해가 안되게 돼버렸다. 차이점이 없을텐데?

분명 이 문제 해결했던 기억이 있어서 적어놓은 글을 다시 찾아봤고,
"태평양보다 넓다"고 했던 식으로 되돌아가봤는데, 여전히 좁다.

뭔가... 뭔가가 잘못됐음.

    void Start()
    {
        float boundSize = transform.GetComponent<SpriteRenderer>().bounds.size.x * transform.localScale.x;
        Debug.Log("새롭게 만든 오브젝트의 boundsize : " + boundSize);
    }

다른씬에 가서 새로운 오브젝트에 새로운 스크립트로 확인해봐도 값이 이상하게 나옴.

아니 분명 그저께는 이렇게 잘 나오고 있었고
Start에 넣어놓은거라 뭐가 방해받을만한 것도 없고
만약에 방해받았다고 하더라도 아무것도 없는 씬에서는 제대로 작동해야되는데 왜 안하는거임
아니 그리고 Map1 씬에선 또 왜 약간 넓어진거지??

Map1 씬에 새 오브젝트 복붙해봤는데 이건 또 결과가 다르게 나옴

일단 중요한 변인 하나를 확인했다. 각도 바꾸니까 뭔가 값이 바뀐다.
처음에 저 식 쓸때까지만 해도
'bound.size.x면 각도 틀어졌을 때 값이 이상하게 나올 것 같긴 한데,
나중에 맵 만들 때 초기 각도 받아와서 돌려놓으면 되겠다.'
라고 생각했었는데 까맣게 잊어버림.

당황시킨 것 치고 허무할 정도로 간단했다.
키워드 몇 글자만 바꾸면 되는 거였음. 해결 완료.

그럼 이전에는 왜 raycast를 제대로 쏴줬나?
: 사실 살짝 어긋나 있었는데 해결했다고 착각했었던 것 같음.

raycast에 오프셋 적용

빠르게 친 사람은 미래로 보내주고
느리게 친 사람은 과거로 보내주고

빠르게 치면 offset이 음수고 느리게 치면 양수니까
원래 의도한 좌표에서 offset을 빼주면 된다

    void Start()
    {
        float InputOffset = ES3.Load<float>("InputOffset", defaultValue: 0f);
        if (OffsetTestMode) InputOffset = 0f;
        float boundSize = transform.GetComponent<SpriteRenderer>().sprite.bounds.size.x;
        localFrontOffset = new Vector3(boundSize / 2 - InputOffset, 0, 0);
        localBackOffset = new Vector3(-boundSize / 2 - InputOffset, 0, 0);
        rayDirection = Vector3.back;

완성

Let there be light, please...

Emission 효과 튜토리얼 따라해봤는데 안됨
새 프로젝트 파서 했는데도 안됨
URP 설정에 뭔가 문제가 있는 것 같아,
애셋으로 사놨던 Topdown Engine을 참고하여 설정이 뭐가 다른건지 확인해보기로 함
이건 저번에 봤을 때 조명 빛났음

이것들이 overwrite되는 설정들
EditorSettings 확인하기
EGraphicsSettings 확인하기
ProjectSettings 확인하기
QualitySettings 확인하기
VFXManager 확인하기

bloom이라고 기억하고 있던게
그냥 횃불 스프라이트랑 시야에 들어오는 곳만 밝히는 기능이었다

그래도 뭔가 이것저것 import해서 overwrite했으니까
한 번 이걸로 튜토 과정 그대로 따라해봤는데 역시나 안됨

설정 확인하고 말고 자시고 이것도 안됨

튜토리얼 이것저것 다 해보는데 죽어도 안됨
버전이 뭔가 다른 것 같음

내일 https://www.youtube.com/watch?v=Kezjif-WpnI 이거 해보기



profile
너 정말 **핵심**을 찔렀어

0개의 댓글