241209

lililllilillll·2024년 12월 9일

개발 일지

목록 보기
15/350

✅ 오늘 한 일


  • Project Etude
  • C# 교과서 읽기
  • 백준 1문제 풀기


🎮 Project Etude


예제 애셋 코드 분석

https://assetstore.unity.com/packages/templates/systems/rhythm-game-starter-create-your-rhythm-160117

블프 때 사둔 애셋을 분석해본 뒤에 개발에 들어가기로 함.
이유: 나 혼자 하면 구현한 방식에 치명적 약점이 있어서 다 갈아엎어야 하는 상황이 나올까봐 무서워서 일단 레퍼런스 보고 대충 어떤 느낌인지 감 잡고 싶어서


Getting Started 영상에서 Project Settings > Audio > DSP Buffer Size > Best latency로 변경했다.
이거 설정하면 음악과 노트의 동기화가 더 잘된다고 함.

FAQ

동기화에 AudioSettings.dspTime을 사용했다
비트 맵 저장할 때 ScriptableObject 사용했다
유니티의 물리 콜라이더로 노트 판정
유니티 에디터에서 작업할 때 오디오 딜레이 생기면 DSP buffer size를 'Default'나 'Good Latency'로 바꾼 다음 작업하면 됨. 빌드할 땐 'Best Latency'로 다시 돌려놔야 됨.

Quick Start

Pacakage Manager에서 device simulator 설치하면 모바일 기기 인풋 테스트할 수 있다

RhythmCore 프리팹이 게임 로직을 관장한다

https://docs.unity3d.com/ScriptReference/AudioSettings.GetDSPBufferSize.html

위 설명은 Unity의 소프트웨어 오디오 믹서에서 링 버퍼와 관련된 설정 및 성능 조정에 대한 내용입니다. 주요 내용을 요약하고 상세히 풀어서 설명하면 다음과 같습니다:

1. 링 버퍼(Ring Buffer)란?

  • 링 버퍼는 순환 버퍼로, 오디오 데이터를 저장하는 메모리 구조입니다.
  • 링 버퍼는 일정한 크기의 메모리 공간을 가지며, 오디오 데이터가 추가될 때 끝에 도달하면 다시 시작 부분으로 돌아가 데이터를 덮어씁니다.
  • Unity의 오디오 시스템은 이 링 버퍼를 사용해 오디오 데이터를 저장하고 재생합니다.

2. 주요 용어

  • bufferLength:

    • 한 번에 믹싱하는 사운드 데이터 블록의 샘플 수를 의미합니다.
    • 이 값이 작으면 더 자주 작은 크기의 오디오 데이터를 처리합니다.
    • 값이 작을수록 지연(Latency)가 줄어들지만, CPU 사용량이 늘어납니다.
  • numBuffers:

    • 링 버퍼를 구성하는 데이터 블록의 개수입니다.
    • bufferLength와 함께 링 버퍼의 전체 크기를 결정합니다.
    • 안정적인 출력(글리치나 끊김 없는 재생)을 위해 이 값을 조정할 수 있습니다.
  • bufferSize:

    • 전체 링 버퍼의 크기를 결정하는 값으로, bufferLength * numBuffers입니다.
    • 이 값은 Unity가 기본적으로 출력 장치와 드라이버에 맞게 자동 설정하므로, 일반적으로 변경하지 않는 것이 좋습니다.

3. 값 조정의 영향

bufferLengthnumBuffers의 조정

  • 작게 설정 (저지연 설정):
    • 작은 bufferLength지연(latency)을 줄일 수 있습니다.
    • 하지만 CPU에 더 많은 부하를 줍니다(캐시 미스 증가, DSP 네트워크 오버헤드 등).
    • 지나치게 작은 값은 CPU 성능에 따라 소리 끊김(glitch)을 발생시킬 수 있습니다.
  • 크게 설정 (안정성 우선 설정):
    • bufferLengthnumBuffers는 안정적인 출력과 글리치 없는 오디오 재생을 보장합니다.
    • 그러나 값이 너무 크면 명령 업데이트(볼륨, 피치, 팬 조정 등)가 느려지고, 20ms 이상의 지연은 사용자가 인식할 정도로 명령이 부드럽지 않게 들립니다.

