2018/01/02 - [Programming/Unity] - [유니티/C#/리듬게임] 2. BPM이란?
이전 포스팅에서는 BMS파일 구조와 BPM에 관하여 살펴보았으니 이번 포스팅부턴 실제로 개발해봅시다.
코드에 아직 미숙한 부분이 많아도 차차 개선할 예정이니 알고리즘 참고로는 괜찮지 않을까 싶습니다.
시작해봅시다!
일단 먼저 UI 틀부터 잡았습니다. 물론 구조부터 짠 다음, 진행하는게 수월합니다만.
이것저것 신경쓸 부분이 많더군요.
저는 기능 모듈별로 코딩 한다음, 모듈끼리 연동 하면서 디버깅 하는 방식으로 진행해 볼까 합니다. 사실 시간이 부족한 것도 있는데, 귀찮은게 더 큰건 함정.
곡 선택 Scene의 하이어라키 뷰 구조입니다. 마스터 패널 내부에서 오브젝트를 한꺼번에 관리합니다. 개발 도중에 포스팅 하는 상황이라 UI는 변경될 수 있습니다.
마스터 패널 내부에서 캔버스로 UI를 그려주는데,
곡 정보 뷰인 Info와 곡 리스트 뷰인 Song List로 나누었습니다.
Info에서는 말 그대로 곡 정보와 썸네일 이미지를 BMS파일의 헤더를 파싱하여
오른쪽 상단에 Title, Artist, Genre, BPM, Playlevel, Rank 등 곡 정보와
왼쪽 상단에 해당 곡 이미지를 파싱하여 UI에 뿌려줍니다.
Song List에서는 하단 패널에서 좌, 우 스크롤링하여 List로 구현할 예정입니다.
타깃은 모바일, PC 둘다 타깃으로 잡아 버튼 형식으로 List를 스크롤할 예정입니다.
일단은 현재까진 곡 정보를 불러오는 파싱작업부터 완료하였기 때문에 하단 스크롤 List는 나중에 포스팅 하겠습니다.
일단 헤더 파일 부분만 파싱하는 이유는 곡을 선택할때마다 데이터 파일까지 파싱 할 경우, 프레임 드랍이 되는 경우를 막기 위해 헤더 파일 부분만 파싱합니다.
헤더 파일에서도, 현재 Scene에서는 선택한 곡의 정보만 필요하기 때문에 필요한 부분만 파싱합시다.
위 사진에서 빨간색 박스 내부의 내용만 필요하기 때문에 아래 WAV 파일을 지정하는 부분은 지금 파싱하지 않습니다.
아래는 코드입니다. 아직 수정할 부분이 많아서 좀 더럽긴 하지만 참고하는 용도 정도는 되지 않을까 싶습니다. 코드 보시고 궁금한점이 있으시면 댓글달아 주세요.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | using System.Collections; using System.Collections.Generic; using UnityEngine; using System.IO; using System; using UnityEngine.UI; public class SongInfoLoading : MonoBehaviour { public Transform ParentObj; // 파싱한 데이터를 저장하기 위한 부모 오브젝트 public Transform[] tpList; // 자식 오브젝트를 저장하기 위한 배열 public string[] songList; // 곡 이름을 저장하는 문자열 배열 public int index; // 몇번째 곡이 선택되었는지 표시하는 인덱스 변수 //=================================== Data Parse public void ParseData(int index) // 파싱한 곡의 정보를 입력하는 메소드, 정수형 파라미터로 오브젝트를 구분함. { string temp = ""; // 임시코드, Title, Artist 등 헤더 파일 값을 저장. tempStr = ""; for (int i = 1; i < tempSplit.Length; i++) // #TITLE ~ [#TITLE] 을 자른 나머지 데이터를 취합한다. (곡 제목, 아티스트 등) 데이터 저장 { tempStr += tempSplit[i] + " "; // 공백 혹은 콜론 구분자로 문자열을 잘랐으나, 콜론의 경우 데이터 파싱 부분에서만 사용하기 때문에 공백을 추가하여 누적한다. } temp = tempSplit[0].Substring(1, tempSplit[0].Length-1); // 18번 라인에서 언급한 [Title]의 문자열 저장. //Debug.Log(temp); tpList[index].GetComponent<Text>().text = temp + " : " + tempStr; // 파싱한 데이터를 각 자식 오브젝트의 Text에 뿌려줌. } //=================================== Data Parse //=================================== Image Parse public void ParseBackImg(int index) // 파싱한 곡의 이미지를 뿌려주는 메소드, 이 또한 정수형 파라미터로 오브젝트 구분 { SpriteRenderer spriteRenderer; // 이미지 오브젝트의 spriteRenderer component를 사용하여 이미지를 변경한다. spriteRenderer = tpList[index].GetComponent<SpriteRenderer>(); // 오브젝트의 spriteRenderer component를 가져옴. Sprite sp = Resources.Load<Sprite>("Song/"+SongName+"/BG"); //이미지 리소스파일 이름은 BG로 통일 할 예정이며, 47번 라인에서 선언한 음악 파일 이름으로 이미지를 구분. spriteRenderer.sprite = sp; // sprite 변경 } //=================================== Image Parse protected FileInfo fileNmae = null; // BMS 파일을 열기위한 파일 제어 클래스 protected StreamReader reader = null; // 파일 스트림을 읽기 위한 StreamReader protected string path; // 곡 파일 path protected string StrText; // 파일을 한줄씩 읽었을때 저장하는 문자열 protected string SongName; // 이미지 파일을 파싱할 때 상대경로로 지정하는 임시 변수, 추후 수정 할 수 있음. private char[] seps; // 구분자, [공백과 콜론]으로 구분. private string[] tempSplit; // 위 구분자로 파싱한 문자열을 잘라 담는 임시 문자열 배열 private string tempStr; // 자른 문자열 데이터에서 자식 오브젝트의 Text에 저장할 임시 문자열, 추후 수정할 수 있음. // Use this for initialization void Start () // 스크립트 호출시 시작. { //========== initializing index = 0; tempSplit = null; tempStr = ""; StrText = ""; SongName = ""; path = "Assets/Resources/Song/"; seps = new char[] { ' ', ':' }; //========== initializing SongName = songList[index]; // 곡 이름은 List에서 담은 값으로 저장, 추후 변경 가능 path = path + songList[index] + "/"; // 42번 라인에서 저장한 root path에서 해당하는 곡의 경로를 저장 fileNmae = new FileInfo(path + songList[index]+".bms"); // 해당 곡의 BMS 파일을 파싱하기 위한 코드, BMS파일을 지정 if (fileNmae != null) //파일이 NULL이 아닐 경우 실행 { reader = fileNmae.OpenText(); // BMS 파일을 Open한다. } else // 파일이 NULL일 경우, 디버그로 에러 검출 { Debug.Log("65Line, BMS Parse Error"); } tpList = ParentObj.gameObject.GetComponentsInChildren<Transform>(); // ParentObj의 Transform components가 있는 자식들을 가져옴 / 자식들 전체를 가져옴. } // Update is called once per frame void Update () // Update문은 추후 코루틴(Coroutines)을 사용하여 변경 예정 { if(StrText != null && StrText != "*---------------------- HEADER FIELD END") // BMS파일에서 읽어온 문자열이 null이 아니면서 [*---------------------- HEADER FIELD END] 이 아닐때. // 원하는 헤더파일 부분만 읽기위해 작성. { StrText = reader.ReadLine(); // BMS파일을 한줄씩 읽음. tempSplit = StrText.Split(seps); // 구분자(공백, 콜론)으로 읽어온 문자열을 자름 if (tempSplit[0].Equals("#TITLE")) // 자른 문자열이 #Title일때 { ParseData(2); }else if (tempSplit[0].Equals("#ARTIST")) { ParseData(3); }else if (tempSplit[0].Equals("#GENRE")) { ParseData(4); }else if (tempSplit[0].Equals("#BPM")) { ParseData(5); }else if (tempSplit[0].Equals("#PLAYLEVEL")) { ParseData(6); }else if (tempSplit[0].Equals("#RANK")) { ParseData(7); }else if (tempSplit[0].Equals("#STAGEFILE")) // 자른 문자열이 이미지 파일 데이터일때 { ParseBackImg(10); } else { Debug.Log("[NotErr]Nothing : " + StrText); //에러X 확인용 디버그 코드 } } } } | cs |
코드 부분을 살펴보면 무식하게 Update 함수에 코딩한 것을 볼 수 있습니다.
이 부분은 추후 코루틴(Coroutines)을 다루면서 수정하겠습니다.
다음 포스팅에서 UI와 함께 다시 살펴봅시다.
'Programming > [Unity]' 카테고리의 다른 글
[유니티/C#/리듬게임] 2. BPM이란? (0) | 2018.01.02 |
---|---|
[유니티/C#/리듬게임] 1. BMS에 관하여. (0) | 2018.01.02 |