0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

C3Advent Calendar 2022

Day 7

Unityで音ゲー制作するためにUnityEditor拡張したよ

Last updated at Posted at 2022-12-06

前置き

ゲームとかイラストとかBotとか書いてるHayaoです。

今、音ゲー制作をやってます。
ようやくα版がリリースしました。この制作の上で自作のUnityEditorを作ったのでそれを紹介します。

作ったもの

音ゲーと制作する上で必要になってくる譜面を製作するためのUnityEditorです。

そもそも

音ゲー作る上で一番きつい部分はどこでしょうか?
私自身が一番きつい部分は譜面制作です。(個人差あり)

で、私はCSVファイルに書き込み、それをUnity上で読み込むというふうにシステムを作り出しました。
ただ・・・・

image.png

これを手書きするのは面倒くさい・・・・
ということで自作でUnityEditorを作りました。うおーーー-

完成物

実際に作ったものは以下のものです。
image.png

機能

これはaddblockという自作Editorで何小節目のどこかを指定してそれをCSVファイルに書き、画面上に反映させるものです。

作り方

実際にどのように作っていったか。部分的ではありますがコードを載せたいと思います。

まず縦線を表示する部分です。

Editor.cs
for (int i = 0; i <= lineCount; i++)
{
    var spos = new Vector3(xpos, 20.0f);
    var vector = new Vector3(xpos, 2.5f, 0f);
    var beat_4_top = new Vector3(before_xpos_per, 20.0f, 0f);
    var beat_4_bottom = new Vector3(before_xpos_per, 1000.0f, 0f);
    var beat_8_top = new Vector3(before_xpos_per, 20.0f, 0f);
    var beat_8_bottom = new Vector3(before_xpos_per, 1000.0f, 0f);
    var beat_12_top = new Vector3(before_xpos_per, 20.0f, 0f);
    var beat_12_bottom = new Vector3(before_xpos_per, 1000.0f, 0f);
    var beat_16_top = new Vector3(before_xpos_per, 20.0f, 0f);
    var beat_16_bottom = new Vector3(before_xpos_per, 1000.0f, 0f);
    int beat_count_4 = 0;
    int beat_count_8 = 0;
    int beat_count_12 = 0;
    // baseLinePosは起点のPosition
    if (i % 5 == 0)
    {
        vector.y = 0f;
    }
    EditorGUILayout.LabelField(i.ToString(), GUILayout.Width(perspace-3f));
    Handles.DrawLine(spos, vector);
    if(xpos != 0.0f){
        for(int beat = 0; beat < 16; beat++){
            beat_16_top.x = (space * scale) / 16 + beat_16_top.x;
            beat_16_bottom.x = beat_16_top.x;
            var beatColor = Handles.color;
            Handles.color = new Color(35f,35f,35f,0.1f);
            Handles.DrawLine(beat_16_top, beat_16_bottom);
            Handles.color = beatColor;
            if(beat_count_4 < 4){
                beat_4_top.x = (space * scale) / 4 + beat_4_top.x;
                beat_4_bottom.x = beat_4_top.x;
                beatColor = Handles.color;
                Handles.color = new Color(35f,35f,35f,0.4f);
                Handles.DrawLine(beat_4_top, beat_4_bottom);
                Handles.color = beatColor;
                beat_count_4++;
            }
            if(beat_count_8 < 8){
                beat_8_top.x = (space * scale) / 8 + beat_8_top.x;
                beat_8_bottom.x = beat_8_top.x;
                beatColor = Handles.color;
                Handles.color = new Color(35f,35f,35f,0.3f);
                Handles.DrawLine(beat_8_top, beat_8_bottom);
                Handles.color = beatColor;
                beat_count_8++;
            }
            if(beat_count_12 < 12){
                beat_12_top.x = (space * scale) / 12 + beat_12_top.x;
                beat_12_bottom.x = beat_12_top.x;
                beatColor = Handles.color;
                Handles.color = new Color(35f,35f,35f,0.05f);
                Handles.DrawLine(beat_12_top, beat_12_bottom);
                Handles.color = beatColor;
                beat_count_12++;
            }
            before_xpos_per = xpos;
        }
    }
    xpos = xpos + space * scale;
}
Handles.DrawLine(startPos, endPos);
Handles.color = prev;
EditorGUILayout.EndHorizontal();

このEditorでの1目盛りは1小節のため4分、8分、12分、16分で縦線を引いています。

次に降ってくるブロックを設定する部分です。