Unity의 기본값 유지 권장

  • Unity는 기본적으로 최적의 값(출력 장치와 드라이버에 따라)을 자동 설정합니다.
  • 이 값들은 대부분의 경우 안정성과 성능의 균형을 유지하므로, 특별한 이유가 없다면 변경하지 않는 것이 좋습니다.
  • 기본값을 변경하면 기본 설정보다 성능이 나빠질 가능성이 있습니다.

Components

미디 파일에 있는 노트들을 그대로 트랙으로 가져올 수 있는 기능 있다
근데 내 게임은 이렇게 하기 힘들듯.


1/4분 음표 하나에 유니티 좌표 1씩 움직이기

애셋을 대충 훑어봤는데, DSP buffer라는 키워드 말곤 딱히 얻어간게 없을지도.
그것보단 일단 하나하나 기능을 쌓아올리는 것에 집중하는게 나아 보인다.

가장 먼저 할 것은 1/4분 음표 하나에 유니티 좌표 1씩 움직이기.

bpm이라는게 중요한데 인터넷에 있는 녹음 파일들은 연주 중에 전부 다 박자가 조금씩 빨라지거나 느려짐

일류급 피아니스트여도 정확한 박자를 맞추진 못할 것이고, 그렇게 하지도 않을 것임. 예술이기 때문.
그렇다면 midi 파일을 구해서 음악을 뽑아보기로 함.

그러려면 또 daw라는게 필요함. 업계에서 많이 쓰는 큐베이스라는 건 가격이 80만원이길래 무료인 cakewalk 사용.
daw에서 가상 악기를 불러와야 한다고 함. https://labs.spitfireaudio.com/ko/packs?labels=2zfz1K2g4Ex6td4fhItoFh 여기 있는 것들 쓰면 될듯.

가상 악기 적용하려는데

https://www.youtube.com/watch?v=K5KwWj1qlWE

영상 보고 따라하는데 자꾸 안됨
뭔가 업데이트돼서 달라진건지 뭔지...

중요한 건 1/4 박자에 1칸이 가도록 조절하는 것이니, 우선 메트로놈 음원을 구한 뒤 그걸로 테스트를 하자. 더 우선인 문제, 주된 문제에 집중해야지 rabbit hole에 빠지면 안된다. cakewalk 문제는 비동기로 돌려놓고 시간 되는대로 탐색해보자.



📖 C# 교과서


25 문자열 다루기

메서드설명
Length문자열 길이 값 반환
ToUpper()문자열을 모두 대문자로 변환
ToLower()문자열을 모두 소문자로 변환
Trim()문자열 양쪽 공백을 잘라냄
Replace(원본문자열, 대상문자열)원본 문자열을 대상 문자열로 변경
Substring(문자열인덱스, 길이)지정된 문자열 인덱스부터 길이만큼 반환
String.Concat()문자열 연결
ToCharArray()문자열을 문자 배열로 변환
Split()구분자를 사용하여 문자열 분리
string.IsNullOrEmpty()null 또는 빈 값인지 확인
string.IsNullOrWhiteSpace()null 또는 빈 값 또는 공백인지 확인
IndexOf()문자열 앞부분부터 검색해서 특정 문자 첫 등장 위치
LastIndexOf()문자열 뒷부분부터 검색해서 특정 문자 첫 등장 위치
Insert()문자열 삽입
Remove()지정한 위치의 문자 또는 문자열 제거
PadLeft()특정 문자를 왼쪽에 채움
PadRight()특정 문자를 오른쪽에 채움
StartsWith()특정 문자열로 시작하는지 여부
EndsWith()특정 문자열로 끝나는지 여부

문자열을 묶는 세 가지 표현 방법

  1. +로 연결
  2. String.Format() : String.Format("이름 : {0}{1}", lastName, firstName);
  3. 문자열 보간법 : $"이름 : {lastName}{firstName}";

