plitri

검색어 '게임제작'로 3개의 글을 찾았습니다.

  1. 2016.01.31 [번역] 어떻게 리듬게임을 음악이랑 맞추나요? (레딧 댓글) 
  2. 2015.02.15 네모밍 week 3 
  3. 2015.02.11 네모밍 week 2 

[번역] 어떻게 리듬게임을 음악이랑 맞추나요? (레딧 댓글)

2016.01.31 19:34기타

이 글은 번역입니다. 대충 의역한 부분이 많으니 찰떡같이 알아들으세요.
https://www.reddit.com/r/gamedev/comments/13y26t/how_do_rhythm_games_stay_in_sync_with_the_music/c78aawd

반가워요. 저는 리듬게임을 작업한 적이 있습니다. (영상, 영상, 영상)

고려할 게 두 가지가 있습니다. 가장 중요한 하나는 어떻게 플레이어의 입력을 정확하게 받아들이는 걸 보장해서 플레이어가 정확하게 보상받는 것처럼 느끼게 하느냐이고, 약간 덜 중요한 하나는 그래픽이 음악에 맞도록 보장해서 노트와 음악이랑 사용자 동작이 들어맞는 것처럼 보이게 하는 것입니다.

두 번째 거, 그러니까 사용자 동작/그래픽이랑 음악이 맞도록 하는 것부터 시작하겠습니다. 만드는 게임이 DDR이나 기타히어로랑 비슷해서, 음악이 재생하는 것에 따라 노트가 "판정선"(strum bar)을 향해 떨어지고, 노트가 그 막대기에 닿는 순간 플레이어는 키를 눌러야 한다고 가정해봅시다. 쉽네요. 그쵸? 그냥 이런 함수를 쓸 수 있겠죠.

(역주: 쓰지 마세요! 이후를 위한 예제입니다.)

renderNoteFallingDownScreen(id:int) {
    note[id].y = strumBar.y - (mySong.position - note[id].strumTime);
    // 노트[id].y = 판정선.y - (노래.현재위치 - 노트[id].판정시간);
}

이제 이런 함수를 썼고, 컴파일을 할 테지만, 놀랍고도 무섭게도, 모든 게 엉망진창입니다. 노트는 버벅버벅 더듬거리고[각주:1], 마침내 가까스로 아래로 내려와도, 특히 프레임이 떨어진[각주:2] 동안에는 판정선에 노래의 한 0.5초 이후에 도달할 겁니다. 그래서 이게 뭔 말인데요?

