ユニティーを使用した音ゲーの作り方のメモです。ゲーム制作の参考にしていただければ嬉しいです。トグルボタンをクリックすると記事が表示されます。小さくて見ずらい画像はクリックで拡大できます。
土台の作成
cubeを配置しました。名前はBaseにしました。サイズを調整しました。

Baseの子オブジェクトに空のオブジェクトを作成しました。名前はlineにしました。

lineにlinerendererを追加して線のサイズを調整しました。

カメラの位置を調整しました。

materialを作成しました。

Beseとlineにマテリアルをアタッチしての色を変更しました。

ノーツの作成
新しくcubeを作成しました。名前はnotesにしました。
サイズを調整しました。

新しくC#スクリプトを作成しました。名前はnotesにしました。

作成したスクリプトをnotesオブジェクトにアタッチしました。
lineに向かってnotesが流れるようにします。
using UnityEngine;
public class notes : MonoBehaviour
{
//ノーツの速度
public int notesSpeed =1;
void Update()
{
transform.position -= transform.forward * Time.deltaTime * notesSpeed;
}
}
notesが流れるようになりました。
notesをprefabにしました。

ボタンを押したら光るようにする
新しくCubeを作成しました。名前はlightにしました。
サイズを調整しました。

lightのマテリアルを作成してlightオブジェクトにアタッチします。
lightのマテリアルのRendereringmodeをfadeに変更しました。

C#スクリプトを作成ました。なまえはlightにしました。

作成したスクリプトをlightオブジェクトにアタッチしました。
using UnityEngine;
public class Light : MonoBehaviour
{
[SerializeField] private float Speed = 3;
[SerializeField] private int num = 0;
private Renderer rend;
private float alfa = 0;
// Start is called before the first frame update
void Start()
{
rend = GetComponent<Renderer>();
}
// Update is called once per frame
void Update()
{
if (!(rend.material.color.a <= 0))
{
rend.material.color = new Color(rend.material.color.r, rend.material.color.r, rend.material.color.r, alfa);
}
if (num == 1)
{
if (Input.GetKeyDown(KeyCode.D))
{
colorChange();
}
}
if (num == 2)
{
if (Input.GetKeyDown(KeyCode.F))
{
colorChange();
}
}
if (num == 3)
{
if (Input.GetKeyDown(KeyCode.J))
{
colorChange();
}
}
if (num == 4)
{
if (Input.GetKeyDown(KeyCode.K))
{
colorChange();
}
}
alfa -= Speed * Time.deltaTime;
}
void colorChange()
{
alfa = 0.3f;
rend.material.color = new Color(rend.material.color.r, rend.material.color.g, rend.material.color.b, alfa);
}
}
lightオブジェクトをコピーして4つにして位置を調整しました。





左のオブジェクトから順番にnumを1,2,3,4と設定しました。

DFJKキーを押すとレーンが光るようになりました。
譜面の作成
こちらのサイトからNoteEditorをダウンロードしました。

新しくプロジェクトを作成して解凍したNoteEditor-masterフォルダを
Unityにドラッグ&ドロップしてインストールしました。
Sceneフォルダに入っているNoteEditorを開きました。

実行ボタンを押すと右上のところに音楽ファイルを入れるフォルダのパスが出てくるので、

エクスプローラーからそのフォルダを開いて使用する音楽ファイルを入れます。

追加するとリストに表示されるようになるので選択して読み込みます。

線の部分をクリックするとノーツが置けるので適当に作成してctrl+Sで保存します。

元のプロジェクトに戻り新しくResourcesフォルダを作成して、

その中に保存した譜面ファイルをドラッグ&ドロップしました。