문자열을 비교하는 두 가지 방법

  1. ==연산자 : 대소문자를 구분
  2. Equals(); : 대소문자 구분x, if(s1.Equals(s2, StringComparison.InvariantCultureIgnoreCase)) 또는 if(string.Equals(s1,s2,StringComparison.InvariantCultureIgnoreCase)

25.3 StringBuilder 클래스

StringBuilder 클래스를 사용하려면 다음과 같이

> StringBuilder builder = new StringBuilder();

새로운 이름의 개체(인스턴스)를 생성해야 함.
출력하려면 ToString() 메서드로 문자열로 변환 후 사용 가능.

메서드설명
Append()문자열 추가
AppendLine()문자열 추가하는데 끝에 \r\n 있음

26 예외 처리하기

26.2 try-catch-finally 구문

try
{
	// 예외가 발생할 만한 코드 작성
}
catch
{
	// 예외가 발생할 때 처리해야 할 코드 블록
}
finally
{
	// 예외가 발생하거나 정상일 때 모두 처리해야 할 코드 블록
}

26.3 Exception 클래스로 예외 처리하기

Exception: 닷넷에서 모든 예외에 대해 처리할 주요 기능을 담아 놓은 클래스

class ExceptionDemo
{
    static void Main()
    {
        try
        {
            int[] arr = new int[2];
            arr[100] = 1234;
        }
        catch(Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}

Exception 클래스 형식의 변수인 ex에 예외 내용을 담으면 Message 속성으로 예외 내용을 알 수 있다.
Exception은 다양한 예외 클래스(ArgumentException, NullReferenceException, FormatException 등)의 부모 클래스이다.

FormatException은 형식이 올바르지 않은 데이터가 사용될 때 발생하는 오류를 위한 Exception

26.5 throw 구문으로 직접 예외 발생시키기

C#에서 throw 구문은 예외를 발생시키는 것.

void Divide(int a, int b)
{
    if (b == 0)
    {
        throw new DivideByZeroException("0으로 나눌 수 없습니다.");
    }
    Console.WriteLine(a / b);
}

throw를 사용하여 특정 조건에서 새로운 예외를 발생시킬 수 있습니다.

try
{
    int result = int.Parse("abc"); // 형식 오류 발생
}
catch (FormatException ex)
{
    Console.WriteLine("예외를 기록하고 다시 던짐.");
    throw; // 원래 예외를 재발생
}

throw를 사용하여 현재 발생한 예외를 다시 던질 수 있습니다.
이를 통해 예외 처리를 상위 호출 스택에 전달할 수 있습니다.

throw와 throw ex의 차이

catch (Exception ex)
{
    throw; // 원래 예외를 유지하고 상위로 전달
}
  • 현재 예외의 원래 호출 스택 정보를 유지합니다.
  • 디버깅 시 예외가 발생한 정확한 위치를 추적할 수 있습니다.
catch (Exception ex)
{
    throw ex; // 호출 스택 정보가 덮어써짐
}
  • 예외 객체를 새로 던지면서 원래 호출 스택 정보를 덮어씁니다.
  • 디버깅 시 원래 예외가 발생한 위치를 알기 어렵게 만듭니다.

27 컬렉션 사용하기

네임스페이스클래스
SystemArray 클래스
System.CollectionsStack 클래스, Queue 클래스, ArrayList 클래스
System.Collections.GenericList<T> 클래스, LinkedList<T> 클래스, Stack<T> 클래스, Queue<T> 클래스
System.Collections.ConcurrentConcurrentStack<T> 클래스, ConcurrentQueue<T> 클래스

27.3 Array 클래스

  • Array.Sort() 배열을 정렬
  • Array.Reverse() 배열을 역순으로 바꿈
  • Array.ConvertAll() 배열을 다른 형식으로 변환

27.5 Stack 클래스

  • Count: 스택에 있는 데이터 개수 조회
  • Push(): 스택에 데이터 저장
  • Pop(): 스택에서 데이터 꺼내기
  • Peek(): 스택 마지막 데이터 반환
  • Clear(): 스택 비우기

27.6 Queue 클래스

  • Enqueue()
  • Dequeue()


⚔️ 백준


7568 덩치

N=int(input())
h=[tuple(map(int,input().split())) for _ in range(N)]
# h.sort() 바보
ranks=[0 for _ in range(N)]
for i in range(N):
    rank = 1
    for j in range(N):
        if h[i][0]<h[j][0] and h[i][1]<h[j][1]:
            rank += 1
    ranks[i] = rank
for r in ranks:
    print(r,end=' ')

sort하면 순서가 흐트러져서 정렬하면 안됨
공백 문자로 구분하라고 했는데 안했었음



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

0개의 댓글