Editor.cs
if(!EditMusicScore.GetisPlay() && !canSet){
    startime = EditMusicScore.GetMusicTime();
    endtime = EditMusicScore.GetMusicTime();
    canSet = !canSet;
}
if(GUILayout.Button("Add File")){
    filepath = EditorUtility.OpenFilePanel("Open csv", "", "CSV");
    if(filepath == null){
        return;
    }else{
        filename = Path.GetFileNameWithoutExtension(filepath);
    }
}
GUILayout.Space(15f);
GUILayout.Label("Time or Measure");
_StartWirteIndex = GUILayout.SelectionGrid(_StartWirteIndex, WriteTipe, 3);
if(_StartWirteIndex == 1){
    GUILayout.Space(15f);
    GUILayout.Label("Measure Type");
    _MeasureIndex =  GUILayout.SelectionGrid(_MeasureIndex, MeasureType, 3);
    GUILayout.Space(15f);
    GUILayout.Label("拍子数");
    measure_num = EditorGUILayout.DelayedFloatField(measure_num);
    GUILayout.Label("拍数");
    beat_num = EditorGUILayout.DelayedFloatField(beat_num);
}else{
    GUILayout.Space(15f);
    GUILayout.Label("Now Time");
    startime = EditorGUILayout.DelayedFloatField(startime);
}
GUILayout.Space(15f);
GUILayout.Label("Select line");
_LineIndex = GUILayout.SelectionGrid(_LineIndex, Line, 3);
GUILayout.Label("Select Block Type");
_TypeIndex = GUILayout.SelectionGrid(_TypeIndex, BlockType, 3);
if(_TypeIndex == 1){
    GUILayout.Space(15f);
    GUILayout.Label("Time or Measure");
    _EndWriteIndex = GUILayout.SelectionGrid(_EndWriteIndex, WriteTipe, 3);
    if(_EndWriteIndex == 1){
        GUILayout.Space(15f);
        GUILayout.Label("Measure Type");
        _EndMeasureIndex =  GUILayout.SelectionGrid(_EndMeasureIndex, MeasureType, 3);
        GUILayout.Space(15f);
        GUILayout.Label("拍子数");
        end_measure_num = EditorGUILayout.DelayedFloatField(end_measure_num);
        GUILayout.Label("拍数");
        end_beat_num = EditorGUILayout.DelayedFloatField(end_beat_num);
    }else{
        GUILayout.Label("Input Last time");
        endtime = EditorGUILayout.DelayedFloatField(endtime);
    }
}
GUILayout.Space(35f);

GUILayout.Label("notes speed");
notes_speed = EditorGUILayout.DelayedFloatField(notes_speed);

GUILayout.Space(35f);

if(GUILayout.Button("Add")){
    if(_StartWirteIndex == 1){
        startime = ((float)240/(float)EditMusicScore.GetBpm()/(float)((float)4*(float)(_MeasureIndex+1)))*((float)((4*(_MeasureIndex+1))*measure_num + beat_num));
    }
    if(_EndWriteIndex == 1){
        endtime = ((float)240/(float)EditMusicScore.GetBpm()/(float)((float)4*(float)(_EndMeasureIndex+1)))*((float)((4*(_EndMeasureIndex+1))*end_measure_num + end_beat_num));
    }
    if(_TypeIndex == 1){
        CSV.AddCSV(filepath, Line[_LineIndex], BlockType[_TypeIndex], startime, endtime, notes_speed);
    }else{
        CSV.AddCSV(filepath, Line[_LineIndex], BlockType[_TypeIndex], startime, 0.0f, notes_speed);
    }
    CSV.GetCSV(filename, CSVData);
    EditMusicScore.UpdateCSV();
}

これとCSVファイルに書き込む部分と読み込む部分は以下の通りになります

Editor.cs
public class CSV : MonoBehaviour
{
    private static int rownum = 0;

    public static void AddCSV(string filename, string linename, string tyepname, float startime, float endtime, float notes_speed){
        var list = "";
        Debug.Log(filename);
        list = linename + "," + tyepname + "," + startime.ToString() + "," + endtime.ToString() + "," + notes_speed.ToString() + "\n";
        if(filename == null){
            return;
        }
        using (var file = new StreamWriter(filename, true, System.Text.Encoding.GetEncoding("UTF-8"))){
            file.Write(list);
        }
    }

    public static void GetCSV(string filename, List<string[]> csvDatas){
        var csvfile = Resources.Load(filename) as TextAsset;
        StringReader file = new StringReader(csvfile.text);
        rownum = 0;
        while(file.Peek() != -1){
            string line = file.ReadLine();
            csvDatas.Add(line.Split(','));
            rownum = rownum + 1;
        }
    }

    public static bool HasData(string filename){
        int count = 0;
        var csvfile = Resources.Load(filename) as TextAsset;
        StringReader file = new StringReader(csvfile.text);
        while(file.Peek() != -1){
            string line = file.ReadLine();
            count++;
        }
        if(count == 0){
            return false;
        }else{
            Debug.Log(count);
            return true;
        }
    }

    public static int GetRowNum(){
        return rownum;
    }
}

こんな感じでゴニョゴニョすれば譜面を作るためのUnityEditorが完成します。

終わりに

実際にこのEditorを使用して、一譜面完成させましたが、しんどかったです。まじで・・・・
あと、改修しない部分も多く、削除部分だったり、既存の部分の編集だったり・・・これらの問題自体はUnityEditorはEditorWindowを継承しているのでMonoBehaviorよりとっつきにくく、難しいのです・・・・。今後も頑張っていこうと思います。

明日は鈴木乖離さんの「醜く生きるお絵描き道~大学生から目指すつよつよ絵描き~」です。よろしくお願いします。

参考にさせていただいた資料

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?