먼저, 노래 파일을 재생하는 대부분의 환경에서 (아니면 최소한 제가 작업했던 환경에서 : AS3, javascript, C#), 음악 파일의 정확한 재생위치, 그러니까 충분한 비율로 갱신되는 (~60FPS) 재생 위치를 얻기란 매우 어렵습니다. 모든 게 완벽한 세계에서, 매 프레임마다 음악의 재생 위치를 추적하면, 이런 결과가 나올겁니다.

0, 17, 33, 50, 67, 83, 100, 117, 133...

하지만 실제 세계에서는, 결과는 이런식으로 나올 겁니다.

0, 0, 0, 0, 83, 83, 83, 133, 133, 133, 133, 200, 200...

정확하고 일관적인 결과를 주는 대신, 재생위치는 건너뛰며[각주:3] 갱신될 겁니다. 이제 멀티플레이어 게임에서 보간하는 것과 똑같이 이 건너뛴 사이들을 보간[각주:4]해야겠죠.

이걸 하는 가장 쉬운 방법은 재생 위치를 특정 변수에 보관해놓고, 매 프레임마다 자동으로 시간을 더하는 거겠죠. 다음은 별로 안 좋은 방법입니다.

everyFrame() {
    songTime += 1000/60; // 1초에 1000ms, 1초당 60프레임
}

그리고 이걸 하는 약간 더 나은 방법입니다.

songStarted() {
    previousFrameTime = getTimer();
}

everyFrame() {
    songTime += getTimer() - previousFrameTime;
    previousFrameTime = getTimer();
}

// OR:

songStarted() {
    startTime = getTimer();
}

everyFrame() {
    songTime = getTimer() - startTime;
}

하지만, 이 세 방법은 모두 완벽하지 않습니다. 아니, 좀 더 정확히 하자면, 여러분의 음악 재생 방식이 완벽하지 않습니다. 어느쪽이 됐던, 갑작스럽게 여러분의 쬐끄만 변수 songTime은 실제 노래의 재생위치와 어긋나게 될 거라는걸 의미합니다. 특히 재생 환경이 음악을 건너뛰고, 버퍼링하고, 뭉개고[각주:5] 하는 환경이라면 이런 일이 일어날 가능성이 높습니다 - 웹 게임이나 파일에서 노래를 재생하는 대신 스트리밍해서 노래를 재생하는 게임 같은 경우 말이죠. 또, 대부분의 음원 재생 루틴은 극초반에 재생할 때 머뭇거리기[각주:6] 때문에, 어긋난 상태로 재생될수도 있습니다 - 특히 인코딩 데이터를 구워놓은 MP3 파일을 쓰고있다던가[각주:7], 느린 하드디스크에서 오디오 파일을 읽어오고 있다던가, 여러분의 게임이 쓰레기같은[각주:8] 크롬의 내장 "pepperflash" 플러그인을 쓰고있다면 말이죠.

그래서, songTime을 불러오고 실제 음원 파일의 재생위치에 맞도록 유지하기 위해, 매번 재생 위치를 새로 가져올 때마다 그 값을 교정하기 위한 기본적인 보간[각주:9] 알고리즘을 사용하고 싶군요. 이렇게요.

songStarted() {
    previousFrameTime = getTimer();
    lastReportedPlayheadPosition = 0;
    mySong.play();
}

everyFrame() {
    songTime += getTimer() - previousFrameTime;
    previousFrameTime = getTimer();
    if(mySong.position != lastReportedPlayheadPosition) {
        songTime = (songTime + mySong.position)/2;
        lastReportedPlayheadPosition = mySong.position;
    }
}

이 함수는 수동으로 추적중인 songTime 변수를 자동으로 가져와서 새 재생위치를 알게 되었을 때마다 실제 알아낸 재생위치와 평균을 낼 것입니다. 새로운 재생위치를 받았을 때에만 이렇게 하는데요, 새로운 값[각주:10]을 받는 사이사이에 "계단진" 값을 향해 계속 보간[각주:11]하다보면, 또다시 버벅거리는[각주:12] 재생위치를 얻게 될 것이기 때문입니다. 그 대신, 새로이 값을 받아올 때까지는 계속 수동으로 songTime을 증가시킬 것입니다.

하지만 아직 재밌는 부분이 끝난 건 아니죠!


※ 이 부분은 @Tis_Lenia 님에 의한 번역입니다. 늦은 반영 죄송합니다. 검토는 하지 않았습니다.

보시면 알다시피, 모든 렌더링 경로(pipelines)는 각각 상이한 지연 시간을 갖습니다: 지연 시간에는 영상(scene) 자체를 렌더링하는데 소요되는 시간과 사용자의 모니터 자체에 띄우는 작은 딜레이가 포함이 됩니다. (만일 사용자가 일반 모니터가 아닌 TV와 같은 디스플레이를 사용할 경우 후자의, 화면에 띄울 때 소요되는 시간은 늘어납니다.) 그래픽(영상) 화면에 뜨는데 발생하는 딜레이에 더하여 플레이어가 키보드를 누르고 그 입력이 프로그램에 전송될 때에도 딜레이가 발생합니다. 대부분의 게임에서 키 입력상에서 발생하는 딜레이는 무시해도 큰 문제가 되지 않으나, 리듬게임에 있어서는 이 딜레이는 철저한 계산이 요구되며 이는 제작자가 다른 게임에서는 무시되는 키 입력상에서 발생하는 이 딜레이를 고려해야함을 의미합니다.

허나 불행하게도, 모든 플레이어가 같은 모니터와 입력 장치를 사용하지 않는데, 이는 playhead에 삽입할 일정한 공통 기준이 존재하지 않음을 의미합니다. 따라서 타 리듬게임, Rock Band나 Guitar Hero에서 채용하고 있는 것과 같이 플레이어가 딜레이를 시각적으로 확인/조정할 수 있는 테스트가 필요합니다. 앞에서 언급된 두 리듬게임은 두 테스트를 사용하는데 이 중 하나에 대해 먼저 언급한 후 나머지를 설명하겠습니다.

이 테스트를 하는데에는 다양한 방식을 사용할 수 있습니다. 화면을 일정한 패턴으로 깜빡이는 것으로 딜레이 시간을 측정하는 것이나, 혹은 메트로놈(연주에 사용하는 박자기) 같이 시각적인 지표(노트)를 주어 플레이어에게 이에 맞춰 키를 누르게 하는 방법을 사용할 수도 있습니다. 이 테스트를 할 때에는 영상의 딜레이를 확인하기 위함이지 음향의 딜레이를 확인하는 것이 아니기 때문에 음악을 재생하여서는 안됩니다. 매 순간 화면이 깜빡일 때 (혹은 메트로놈이 똑딱일 때) 그 사이의 시간을 측정합니다. 그 다음에 플레이어로부터 키 입력을 받고 그 사이의 시간을 또 측정합니다. 화면을 깜빡일 때 발생한 딜레이를 키 입력까지 발생한 딜레이에서 뺀 시간이 시각적(영상) 딜레이입니다.

이론적으로는 시각적(영상) 딜레이는 렌더링 딜레이와 키입력의 딜레이의 합이기 때문에 마이너스의 값이 발생할 수 없으나 플레이어가 습관적으로 실제로 입력해야한다고 생각하는 순간보다 노트를 빨리 입력하는 버릇이 있을 수도 있습니다. 만일 플레이어가 이와 같은 습관을 가지고 있고 모니터와 입력 장치 모두 딜레이가 짧은 장비들이라면 마이너스의 딜레이를 갖는 것도 불가능하지는 않습니다. 따라서 게임을 제작할 떄 이 이론상으로 존재할 수 없는 마이너스 값의 딜레이에도 대응할 수 있도록 해야합니다.

또한 중요한 점은, 15초에서 30초 정도는 이 테스트를 진행해야 신뢰할 수 있는 테스트 결과가 나온다는 것입니다. 다양한 변수로 인하여 일관적인 딜레이 값을 측정하는데 방해가 발생할 수 있기 때문에 한번의 일련의 딜레이 측정 테스트로는 신뢰할 수 있는 결과를 도출하기 어렵습니다. 이런 방해 요소는 렌더링, 키 입력 과정과 더불어 플레이어의 테스트 중 규칙적인 키 입력에서도 발생할 수 있습니다. 그렇기 때문에 반복된 검사를 진행하여 영상 딜레이의 평균값을 구합니다.


글을 대충 읽고 저는 이런 걸 짰는데요, 이것도 나쁘지 않은 것 같지만,

자세히 읽어보니 반으로 나누는 보간하는 부분이 있었군요. 보간이 있는 쪽이 없는것보다 나을 것 같긴 하네요.

아무튼 앞부분의 중요 내용은 "값이 계단지게 띄엄띄엄 나온다" 이고, 그 부분을 커버해줄 수 있는 알고리즘이 있으면 충분하지 싶습니다. 이렇게 해놓으면 싱크가 어긋나는 일은 없겠죠.

뒷부분의 딜레이 관련 내용은 귀찮으면 그저 유저에게 맡기면 되는 문제... 니까요. 오프셋 조절하셈 하고 던져주면 되는 (..

  1. jittery/stuttery [본문으로]
  2. dip [본문으로]
  3. in steps, "단계별로"가 일반적인 번역이겠지만 의미가 와닿지 않을 것 같아서 수정 [본문으로]
  4. interpolate. "선형 보간"을 검색해보세요. 찾을 시간이 없으시면, 사잇값을 구한다는 느낌으로 받아들이시면 될 듯. [본문으로]
  5. skip, buffer, or crash [본문으로]
  6. hiccup [본문으로]
  7. 이 구문은 무슨 말인지 몰라 그대로 적었습니다. if you're using MP3 files that have encoding data baked in [본문으로]
  8. piece of shit (똥조각) [본문으로]
  9. easing [본문으로]
  10. 원문에 valuable이라고 되어있는데, variable의 오타일 겁니다. (자동완성의 폐해...) [본문으로]
  11. easing [본문으로]
  12. stuttery [본문으로]

네모밍 week 3

2015.02.15 17:30제작일지/네모밍

3주째는 안 만들줄 아셨죠? 유감! 손 대긴 했답니다~

진행한 것들


저번주.. 아니 수요일에는 가로줄 긋는 방식으로 표시했었는데 이번엔 그냥 한 것만 직접 쓸래요. 다른 페이지를 열기 귀찮아서 그런 건 맞고요... (엉? 뭐라고요?)

  • 두 번 누르는 블록 추가
  • 블록의 임시 이미지를 더 귀여운 임시 이미지로 변경 [*^o^*]
  • 구글 플레이 스토어에 알파 버전 게시
  • 버튼 누르는 타이밍의 모양 변경,  시계 배경을 포인터로 모양을 변경 (가독성)

알파 버전

사실 이름만 알파버전이지, 알파 베타 구분 없이 현재 제작중인 걸 폰으로 내보낼때마다 수동으로  설치했어야 했는데, 그게 귀찮아서 올린겁니다. 어차피 플레이에는 등록할 예정이었고요. 귀차니즘을 무릅쓰고 급하게 등록해보았습니다.

근데 테스트 버전도 어김없이 구글 플레이에 게시하는 딜레이는 있더군요. 흑.. 얼마나 더  기다려야 되려나

제작 양에 대한 변

제작량이 적습니다. 목요일부터 오늘까지니 적을 수 밖에요... 라기보단 정말로 이대로 그냥 시간을 보내다간 일주일 이상 버려두게 될 거 같아서, 그래서 어디까지 만들었는지 까먹어버리고 결국 버려지는 프로젝트가 될 거 같아서 가까스로? 잡아서 진행했습니다. 시간이 얼마 없었던 만큼, 최우선 목표인 추가 블록 타입을 먼저 구현했죠.

실제로 이 작업은, 절반은 금요일 오후, 디버깅?은 집에 내려가는 기차 안에서 이루어졌습니다. 그게, 어째서인지 배경의 선이 안 그려지더라구요. 그거 잡는다고 좀 걸렸어요. 자세히 보니 단순한 문제였더라구요.. 으으

받은 피드백

동생한테 보여줬더니 어디로 가야하는지 방향을 가리키는 화살표가 뒤의 잇는 선들에 있었으면 좋겠다고 했습니다. 이건 프로토타입 1, 2에는 있었던건데 현재에는 없는 부분이죠. 그게, 선의 두께가 달라지는 관계로 제작하기 좀 골치아프겠지만, 긍정적으로 생각해볼까 합니다. 시간이 남을때에? 정신적 여유가 있을 때에?

다음 할 것

드디어 이 차례네요. 귀찮으니 과거 글에서 목록을 가져오는 대신 직접 적겠습니다.

  • 추가 블록종류 1개 더 구현 (여기까지가 다음주까지의 최소지점)
    • 드래그 블록
    • 드래그 블록만해도 구현이 꽤나 복잡하기에 다른 블록에 대한 구현은 아이디어를 기록하는 정도로 하려고 합니다.
    • 잊기 전에 아이디어 : 이펙트 선택 블록 (2개가 동시에, 둘 중 하나만)
  • 시퀀스 (여기까지가 다음주까지의 최대지점)
    • 시퀀스 방식의 결정 : 랜덤 / 미리 정해진 것 / 부분 랜덤?
    • 시퀀스의 구현
    • 지금은 블록들이 랜덤하게 나오고있고, 비율이나 확률에 대한 조절도 없습니다. 이러한 부분을 어떻게 할 것인가 고민하고 결정해야 하는 일이 남아있습니다.
  • 조금 먼 미래에 만들기
    • 메뉴
    • 모드 기획?

뭐 이 정도군요.

마무리

오늘 게시글은 좀 일본어투가 많이 섞인 거 같네요. 알 게 뭐야~

웹으로든 오프라인으로든 저와 서로 알고계신 분들께서 제작중 체험 (알파 테스터 등록)을 원하신다면 언제라도 트위터 @sftblw 로 멘션 넣어주세요! 이 글의 댓글도 괜찮아요.

'제작일지 > 네모밍' 카테고리의 다른 글

네모밍 week 3  (0) 2015.02.15
네모밍 week 2  (0) 2015.02.11
네모밍 w1u1  (0) 2015.02.01

네모밍 week 2

2015.02.11 14:39제작일지/네모밍

게을러서 저번 주말에 올라왔어야 했는데 늦었습니다. 죄송합니다

수요일이네요. 이번주 월 ~ 지금 작성하는 때까지는 어떠한 작업도 하지 않았습니다. (어째서...


달성사항

크게 Prototype 1의 수준까지 진행하였습니다. 안드로이드 앱으로 테스트도 해보았고, 제 기기에서 이상없이 동작했습니다. Intel XDK도 오랜만에 업데이트하고...

  • 기본 게임 로직
    • 이펙트 : 블록 파괴시 1/n의 상자로 나뉘어 사라지기 (상단 포물선)
  • 기본적인 체력 기능
    • 상자에 타이머 출력 (프로토타입 1) → 시계 모양으로 넣었습니다. 하지만 옛날 방식이 더 좋은듯
    • 상자의 타이머가 0이 되면 체력 깎이기 (프로토타입 1) → 한 여기까지 구현을 예상하고 있습니다.
    • 시퀸스 기능
      • 시퀸스 기능의 구현
      • 시퀸스 완료시 체력 회복
  • 디스플레이
    • 상자끼리 잇는 선을 가까움에 따라 다른 굵기로 출력 (프로토타입 1) → 굵기 외에도 투명도도 조절되도록 하여 좀더 가독성을 늘렸습니다.

추가로 한 작업.. 으음... SpriteFont로 격파한 갯수를 기록하는 건 예전에도 있었고.. 흐음... 별 건 없군요.

블록을 결국 일반화했습니다. 패밀리로 옮겼기에 이후에 블록 추가 작업이 더 수월해질 것입니다.

다음 목표

  • 블록 종류 다양화
    • 당장 생각나는 두 가지
      • 2회 이상 터치
      • 드래그해서 해당 장소에 끼워맞추기
  • 시퀸스 기능
    • 시퀸스와 체력, 회복의 관계에 대한 디자인 결정
    • 시퀸스의 구현

이것만 해도 힘들겁니다. 블록 종류 다양화는 쉽게 할 수 있을텐데, 시퀸스 기능이 좀 많이 복잡해보이는군요.

마무리는 복붙으로

언젠가 해야하는 다음 마일스톤

  • 다른 종류의 블록 (네모) 만들기
  • 귀여운 네모 그림
  • 아케이드모드
  • 상점, 아이템 → 이게 완료되면 릴리즈
  • 스테이지모드 (스토리모드)


'제작일지 > 네모밍' 카테고리의 다른 글

네모밍 week 3  (0) 2015.02.15
네모밍 week 2  (0) 2015.02.11
네모밍 w1u1  (0) 2015.02.01
1