Note Audio Submodule

This commit is contained in:
SoulliesOfficial
2025-05-03 01:08:29 -04:00
parent 39c1b4e16a
commit cca8ec49a6
32 changed files with 1162 additions and 119 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a08d8a0b7d3d8e0478bb20f91a8df21d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,69 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 2d8a87c5b71c49f4997d1b98e9dea18b, type: 3}
m_Name: NoteAudioCollection
m_EditorClassIdentifier:
serializationData:
SerializedFormat: 2
SerializedBytes:
ReferencedUnityObjects:
- {fileID: 8300000, guid: 659cb798f955c8f4bb530bf89f54e2cc, type: 3}
- {fileID: 8300000, guid: 617b904af4f9aa4479b11e83947d02fd, type: 3}
SerializedBytesString:
Prefab: {fileID: 0}
PrefabModificationsReferencedUnityObjects: []
PrefabModifications: []
SerializationNodes:
- Name: audioClips
Entry: 7
Data: 0|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[UnityEngine.AudioClip,
UnityEngine.AudioModule]], mscorlib
- Name: comparer
Entry: 7
Data: 1|System.Collections.Generic.GenericEqualityComparer`1[[System.String,
mscorlib]], mscorlib
- Name:
Entry: 8
Data:
- Name:
Entry: 12
Data: 2
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: DefaultTap
- Name: $v
Entry: 10
Data: 0
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: DefaultStay
- Name: $v
Entry: 10
Data: 1
- Name:
Entry: 8
Data:
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 32b615cfb2614a946a8ff57e380b4759
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,33 @@
using System.Collections;
using System.Collections.Generic;
using Sirenix.OdinInspector;
using UnityEngine;
namespace Ichni.RhythmGame
{
[CreateAssetMenu(fileName = "NoteAudioCollection", menuName = "Ichni/Note/NoteAudioCollection")]
public class NoteAudioCollection : SerializedScriptableObject
{
public Dictionary<string, AudioClip> audioClips = new Dictionary<string, AudioClip>();
}
public static class AudioExtension
{
/// <summary>
/// 在全局(不受位置影响)播放一段 AudioClip。
/// </summary>
public static void PlayClipAtPoint2D(AudioClip clip, float volume = 1f)
{
// 新建一个临时的 GameObject
GameObject go = new GameObject("TempAudio2D");
var src = go.AddComponent<AudioSource>();
src.clip = clip;
src.volume = volume;
src.spatialBlend = 0f; // 0 = 完全 2D
src.playOnAwake = false;
src.Play();
// 自动销毁,避免内存泄漏
Object.Destroy(go, clip.length + 0.1f);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2d8a87c5b71c49f4997d1b98e9dea18b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,174 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
namespace Ichni.RhythmGame
{
public partial class NoteAudioSubmodule : SubmoduleBase
{
public List<string> generalJudgeAudioList;
public List<string> perfectAudioList;
public List<string> goodAudioList;
public List<string> badAudioList;
public List<string> missAudioList;
public List<string> holdStartAudioList;
private NoteBase note => attachedGameElement as NoteBase;
public NoteAudioSubmodule(NoteBase attachedGameElement, string defaultAudio) : base(attachedGameElement)
{
generalJudgeAudioList = new List<string>();
perfectAudioList = new List<string>();
goodAudioList = new List<string>();
badAudioList = new List<string>();
missAudioList = new List<string>();
holdStartAudioList = new List<string>();
generalJudgeAudioList.Add(defaultAudio);
this.note.noteAudioSubmodule = this;
}
public NoteAudioSubmodule(NoteBase attachedGameElement, List<string> generalJudgeAudioList,
List<string> perfectAudioList, List<string> goodAudioList, List<string> badAudioList,
List<string> missAudioList, List<string> holdStartAudioList) : base(attachedGameElement)
{
this.generalJudgeAudioList = generalJudgeAudioList;
this.perfectAudioList = perfectAudioList;
this.goodAudioList = goodAudioList;
this.badAudioList = badAudioList;
this.missAudioList = missAudioList;
this.holdStartAudioList = holdStartAudioList ?? new List<string>();
this.note.noteAudioSubmodule = this;
}
}
public partial class NoteAudioSubmodule
{
public void PlayHoldStartAudio()
{
PlayAudio(holdStartAudioList);
}
public void PlayNoteJudgeAudios(NoteBase.NoteJudgeType judgeType)
{
PlayAudio(generalJudgeAudioList);
switch (judgeType)
{
case NoteBase.NoteJudgeType.Perfect:
PlayAudio(perfectAudioList);
break;
case NoteBase.NoteJudgeType.Good:
PlayAudio(goodAudioList);
break;
case NoteBase.NoteJudgeType.Bad:
PlayAudio(badAudioList);
break;
case NoteBase.NoteJudgeType.Miss:
PlayAudio(missAudioList);
break;
}
}
private void PlayAudio(List<string> audioList)
{
foreach (var audio in audioList)
{
if (EditorManager.instance.noteAudioCollection.audioClips.TryGetValue(audio, out AudioClip clip))
{
AudioExtension.PlayClipAtPoint2D(clip);
}
}
}
}
public partial class NoteAudioSubmodule
{
public override void SaveBM()
{
matchedBM = new NoteAudioSubmodule_BM(attachedGameElement, this);
}
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Judge Submodule");
var submoduleSettings = container.GenerateSubcontainer(3);
var generalJudgeAudioListButton = inspector.GenerateButton(this, submoduleSettings, "General Judge", () =>
{
inspector.GenerateCompositeParameterWindow(this, "General Judge Sound List", nameof(generalJudgeAudioList)).SetAsStringList();
});
var perfectAudioListButton = inspector.GenerateButton(this, submoduleSettings, "Perfect", () =>
{
inspector.GenerateCompositeParameterWindow(this, "Perfect Sound List", nameof(perfectAudioList)).SetAsStringList();
});
var goodAudioListButton = inspector.GenerateButton(this, submoduleSettings, "Good", () =>
{
inspector.GenerateCompositeParameterWindow(this, "Good Sound List", nameof(goodAudioList)).SetAsStringList();
});
var badAudioListButton = inspector.GenerateButton(this, submoduleSettings, "Bad", () =>
{
inspector.GenerateCompositeParameterWindow(this, "Bad Sound List", nameof(badAudioList)).SetAsStringList();
});
var missAudioListButton = inspector.GenerateButton(this, submoduleSettings, "Miss", () =>
{
inspector.GenerateCompositeParameterWindow(this, "Miss Sound List", nameof(missAudioList)).SetAsStringList();
});
if (note is Hold)
{
var holdStartAudioListButton = inspector.GenerateButton(this, submoduleSettings, "Hold Start", () =>
{
inspector.GenerateCompositeParameterWindow(this, "Hold Start Sound List", nameof(holdStartAudioList)).SetAsStringList();
});
}
}
}
namespace Beatmap
{
public class NoteAudioSubmodule_BM : Submodule_BM
{
public List<string> generalJudgeAudioList;
public List<string> perfectAudioList;
public List<string> goodAudioList;
public List<string> badAudioList;
public List<string> missAudioList;
public List<string> holdStartAudioList;
public NoteAudioSubmodule_BM()
{
}
public NoteAudioSubmodule_BM(GameElement attachedElement, NoteAudioSubmodule noteAudioSubmodule) : base(attachedElement)
{
generalJudgeAudioList = noteAudioSubmodule.generalJudgeAudioList;
perfectAudioList = noteAudioSubmodule.perfectAudioList;
goodAudioList = noteAudioSubmodule.goodAudioList;
badAudioList = noteAudioSubmodule.badAudioList;
missAudioList = noteAudioSubmodule.missAudioList;
holdStartAudioList = noteAudioSubmodule.holdStartAudioList;
}
public override void ExecuteBM()
{
attachedElement = GameElement_BM.GetElement(attachedElementGuid);
(attachedElement as NoteBase).noteAudioSubmodule = new NoteAudioSubmodule(attachedElement as NoteBase,
generalJudgeAudioList, perfectAudioList, goodAudioList, badAudioList, missAudioList, holdStartAudioList);
}
public override void DuplicateBM(GameElement attached)
{
(attached as NoteBase).noteAudioSubmodule = new NoteAudioSubmodule(attached as NoteBase,
generalJudgeAudioList, perfectAudioList, goodAudioList, badAudioList, missAudioList, holdStartAudioList);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4480fb04e0840404ca13fa9126c908ef
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -56,6 +56,12 @@ namespace Ichni.RhythmGame
public partial class Flick
{
public override void SetDefaultSubmodules()
{
base.SetDefaultSubmodules();
noteAudioSubmodule = new NoteAudioSubmodule(this, "DefaultStay");
}
public override void SaveBM()
{
matchedBM = new Flick_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM,

View File

@@ -84,6 +84,12 @@ namespace Ichni.RhythmGame
public partial class Hold
{
public override void SetDefaultSubmodules()
{
base.SetDefaultSubmodules();
noteAudioSubmodule = new NoteAudioSubmodule(this, "DefaultTap");
}
public override void SaveBM()
{
matchedBM = new Hold_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM, exactJudgeTime, holdEndTime);
@@ -150,13 +156,13 @@ namespace Ichni.RhythmGame
{
isHolding = false;
isFinalJudged = true;
noteAudioSubmodule.PlayNoteJudgeAudios(EditorManager.instance.currentJudgeType);
}
if (!isFirstJudged && songTime >= exactJudgeTime)
{
if (!isFirstJudged)
{
//AudioSource.PlayClipAtPoint(EditorManager.instance.basePrefabs.tapNoteSound, Camera.main.transform.position, 1f);
isFirstJudged = true;
}

View File

@@ -26,6 +26,7 @@ namespace Ichni.RhythmGame
[Title("Submodules")]
public TimeDurationSubmodule timeDurationSubmodule { get; set; }
public NoteJudgeSubmodule noteJudgeSubmodule { get; set; }
public NoteAudioSubmodule noteAudioSubmodule { get; set; }
[Title("In-Game Info")]
public Vector2 noteScreenPosition;
@@ -85,7 +86,7 @@ namespace Ichni.RhythmGame
{
if (!isFirstJudged)
{
//AudioSource.PlayClipAtPoint(EditorManager.instance.basePrefabs.tapNoteSound, Camera.main.transform.position, 1f);
noteAudioSubmodule.PlayNoteJudgeAudios(EditorManager.instance.currentJudgeType);
isFirstJudged = true;
}
}

View File

@@ -51,6 +51,12 @@ namespace Ichni.RhythmGame
public partial class Stay
{
public override void SetDefaultSubmodules()
{
base.SetDefaultSubmodules();
noteAudioSubmodule = new NoteAudioSubmodule(this, "DefaultStay");
}
public override void SaveBM()
{
matchedBM = new Stay_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM, exactJudgeTime);

View File

@@ -40,7 +40,7 @@ namespace Ichni.RhythmGame
tap.track = null;
tap.isOnTrack = false;
}
if (EditorManager.instance.useNotePrefab)
{
EditorManager.instance.projectManager.notePrefabManager.LoadNotePrefab(tap,GetNoteTypeName(tap) + "_Prefab");
@@ -52,6 +52,12 @@ namespace Ichni.RhythmGame
public partial class Tap
{
public override void SetDefaultSubmodules()
{
base.SetDefaultSubmodules();
noteAudioSubmodule = new NoteAudioSubmodule(this, "DefaultTap");
}
public override void SaveBM()
{
matchedBM = new Tap_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM, exactJudgeTime);

View File

@@ -25,12 +25,6 @@ public class BasePrefabsCollection : SerializedScriptableObject
public GameObject stayNote;
public GameObject holdNote;
public GameObject flickNote;
public AudioClip tapNoteSound;
public AudioClip stayNoteSound;
public AudioClip holdNoteStartSound;
public AudioClip holdNoteLoopSound;
public AudioClip holdNoteEndSound;
public AudioClip flickNoteSound;
[Title("Note 判定UI")]
public GameObject fullscreenNearTimeHint;
public GameObject areaHint;

View File

@@ -38,6 +38,7 @@ namespace Ichni
public NoteBase.NoteJudgeType currentJudgeType;
public bool useNotePrefab;
public BasePrefabsCollection basePrefabs;
public NoteAudioCollection noteAudioCollection;
[Title("Runtime Global Elements")]
public VariablesContainer variablesContainer;