블프 때 사둔 애셋을 분석해본 뒤에 개발에 들어가기로 함.
이유: 나 혼자 하면 구현한 방식에 치명적 약점이 있어서 다 갈아엎어야 하는 상황이 나올까봐 무서워서 일단 레퍼런스 보고 대충 어떤 느낌인지 감 잡고 싶어서
Getting Started 영상에서 Project Settings > Audio > DSP Buffer Size > Best latency로 변경했다.
이거 설정하면 음악과 노트의 동기화가 더 잘된다고 함.
동기화에 AudioSettings.dspTime을 사용했다
비트 맵 저장할 때 ScriptableObject 사용했다
유니티의 물리 콜라이더로 노트 판정
유니티 에디터에서 작업할 때 오디오 딜레이 생기면 DSP buffer size를 'Default'나 'Good Latency'로 바꾼 다음 작업하면 됨. 빌드할 땐 'Best Latency'로 다시 돌려놔야 됨.
Pacakage Manager에서 device simulator 설치하면 모바일 기기 인풋 테스트할 수 있다
RhythmCore 프리팹이 게임 로직을 관장한다
https://docs.unity3d.com/ScriptReference/AudioSettings.GetDSPBufferSize.html
위 설명은 Unity의 소프트웨어 오디오 믹서에서 링 버퍼와 관련된 설정 및 성능 조정에 대한 내용입니다. 주요 내용을 요약하고 상세히 풀어서 설명하면 다음과 같습니다:
1. 링 버퍼(Ring Buffer)란?
2. 주요 용어
bufferLength:
numBuffers:
bufferLength와 함께 링 버퍼의 전체 크기를 결정합니다.bufferSize:
bufferLength * numBuffers입니다.3. 값 조정의 영향
bufferLength 및 numBuffers의 조정bufferLength는 지연(latency)을 줄일 수 있습니다.bufferLength와 numBuffers는 안정적인 출력과 글리치 없는 오디오 재생을 보장합니다.
미디 파일에 있는 노트들을 그대로 트랙으로 가져올 수 있는 기능 있다
근데 내 게임은 이렇게 하기 힘들듯.
애셋을 대충 훑어봤는데, 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 문제는 비동기로 돌려놓고 시간 되는대로 탐색해보자.
| 메서드 | 설명 |
|---|---|
Length | 문자열 길이 값 반환 |
ToUpper() | 문자열을 모두 대문자로 변환 |
ToLower() | 문자열을 모두 소문자로 변환 |
Trim() | 문자열 양쪽 공백을 잘라냄 |
Replace(원본문자열, 대상문자열) | 원본 문자열을 대상 문자열로 변경 |
Substring(문자열인덱스, 길이) | 지정된 문자열 인덱스부터 길이만큼 반환 |
String.Concat() | 문자열 연결 |
ToCharArray() | 문자열을 문자 배열로 변환 |
Split() | 구분자를 사용하여 문자열 분리 |
string.IsNullOrEmpty() | null 또는 빈 값인지 확인 |
string.IsNullOrWhiteSpace() | null 또는 빈 값 또는 공백인지 확인 |
IndexOf() | 문자열 앞부분부터 검색해서 특정 문자 첫 등장 위치 |
LastIndexOf() | 문자열 뒷부분부터 검색해서 특정 문자 첫 등장 위치 |
Insert() | 문자열 삽입 |
Remove() | 지정한 위치의 문자 또는 문자열 제거 |
PadLeft() | 특정 문자를 왼쪽에 채움 |
PadRight() | 특정 문자를 오른쪽에 채움 |
StartsWith() | 특정 문자열로 시작하는지 여부 |
EndsWith() | 특정 문자열로 끝나는지 여부 |
+로 연결String.Format() : String.Format("이름 : {0}{1}", lastName, firstName);$"이름 : {lastName}{firstName}";==연산자 : 대소문자를 구분Equals(); : 대소문자 구분x, if(s1.Equals(s2, StringComparison.InvariantCultureIgnoreCase)) 또는 if(string.Equals(s1,s2,StringComparison.InvariantCultureIgnoreCase)StringBuilder 클래스를 사용하려면 다음과 같이
> StringBuilder builder = new StringBuilder();
새로운 이름의 개체(인스턴스)를 생성해야 함.
출력하려면 ToString() 메서드로 문자열로 변환 후 사용 가능.
| 메서드 | 설명 |
|---|---|
Append() | 문자열 추가 |
AppendLine() | 문자열 추가하는데 끝에 \r\n 있음 |
try
{
// 예외가 발생할 만한 코드 작성
}
catch
{
// 예외가 발생할 때 처리해야 할 코드 블록
}
finally
{
// 예외가 발생하거나 정상일 때 모두 처리해야 할 코드 블록
}
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
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를 사용하여 현재 발생한 예외를 다시 던질 수 있습니다.
이를 통해 예외 처리를 상위 호출 스택에 전달할 수 있습니다.
catch (Exception ex)
{
throw; // 원래 예외를 유지하고 상위로 전달
}
catch (Exception ex)
{
throw ex; // 호출 스택 정보가 덮어써짐
}
| 네임스페이스 | 클래스 |
|---|---|
System | Array 클래스 |
System.Collections | Stack 클래스, Queue 클래스, ArrayList 클래스 |
System.Collections.Generic | List<T> 클래스, LinkedList<T> 클래스, Stack<T> 클래스, Queue<T> 클래스 |
System.Collections.Concurrent | ConcurrentStack<T> 클래스, ConcurrentQueue<T> 클래스 |
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하면 순서가 흐트러져서 정렬하면 안됨
공백 문자로 구분하라고 했는데 안했었음