譜面を読み込むスクリプト
空のオブジェクトを作成してNotesManagerをアタッチしました。
using System;
using System.Collections.Generic;
using UnityEngine;
[Serializable]
public class Data
{
public string name;
public int maxBlock;
public int BPM;
public int offset;
public Note[] notes;
}
[Serializable]
public class Note
{
public int type;
public int num;
public int block;
public int LPB;
}
public class NotesManager : MonoBehaviour
{
//総ノーツ数
public int noteNum;
//曲名
private string songName;
//ノーツのレーン
public List<int> LaneNum = new List<int>();
//ノーツの種類
public List<int> NoteType = new List<int>();
//ノーツが判定線と重なる時間
public List<float> NotesTime = new List<float>();
//gameobject
public List<GameObject> NotesObj = new List<GameObject>();
//ノーツの速度
[SerializeField] private float NotesSpeed;
//ノーツのprefabを入れる
[SerializeField] GameObject noteObj;
void OnEnable()
{
//総ノーツを0にする
noteNum = 0;
//読み込む譜面のファイル名を入力
songName = "testmusic";
Load(songName);
}
private void Load(string SongName)
{
//jsonファイルを読み込む
string inputString = Resources.Load<TextAsset>(SongName).ToString();
Data inputJson = JsonUtility.FromJson<Data>(inputString);
//総ノーツ数を設定
noteNum = inputJson.notes.Length;
for (int i = 0; i < inputJson.notes.Length; i++)
{
//時間を計算
float kankaku = 60 / (inputJson.BPM * (float)inputJson.notes[i].LPB);
float beatSec = kankaku * (float)inputJson.notes[i].LPB;
float time = (beatSec * inputJson.notes[i].num / (float)inputJson.notes[i].LPB) + inputJson.offset * 0.01f;
//リストに追加
NotesTime.Add(time);
LaneNum.Add(inputJson.notes[i].block);
NoteType.Add(inputJson.notes[i].type);
float z = NotesTime[i] * NotesSpeed;
//ノーツを生成
NotesObj.Add(Instantiate(noteObj, new Vector3(inputJson.notes[i].block - 1.5f, 0.55f, z), Quaternion.identity));
}
}
}
inspector画面からNotesspeedとprefabを設定しました。

譜面が読み込まれるようになりました。
ノーツの判定
空のオブジェクトを作成しました。名前はParfectにしました。
addcomponentからTextmeshproを追加しました。
- 【Unity】TextMeshProで日本語入力する方法

文字をParfectにしてサイズを調整しました。

判定用のスクリプト
新しくC#スクリプトを作成しました。
名前はJudgeにしました。空のオブジェクトを作成してアタッチしました。
using UnityEngine;
public class Judge : MonoBehaviour
{
//プレイヤーに判定を伝えるゲームオブジェクト
[SerializeField] private GameObject[] MessageObj;
//NotesManagerを入れる変数
[SerializeField] NotesManager notesManager;
void Update()
{
if (Input.GetKeyDown(KeyCode.D))//〇キーが押されたとき
{
if (notesManager.LaneNum[0] == 0)//押されたボタンはレーンの番号とあっているか?
{
Judgement(GetABS(Time.time - notesManager.NotesTime[0]));
/*
本来ノーツをたたく場所と実際にたたいた場所がどれくらいずれているかを求め、
その絶対値をJudgement関数に送る
*/
}
}
if (Input.GetKeyDown(KeyCode.F))
{
if (notesManager.LaneNum[0] == 1)
{
Judgement(GetABS(Time.time - notesManager.NotesTime[0]));
}
}
if (Input.GetKeyDown(KeyCode.J))
{
if (notesManager.LaneNum[0] == 2)
{
Judgement(GetABS(Time.time - notesManager.NotesTime[0]));
}
}
if (Input.GetKeyDown(KeyCode.K))
{
if (notesManager.LaneNum[0] == 3)
{
Judgement(GetABS(Time.time - notesManager.NotesTime[0]));
}
}
if (Time.time > notesManager.NotesTime[0] + 0.2f)//本来ノーツをたたくべき時間から0.2秒たっても入力がなかった場合
{
message(3);
deleteData();
Debug.Log("Miss");
//ミス
}
}
void Judgement(float timeLag)
{
if (timeLag <= 0.10)//本来ノーツをたたくべき時間と実際にノーツをたたいた時間の誤差が0.1秒以下だったら
{
Debug.Log("Perfect");
message(0);
deleteData();
}
else
{
if (timeLag <= 0.15)//本来ノーツをたたくべき時間と実際にノーツをたたいた時間の誤差が0.15秒以下だったら
{
Debug.Log("Great");
message(1);
deleteData();
}
else
{
if (timeLag <= 0.20)//本来ノーツをたたくべき時間と実際にノーツをたたいた時間の誤差が0.2秒以下だったら
{
Debug.Log("Bad");
message(2);
deleteData();
}
}
}
}
float GetABS(float num)//引数の絶対値を返す関数
{
if (num >= 0)
{
return num;
}
else
{
return -num;
}
}
//すでにたたいたノーツを削除する関数
void deleteData()
{
notesManager.NotesTime.RemoveAt(0);
notesManager.LaneNum.RemoveAt(0);
notesManager.NoteType.RemoveAt(0);
}
//判定を表示する
void message(int judge)
{
Instantiate(MessageObj[judge], new Vector3(notesManager.LaneNum[0] - 1.5f, 0.76f, 0.15f), Quaternion.Euler(45, 0, 0));
}
}
inspector画面からprefabとnotesManagerを設定しました。

判定が表示されるようになりました。
