ETC/Talk

유니티 BMS 파싱 프로그램 진행상황

VallistA2015. 6. 21. 19:49

유니티 BMS 파싱 프로그램을 진행중에 있다.

이 블로그를 구독하는 사람중 많은 사람들이 유니티 BMS 파싱을 궁금해 할 것인데, 그래서 준비중에 있다.

거의다 제작에 완료가 되었다.

 

1. 가장 문제였던 유니티에서의 외부 파일 읽는 기능

 - 이미지 BMP 파일 리드 관련해서 유니티 이슈가 많았다.

 - 이미지 BMP 리드 문제 해결 및 음악 파일 파싱 완료

 

2. 대략적인 구조 완성

 - 최대한 Resources 폴더를 사용하지 않고, 최대한 Unity의 기능을 활용한 구조가 완성되었다.

 - 싱글톤을 이용한 게임 관리 및 키보드

 

 

 

실행 전 스샷

 

 

실행 후 스샷

 

필자는 Aci-L 이라는 BMS 를 테스트로 사용했다.

 

헤더 섹션 데이터를 가져온다.

 


데이터 섹션 리스트를 리스트로 불러옴

 

 

데이터 섹션안의 파싱 데이터.

 

 

댓글

  • BlogIcon 조던사랑2015.07.10 17:10 관심있게 지켜보는중인데용~ 파싱은 어떤방식으루 하셨는지 궁금해요~
    전 우연히 검색하다가 bms형식을 json으로 변환해서 유니티안에서 읽어와 처리하는 방식으로
    해봤는데 비슷하게는 되는거 같더라구요~
    판정부분이나 롱노트 같은건 어떻게 구현하셨는지 궁금하기두하고!!
    이 프로젝트도 공유하시는지.. 넘 기다려집니다! +_+
  • BlogIcon VallistA2015.07.10 22:51 신고 저는 json으로 읽진 않았구 그냥 .bms, bme 파일을 읽어버렸습니다 ㅎㅎ
    bms파일 규격도 원래는 txt 파일이니까요 ㅎㅎ

    json으로 변환해서 하는 방법도 생각해봤지만 용량이 너무 커져서 배보다 배꼽이 더 커지더라구요 용량을 압축하는 방법으로 바이너리 난독화를 이용해서 줄이는 것도 있지만 아무래도 bms파일 자체를 난독화및 암호화를 걸 필요성은 없어서 기본형으로 읽어옵니다

    아무래도 회사일하고 병행하고 있어서 쉽지않네요 ㅠㅠ
    그리고 유니티 코루틴으로 돌리니까 로드속도도 현저히 낮아지구요
    쓰레드 환경을 생각해보고 있는중 입니다 ㅠㅠ
  • 2016.01.03 13:42 비밀댓글입니다
  • BlogIcon VallistA2016.01.04 15:48 신고 안녕하세요.

    유니티로 BMS 파싱하는 과정은 일반적인 C# 에서 파싱하는 과정과 틀려집니다.

    기본적으로 파일 입출력은 C#을 이용할 경우, C#의 파일 입출력을 사용해서는 크로스 플랫폼 빌드가 되지 않습니다.
    PC기반이 아니고, 크로스 플랫폼을 기반에 염두를 하실 경우 유니티에서 제공하는 파일 입출력 방법을 최대한 사용을 해야하는데에 중점이 있습니다.

    기본적으로 유니티에서 지원하는 파일 경로는 유니티 프로젝트의 Assets/Resources 입니다. 다만 Resources 에 모두 몰아넣고 사용하기엔 사용자의 편의성이 사라지며, 이 사용자 편의성에 대해서 우리는 생각을 해봐야 합니다.

    파일 옵션에서 Resources 폴더가 아닌 다른 폴더로 변경하는 기능이 있다고 했을때 어디로 연결을 해야할까요?
    기존에 우리는 Resources.Load 로 파일을 가져올 수 있었는데. 이렇게 되면 파일을 제대로 가져오지 못하게 됩니다.

    이것을 이제 C# 파일 입출력을 이용해서 풀어야 하는데요. 파일 입출력을 할 때는 우리는 경로를 알고 있어야 합니다. 이 것에 관해서는 삽질을 조금 하셔야 할 수도 있습니다.

    자. 파일 입출력을 생각하는게 끝낫다 가정을 하고, 그 이후의 작업을 생각을 해봐야 합니다. 이제 여기서 BMS 파일에 대해서 파싱을 해야하는데 먼저 대상 파일을 찾아야합니다.

    bms 파일이 들어가있는 확장자는 아래와 같습니다.
    .bms, .bme, .bm...
    이런식의 파일을 검색해서 우리는 인식을 하여 파일들을 정렬해야 합니다. 정렬을 하는 이유는 난이도에 따라서 파일이 틀리기 때문입니다.
    기본적으로 normal, another, hard 등이 있겠죠? 그럼 난이도 순으로 정렬을 어떻게 하냐에 대해서 내부 파일을 파싱을 전부 해야합니다.

    이제 제일 중요한 내부 파일 파싱의 기능입니다. 이 파싱의 기능에서. 우리는 두가지를 나누어 봐야 합니다.

    1. 헤더 섹션
    헤더 섹션은 말그대로 타이틀 정보만 가지고 있습니다.
    우리가 게임에 플레이할 곡을 정하는 곡 선택 화면에 있다고 한다면, 거기서는 우리가 가지고 있는 곡들에 대한 내용을 가지고 있어야합니다. 예를들자면 아래와 같겠죠.
    Aci-L <hard> <another> <normal>
    Kronos <hard> <another> <normal>

    이렇게 데이터를 다 가지고 있어야 합니다. 그럴때는 곡에 대한 데이터정보를 가지고 있지 않고 타이틀 정보만 가지고 있는 겁니다. 일일히 모두 곡에 대한 데이터를 가지고 있다고 하면 메모리가 남아나질 않을겁니다.

    결론적으로 헤더 섹션은 실질적인 데이터가 아닌, 곡의 타이틀 명, 배속, 난이도 등등을 가지고 있고, 그 곡에 대한 노트 데이터는 가지고 있지 않다고 보시면 됩니다.
  • BlogIcon VallistA2016.01.04 16:03 신고 2. 데이터 섹션
    데이터 섹션은 말 그대로 파싱에 가장 중요한 노트 데이터를 가지고 있는 필드입니다.

    노트 데이터를 읽는 방법은 아래의 링크를 보시고 익히시면 됩니다.

    http://lab.gamecodi.com/board/zboard.php?id=GAMECODILAB_Lecture_series&page=1&sn1=&divpage=1&sn=off&ss=on&sc=on&select_arrange=hit&desc=asc&no=38
    위는 C# 파싱기 개발입니다.

    http://cosmic.mearie.org/2005/03/bmsguide/
    위는 레퍼런스 사이트 입니다

    여기서 읽어도 이해가 안되실 텐데 예를 들도록 하겠습니다.

    #00213:0015
    #00215:0000002C00000000

    예를들어 이런 형식의 데이터가 있습니다.
    #은 명령어 메소드이며, 우리가 코딩을 짤때 # 이후로 부터 검출을 해내시면 됩니다.

    검출을 순서대로 해보겠습니다.
    1. #이후로 3개의 숫자
    - 이것은 Bar의 번호 입니다.
    위의 형식의 데이터에서는 각각 2와 3을 나타내겠죠?
    그러므로 Bar의 번호는 2,3 입니다.
    Bar는 노트가 내려오는 한 줄이라고 생각하시면 됩니다

    2. 그 이후 2글자. #***(**) <- 괄호친 부분
    위에서는 각각 13, 15를 나타내며, 채널 번호입니다.

    이제 데이터 정보를 가져 왔으면 데이터를 기반으로 하여 노트를 뿌려주시면 됩니다.

    궁금한 정보 있으시면 덧글 부탁드립니다.
  • 2016.04.15 00:40 비밀댓글입니다
  • BlogIcon VallistA2016.04.15 09:25 신고 깃허브에 공유된 소스코드는 Cocos2d-x로 BMS를 연동한 소스코드 입니다.

    유니티 소스코드의 경우에는 제가 분실을 해서...
    방향이나 가능성에 대해서는 구체적으로 언급을 해주셔야 말씀 드릴 수 있을 것 같습니다.
  • 안녕하세요2016.06.09 23:40 안녕하세요 리듬게임을 만들고 있는 학생입니다.
    파싱 관련해서 궁금한게 있어서 질문 하려고 하는데
    BMS 파일의 데이터 부분에서

    #00101:0K000000000L00000M0N0O0P

    001이 마디 번호고 01이 BGM : 이후가 데이터 인건 알겠는데
    #00101:00002P2Q002R0000002S002S
    #00101:00
    #00101:00
    #00101:00
    #00101:00
    #00101:00
    #00101:2A002B2A002B2A002B2D002B
    이런 식으로 같은 마디에서 같은 채널을 여러번 호출 하는경우 의미를 잘 모르겠습니다 ㅠㅠ
    같은 라인에 있는걸 동시에 출력 하라는 건지 아니면 순차적으로 전부 재생해야 하는건지 혹시
    알려 주실수 있나요??
  • BlogIcon VallistA2016.06.10 13:12 신고 01 채널은 배경음 채널이라서 그냥 그 마디 위치에 뿌려주시면 됩니다.

    예)
    #00101:00002P2Q002R0000002S002S 이거는 드럼 배경음
    #00101:2A002B2A002B2A002B2D002B 이거는 바이올린 배경음

    이렇게 노트 찍는 사람 (노터) 가 보기좋게 해놓은 것이라 보시면 됩니다.

  • 안녕하세요2016.06.11 07:02 아 그럼 멀티스레드를 통한 동시 재생이 맞는거겠군요 ㅎㅎ
    감사합니다. 계속 이해가 안됬는데 확풀렸네요 ㅎㅎ
  • MUSE2016.08.27 11:21 안녕하세요 리듬게임을 개발하고있는 학생입니다 .

    그런데 저는 위와같은 노트 구성을 하기보다는 음악에 쓰이는 여러 악기 파트 중

    드럼파트만 BMS 파일로 만들고 싶은데 그중에서도 발베이스 소리만 만들고 싶습니다 .

    이렇게 음악의 특정 파트만 BMS 데이터로 추출이 가능한가요 ?
  • BlogIcon VallistA2016.08.29 13:39 신고 추출이라기보다. BMS는 만들어진 음악을 다단부분을 잘라서 그 음악부분을 노터라고 하는 분들이 노트를 찍어서 결과물이 나오는 것 입니다. 그게 바로 BMS 이므로, 질문하신 추출이라고 하는 부분은 일일히 짤라서 그 부분만 대입해주면 된다고 봅니다.
  • 2016.09.23 18:48 비밀댓글입니다
  • BlogIcon VallistA2016.09.26 21:25 신고 1. 저는 추출하기 전 반드시 순차적으로 넣기 위해서 정렬과정을 한번 거칩니다. 정렬 한번 해주시고 List에 넣을때 Dictionary로 해서 int 로 순서 매겨주세요.

    2. 네 저는 리스트 하나에 다 때려박고 리스트 전체를 움직였습니다.

    3. 롱노트는 저는 따로 계산하였습니다.
    제작을 했어용. 04 지점에서 04 지점까지 배치를 했습니다 스프라이트 늘려서.

    4. 싱크는 저는 실시간으로
    double dBarperSecond = ((4 * 60) / D_ASSET_MNG->getBPM());
    double dBarDownTime = D_MAX_NOTEFIELD_HEIGHT * (dt / dBarperSecond);
    요 부분에서 dt값 계산해서 넣어주었습니다.
댓글쓰기 폼

VallistA

병특이 끝나서 게임에서 웹으로 스위칭한 프로그래머.
프로그래밍 정보등을 공유합니다.

자고 싶습니다. ㅠㅠ

페이스북    :: 링크
카카오톡    :: kingbye1
Github      :: 링크

궁금한점 문의 주시면 답변드리도록 하겠습니다

VISITED

Today : 66

Total : 413,759

SNS

  • 페이스북아이콘
  • 카카오톡아이콘
  • 트위터아이콘