This commit is contained in:
SoulliesOfficial
2026-06-05 04:45:57 -04:00
parent 3a63641a2c
commit 7c60c40d6b
377 changed files with 10970 additions and 843 deletions

View File

@@ -213,7 +213,7 @@ Material:
- _Dst: 10 - _Dst: 10
- _DstBlend: 0 - _DstBlend: 0
- _DstBlendAlpha: 0 - _DstBlendAlpha: 0
- _EdgeValue: 0.9431098 - _EdgeValue: 0.6926449
- _EnvironmentReflections: 1 - _EnvironmentReflections: 1
- _FNLfanxiangkaiguan: 0 - _FNLfanxiangkaiguan: 0
- _Face: 1 - _Face: 1
@@ -258,7 +258,7 @@ Material:
- _Mask_scale: 1 - _Mask_scale: 1
- _Metallic: 0 - _Metallic: 0
- _OcclusionStrength: 1 - _OcclusionStrength: 1
- _Opacity: 0.05689019 - _Opacity: 0.3073551
- _Parallax: 0.005 - _Parallax: 0.005
- _Pass: 0 - _Pass: 0
- _QueueOffset: 0 - _QueueOffset: 0

Binary file not shown.

View File

@@ -1 +1,2 @@
⌡# ▒Й┐}~╜╚}АБ·│W' ≥x┘≤╝Ё√Т╜|u<М╖┘<П┬чгт╞удбO╜в┼0 ăęĚý6V ·´ĐVOQĐâ»ăŕűŠ8áw»-Kz'wťý§{"˛ßP ·qS˛
Ę,‰<>ŐU]v}CmIÎQ2zkÔÔaŻ%p)űÁÎ+°—Ë|ŔúćÁÄ› ŕ7ŔeŠG7çv 7 ô˛gŚ ZIJ°o©{ś9J5·Â˛…Jś=$Ŕî¸[·#f“<66>´6Ńgl ®›^É<>L—`öo)i$ż„ѱZ˛řRőfQx?ĆXĄň/4?đtýyĐR­E@í ˇµ<06>‰"?« ţi'IEľ5KUĄ-MZ(VÍä(öG™YăYkF49@‰ŚCąK{&0`-ďÜŢAe9¬:|Ou5<!żÎ<11>”;ßY&žŞ<08>Tąxąů^hâA*śz]B<>b쉸f§B´PlI-´íf

View File

@@ -1 +1,3 @@
.<2E>¯ôc8KŒ³o+0oÑÆb.T@Qdᮤ@¾`.ÇA ÞKcÁ\2ÎÜ „–Ó*S~§ÚX½ÁðqABýwûN7·åéE2¨<ÏöåðЇÀÝ…¶Fw²Õâ{:oc™˜Pv³šÜ˜½U<C2BD><55>·®S¥íI9Î+qt<71>RCÙì/ú°z(NDÃó<15>MØ)qô5'<27>P&ðg brÐ<E2809A>MÜiO,¹R<è·†hˆE^ ‰R¶\ĐÚřF>~ŢŠtŰBśk»§Č†±ö<C2B1>fšÜŤ–”7>ôN#(´Šmím°_±hDtř“Yš|dąÉĄź<C484>ňŤ‡1ŚŘś·”ćMu¨ěwKȡ
Oä«Íâ<5ŁZeěQöë>áZZő˘°ĆÝuŻ
ZÇu[żÉŘB×<09>śS˛ÄçÖ¨Ç?A3¤†é]z™Oţ¨„™<04>xnq¶u¤«BîĽÎÖ,/

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 7ad07a532b11b4549ba56db20244304d guid: db4ec1bf087be0649a821308cfc8a934
DefaultImporter: DefaultImporter:
externalObjects: {} externalObjects: {}
userData: userData:

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 230d1ef4a78be7c4ab981f06a602786b guid: 31bb6b6521c6bc842888c4f9eba7ae7c
DefaultImporter: DefaultImporter:
externalObjects: {} externalObjects: {}
userData: userData:

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 4d2f8fd23969dca4ab51f19a23e9c42e guid: eebcc52a3a0318f449254cb1ba9ecfdd
DefaultImporter: DefaultImporter:
externalObjects: {} externalObjects: {}
userData: userData:

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: daf639bda868a5b41af9718de84f865a guid: 0329be1cff81a4c47a38526a1db2aeca
DefaultImporter: DefaultImporter:
externalObjects: {} externalObjects: {}
userData: userData:

View File

@@ -1,6 +1,6 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 307462e034a69a844875d85225e3afa1 guid: 5a9c2e3cb8f3dd84798db2d1076d8386
TextScriptImporter: DefaultImporter:
externalObjects: {} externalObjects: {}
userData: userData:
assetBundleName: assetBundleName:

View File

@@ -1,6 +1,6 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 9b062776a4c1d624889f0a4e6c4c19a4 guid: 082cfdd75a8e71643bcc334650821eb5
TextScriptImporter: DefaultImporter:
externalObjects: {} externalObjects: {}
userData: userData:
assetBundleName: assetBundleName:

View File

@@ -1,6 +1,6 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 595ff1dd51b0a7a4dbb0ed99dc69091a guid: 9d46af3a0bc9bb546b4c75d3b1d42c13
TextScriptImporter: DefaultImporter:
externalObjects: {} externalObjects: {}
userData: userData:
assetBundleName: assetBundleName:

View File

@@ -1,6 +1,6 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 49de583101f221b4098ec615e80171f0 guid: 38fd7b24f0514884cb9b4d7de52c1045
TextScriptImporter: DefaultImporter:
externalObjects: {} externalObjects: {}
userData: userData:
assetBundleName: assetBundleName:

View File

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

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 580fb6a0454aada4fa7828d1b630c964
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,2 @@
Ùý„ÿ•ŠC<17>×l8ªËZ7$É2ªÂBwÿáâ[¦ÑjÝA¬¸ÿÊ(:îÀya«y  iXxŠþÓþS^Áp%w~æB]?beÆ%Úí™aX„ä<9àÙ±Æ5bèã%†"a^ŸCß(»í7S<>g” ˜MQ¤1£R¶^ÄÚi3ÆÛ“â
³?]ˆ^€Ÿ‡'šÅ˜Í0MãçMP^f> é[gÕQ$¯]“

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 1319b343f4282214bbc41d179652f89f
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 25ac69095a55a8c4c80ae12efcc9436b
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,3 @@
<EFBFBD>‡^†8óôv
[iéÿÓcêïUæ(½ƒ¦#Õ’ò| ç#ªšØ‘KÅÉÎØ<C38E>æT=
ª°žœ<C5BE>·+'ÄŸmJaê“AcÝ€„ÙãolêB0®_eà<65>HÞi;xé—KY|{ï8åÚHÂ@&©A"ßs£<73>ã¤tWj…`Da®

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 3ad33d81f0235434ab4639abe750ad94
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: f884c6de02a49cc41a4e6f70cfadab2f
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,2 @@
ÿ¾·[€%|ÓÊR1¢Ÿ@‡‹Øß`<60>e*^sÄ ÚZeÁiíÂ> eǾ®°ÿŸÝfžU<>b þBt)Ûø¬!¿8©\Ľ׹ä:~9ôÈÇt
˜ÀHt-Öûé¿,Á)õƒÔI¼BNKÕHá"ý"Ñ©Js&p¹Ktñ‰ð<E280B0>Ä̽OÁ<4F>dÏ®EY99ééʃÚɪÛ;|ÙërRû(àÛ« åÔõ9êŠWêÏŸ¥<C5B8>ܳ¯ÝÉ(ù·ÂÖ<03>

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 5b63f7fae492f984eac21f7adbadf4fe
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,3 @@
Ş†ÂťnŘ INŔŹľ< ˛ě<CB9B>®mŻcśÄE<C384>Z ¦ŮŔž·iťËŘÜ<2 ç©x‰ÔL{ËK*§<>@í˝‘°ý>˙“y©óXń¶Ähî:ĂD°ŁSčo._.‰ Rş|©O¬äoŢżbf¦ˇŇ(˘­Ş
5(+şiŞÁÝÎ'Ěa5])„z5 δČó¨ÖĚô8ÚfË
QŇß1eĄ?tźzĆ*[>’ŚÄŁŘ@r”;ŇXËŮOś<4F>ŇÜ

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b72f31d1586895b4892908b2817009a9
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: fef53b05b7387cc43a0a1674f97b0886
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

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

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: dc68bc370cdceef439cb260008bef99d
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1 @@
<EFBFBD>Óé‰]X—Ş”iË7Ý/ÂK÷Óé„4<

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d1211da0c117f744699d63ea3d98d9cc
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,3 @@
ÆS<EFBFBD>!Ùža†^®WaOÙÛ™&]Ä€¡ßFZ@á¦.c Ë<>G­EH¨Ù¿iN%AÕ)#ÔÖ°â”<C3A2>`<60>†yµÜ)QJ¸_8Ã
!$Õ6éj„ê'ÃRwƒÎ]ÍyíJÓѦ<C391>°Oºb“ʼnÙ
ðîIQqñ¡O9¼~“ÄöhþÒØ|ƒk8s‡1}>4$[Ïh<C38F>­:¦K<C2A6>ç¯RdA\<5C>ëAG”øÔOÛ³ÍÂ+`14¿`DªÕgÒVן‰éEŒ_1ñXŠÙrÍ åûQ}¯dz¦Ë…ñݲ<C39D>ÛÁžTÌÅ3ÍoM€¥œAMª„0<E2809E>6ÊAÀ.­¼ êzFx¢<78>ãæÕž<11>V`ÊfL¬“7‡ý_0|¥0šÚÓ <C393>g,=Xç¿÷ƒ8ÀP÷

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 2df60ed2aeb42b54c9a7b2fa0c2ff2de
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,3 @@
ěţ<EFBFBD><EFBFBD>„xŮ˙@ÔźüÚGSŔŢî;{@ÎvH2cM˙~©p§ł´ß¤ ¶l~`JÔ Ř»P1ÇtlQ9#©©ěŻŮ°“¶Ćú ɦـÜ4mfěńöăÓś4Vč¬ŇA ĐRáłöěńP¬ÇŠ1ĂUE%¸Ś˘Ý»Űúl7ę×Ó~ÇYÓRaŮČ2=Äík Đ×(Úe„şF
”w 5GäY4Ó«FGDĐLă1ÄyE†µGŘőŕµ(f ľň“:5#t˝I¨N TUDeřźw\“3ü aBìŢ
bͩ

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: fdc9a6807baa7354086ffe1d3c91cf83
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
namespace Ichni.RhythmGame.Beatmap
{
public class TrackGlobalColorChange_BM : AnimationBase_BM
{
public FlexibleFloat_BM colorR, colorG, colorB, colorA;
public TrackGlobalColorChange_BM()
{
}
public TrackGlobalColorChange_BM(string elementName, Guid elementGuid, List<string> tags,
GameElement_BM attachedElement, FlexibleFloat_BM colorR, FlexibleFloat_BM colorG, FlexibleFloat_BM colorB, FlexibleFloat_BM colorA)
: base(elementName, elementGuid, tags, attachedElement)
{
this.colorR = colorR;
this.colorG = colorG;
this.colorB = colorB;
this.colorA = colorA;
}
public override void ExecuteBM()
{
matchedElement = TrackGlobalColorChange.GenerateElement(elementName, elementGuid, tags, false, GetElement(attachedElementGuid),
colorR.ConvertToGameType(), colorG.ConvertToGameType(), colorB.ConvertToGameType(), colorA.ConvertToGameType());
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 68d836b6038e9744a83ffc7d486c53f0

View File

@@ -3,7 +3,7 @@ using UnityEngine;
namespace Ichni.RhythmGame.Beatmap namespace Ichni.RhythmGame.Beatmap
{ {
public class ColorSubmodule_BM : Submodule_BM public class ColorSubmodule_BM : SubmoduleBase_BM
{ {
public Color originalBaseColor; public Color originalBaseColor;
public bool emissionEnabled; public bool emissionEnabled;

View File

@@ -2,7 +2,7 @@ using System.Collections.Generic;
namespace Ichni.RhythmGame.Beatmap namespace Ichni.RhythmGame.Beatmap
{ {
public class EffectSubmodule_BM : Submodule_BM public class EffectSubmodule_BM : SubmoduleBase_BM
{ {
public Dictionary<string, List<EffectBase_BM>> effectCollection; public Dictionary<string, List<EffectBase_BM>> effectCollection;

View File

@@ -4,16 +4,16 @@ using UnityEngine;
namespace Ichni.RhythmGame.Beatmap namespace Ichni.RhythmGame.Beatmap
{ {
public abstract class Submodule_BM : BaseElement_BM public abstract class SubmoduleBase_BM : BaseElement_BM
{ {
[System.NonSerialized] protected GameElement attachedElement; //存档类对应的游戏物体 [System.NonSerialized] protected GameElement attachedElement; //存档类对应的游戏物体
public Submodule_BM() public SubmoduleBase_BM()
{ {
} }
public Submodule_BM(GameElement attachedElement) public SubmoduleBase_BM(GameElement attachedElement)
{ {
this.attachedElement = attachedElement; this.attachedElement = attachedElement;
attachedElementGuid = attachedElement.elementGuid; attachedElementGuid = attachedElement.elementGuid;

View File

@@ -2,7 +2,7 @@ using System;
namespace Ichni.RhythmGame.Beatmap namespace Ichni.RhythmGame.Beatmap
{ {
public class TimeDurationSubmodule_BM : Submodule_BM public class TimeDurationSubmodule_BM : SubmoduleBase_BM
{ {
public bool isOverridingDuration; public bool isOverridingDuration;
public float startTime, endTime; public float startTime, endTime;

View File

@@ -2,7 +2,7 @@ using UnityEngine;
namespace Ichni.RhythmGame.Beatmap namespace Ichni.RhythmGame.Beatmap
{ {
public class TransformSubmodule_BM : Submodule_BM public class TransformSubmodule_BM : SubmoduleBase_BM
{ {
public Vector3 originalPosition; public Vector3 originalPosition;
public Vector3 originalEulerAngles; public Vector3 originalEulerAngles;

View File

@@ -2,7 +2,7 @@ using System.Collections.Generic;
namespace Ichni.RhythmGame.Beatmap namespace Ichni.RhythmGame.Beatmap
{ {
public class NoteAudioSubmodule_BM : Submodule_BM public class NoteAudioSubmodule_BM : SubmoduleBase_BM
{ {
public List<string> generalJudgeAudioList; public List<string> generalJudgeAudioList;
public List<string> perfectAudioList; public List<string> perfectAudioList;

View File

@@ -4,7 +4,7 @@ using UnityEngine;
namespace Ichni.RhythmGame.Beatmap namespace Ichni.RhythmGame.Beatmap
{ {
public class NoteJudgeSubmodule_BM : Submodule_BM public class NoteJudgeSubmodule_BM : SubmoduleBase_BM
{ {
public List<NoteJudgeUnit_BM> judgeUnitList; public List<NoteJudgeUnit_BM> judgeUnitList;

View File

@@ -2,7 +2,7 @@ using System;
namespace Ichni.RhythmGame.Beatmap namespace Ichni.RhythmGame.Beatmap
{ {
public class NoteJudgeTriggerSubmodule_BM : Submodule_BM public class NoteJudgeTriggerSubmodule_BM : SubmoduleBase_BM
{ {
public NoteJudgeTriggerSubmodule_BM() public NoteJudgeTriggerSubmodule_BM()
{ {

View File

@@ -1,6 +1,6 @@
namespace Ichni.RhythmGame.Beatmap namespace Ichni.RhythmGame.Beatmap
{ {
public class TrackPathSubmodule_BM : Submodule_BM public class TrackPathSubmodule_BM : SubmoduleBase_BM
{ {
public Track.TrackSpaceType trackSpaceType; public Track.TrackSpaceType trackSpaceType;
public Track.TrackSamplingType trackSamplingType; public Track.TrackSamplingType trackSamplingType;

View File

@@ -1,9 +1,10 @@
using System; using System;
using Dreamteck.Splines;
using UnityEngine; using UnityEngine;
namespace Ichni.RhythmGame.Beatmap namespace Ichni.RhythmGame.Beatmap
{ {
public class TrackRendererSubmoduleAutoOrient_BM : Submodule_BM public class TrackRendererSubmoduleAutoOrient_BM : SubmoduleBase_BM
{ {
public string materialThemeBundleName; public string materialThemeBundleName;
public string materialName; public string materialName;
@@ -12,6 +13,11 @@ namespace Ichni.RhythmGame.Beatmap
public bool zWrite; public bool zWrite;
public Vector2 uvScale = Vector2.one; public Vector2 uvScale = Vector2.one;
public Vector2 uvOffset = Vector2.zero; public Vector2 uvOffset = Vector2.zero;
public string customTextureThemeBundleName = "None";
public string customTextureName = "None";
public MeshGenerator.UVMode uvMode = MeshGenerator.UVMode.UniformClip;
public float uvRotation = 0f;
public float size = 1f;
public TrackRendererSubmoduleAutoOrient_BM() { } public TrackRendererSubmoduleAutoOrient_BM() { }
@@ -25,6 +31,11 @@ namespace Ichni.RhythmGame.Beatmap
zWrite = trSubmodule.zWrite; zWrite = trSubmodule.zWrite;
uvScale = trSubmodule.uvScale; uvScale = trSubmodule.uvScale;
uvOffset = trSubmodule.uvOffset; uvOffset = trSubmodule.uvOffset;
customTextureThemeBundleName = trSubmodule.customTextureThemeBundleName;
customTextureName = trSubmodule.customTextureName;
uvMode = trSubmodule.uvMode;
uvRotation = trSubmodule.uvRotation;
size = trSubmodule.size;
} }
public override void ExecuteBM() public override void ExecuteBM()
@@ -33,6 +44,11 @@ namespace Ichni.RhythmGame.Beatmap
if (attachedElement is Track track) if (attachedElement is Track track)
{ {
track.trackRendererSubmodule = new TrackRendererSubmoduleAutoOrient(track, enableEmission, emissionIntensity, zWrite, uvScale, uvOffset); track.trackRendererSubmodule = new TrackRendererSubmoduleAutoOrient(track, enableEmission, emissionIntensity, zWrite, uvScale, uvOffset);
track.trackRendererSubmodule.customTextureThemeBundleName = customTextureThemeBundleName;
track.trackRendererSubmodule.customTextureName = customTextureName;
track.trackRendererSubmodule.uvMode = uvMode;
track.trackRendererSubmodule.uvRotation = uvRotation;
track.trackRendererSubmodule.size = size;
if (materialName.Trim() != String.Empty) if (materialName.Trim() != String.Empty)
{ {
track.trackRendererSubmodule.ApplyMaterial(materialThemeBundleName, materialName); track.trackRendererSubmodule.ApplyMaterial(materialThemeBundleName, materialName);
@@ -41,7 +57,7 @@ namespace Ichni.RhythmGame.Beatmap
} }
} }
public class TrackRendererSubmodulePathGenerator_BM : Submodule_BM public class TrackRendererSubmodulePathGenerator_BM : SubmoduleBase_BM
{ {
public string materialThemeBundleName; public string materialThemeBundleName;
public string materialName; public string materialName;
@@ -50,6 +66,11 @@ namespace Ichni.RhythmGame.Beatmap
public bool zWrite; public bool zWrite;
public Vector2 uvScale = Vector2.one; public Vector2 uvScale = Vector2.one;
public Vector2 uvOffset = Vector2.zero; public Vector2 uvOffset = Vector2.zero;
public string customTextureThemeBundleName = "None";
public string customTextureName = "None";
public MeshGenerator.UVMode uvMode = MeshGenerator.UVMode.UniformClip;
public float uvRotation = 90f;
public float size = 1f;
public TrackRendererSubmodulePathGenerator_BM() { } public TrackRendererSubmodulePathGenerator_BM() { }
@@ -63,6 +84,11 @@ namespace Ichni.RhythmGame.Beatmap
zWrite = trSubmodule.zWrite; zWrite = trSubmodule.zWrite;
uvScale = trSubmodule.uvScale; uvScale = trSubmodule.uvScale;
uvOffset = trSubmodule.uvOffset; uvOffset = trSubmodule.uvOffset;
customTextureThemeBundleName = trSubmodule.customTextureThemeBundleName;
customTextureName = trSubmodule.customTextureName;
uvMode = trSubmodule.uvMode;
uvRotation = trSubmodule.uvRotation;
size = trSubmodule.size;
} }
public override void ExecuteBM() public override void ExecuteBM()
@@ -71,6 +97,11 @@ namespace Ichni.RhythmGame.Beatmap
if (attachedElement is Track track) if (attachedElement is Track track)
{ {
track.trackRendererSubmodule = new TrackRendererSubmodulePathGenerator(track, enableEmission, emissionIntensity, zWrite, uvScale, uvOffset); track.trackRendererSubmodule = new TrackRendererSubmodulePathGenerator(track, enableEmission, emissionIntensity, zWrite, uvScale, uvOffset);
track.trackRendererSubmodule.customTextureThemeBundleName = customTextureThemeBundleName;
track.trackRendererSubmodule.customTextureName = customTextureName;
track.trackRendererSubmodule.uvMode = uvMode;
track.trackRendererSubmodule.uvRotation = uvRotation;
track.trackRendererSubmodule.size = size;
if (materialName.Trim() != String.Empty) if (materialName.Trim() != String.Empty)
{ {
track.trackRendererSubmodule.ApplyMaterial(materialThemeBundleName, materialName); track.trackRendererSubmodule.ApplyMaterial(materialThemeBundleName, materialName);
@@ -79,7 +110,7 @@ namespace Ichni.RhythmGame.Beatmap
} }
} }
public class TrackRendererSubmoduleSurface_BM : Submodule_BM public class TrackRendererSubmoduleSurface_BM : SubmoduleBase_BM
{ {
public string materialThemeBundleName; public string materialThemeBundleName;
public string materialName; public string materialName;
@@ -88,6 +119,9 @@ namespace Ichni.RhythmGame.Beatmap
public bool zWrite; public bool zWrite;
public Vector2 uvScale = Vector2.one; public Vector2 uvScale = Vector2.one;
public Vector2 uvOffset = Vector2.zero; public Vector2 uvOffset = Vector2.zero;
public MeshGenerator.UVMode uvMode = MeshGenerator.UVMode.UniformClip;
public float uvRotation = 0f;
public float size = 1f;
public TrackRendererSubmoduleSurface_BM() { } public TrackRendererSubmoduleSurface_BM() { }
@@ -101,6 +135,9 @@ namespace Ichni.RhythmGame.Beatmap
zWrite = trSubmodule.zWrite; zWrite = trSubmodule.zWrite;
uvScale = trSubmodule.uvScale; uvScale = trSubmodule.uvScale;
uvOffset = trSubmodule.uvOffset; uvOffset = trSubmodule.uvOffset;
uvMode = trSubmodule.uvMode;
uvRotation = trSubmodule.uvRotation;
size = trSubmodule.size;
} }
public override void ExecuteBM() public override void ExecuteBM()
@@ -109,6 +146,9 @@ namespace Ichni.RhythmGame.Beatmap
if (attachedElement is Track track) if (attachedElement is Track track)
{ {
track.trackRendererSubmodule = new TrackRendererSubmoduleSurface(track, enableEmission, emissionIntensity, zWrite, uvScale, uvOffset); track.trackRendererSubmodule = new TrackRendererSubmoduleSurface(track, enableEmission, emissionIntensity, zWrite, uvScale, uvOffset);
track.trackRendererSubmodule.uvMode = uvMode;
track.trackRendererSubmodule.uvRotation = uvRotation;
track.trackRendererSubmodule.size = size;
if (materialName.Trim() != String.Empty) if (materialName.Trim() != String.Empty)
{ {
track.trackRendererSubmodule.ApplyMaterial(materialThemeBundleName, materialName); track.trackRendererSubmodule.ApplyMaterial(materialThemeBundleName, materialName);
@@ -117,7 +157,7 @@ namespace Ichni.RhythmGame.Beatmap
} }
} }
public class TrackRendererSubmoduleTubeGenerator_BM : Submodule_BM public class TrackRendererSubmoduleTubeGenerator_BM : SubmoduleBase_BM
{ {
public string materialThemeBundleName; public string materialThemeBundleName;
public string materialName; public string materialName;
@@ -127,6 +167,9 @@ namespace Ichni.RhythmGame.Beatmap
public int sideCount; public int sideCount;
public Vector2 uvScale = Vector2.one; public Vector2 uvScale = Vector2.one;
public Vector2 uvOffset = Vector2.zero; public Vector2 uvOffset = Vector2.zero;
public MeshGenerator.UVMode uvMode = MeshGenerator.UVMode.UniformClip;
public float uvRotation = 0f;
public float size = 1f;
public TrackRendererSubmoduleTubeGenerator_BM() { } public TrackRendererSubmoduleTubeGenerator_BM() { }
@@ -141,6 +184,9 @@ namespace Ichni.RhythmGame.Beatmap
zWrite = trSubmodule.zWrite; zWrite = trSubmodule.zWrite;
uvScale = trSubmodule.uvScale; uvScale = trSubmodule.uvScale;
uvOffset = trSubmodule.uvOffset; uvOffset = trSubmodule.uvOffset;
uvMode = trSubmodule.uvMode;
uvRotation = trSubmodule.uvRotation;
size = trSubmodule.size;
} }
public override void ExecuteBM() public override void ExecuteBM()
@@ -149,6 +195,9 @@ namespace Ichni.RhythmGame.Beatmap
if (attachedElement is Track track) if (attachedElement is Track track)
{ {
track.trackRendererSubmodule = new TrackRendererSubmoduleTubeGenerator(track, enableEmission, emissionIntensity, zWrite, sideCount, uvScale, uvOffset); track.trackRendererSubmodule = new TrackRendererSubmoduleTubeGenerator(track, enableEmission, emissionIntensity, zWrite, sideCount, uvScale, uvOffset);
track.trackRendererSubmodule.uvMode = uvMode;
track.trackRendererSubmodule.uvRotation = uvRotation;
track.trackRendererSubmodule.size = size;
if (materialName.Trim() != String.Empty) if (materialName.Trim() != String.Empty)
{ {
track.trackRendererSubmodule.ApplyMaterial(materialThemeBundleName, materialName); track.trackRendererSubmodule.ApplyMaterial(materialThemeBundleName, materialName);

View File

@@ -1,6 +1,6 @@
namespace Ichni.RhythmGame.Beatmap namespace Ichni.RhythmGame.Beatmap
{ {
public class TrackTimeSubmoduleMovable_BM : Submodule_BM public class TrackTimeSubmoduleMovable_BM : SubmoduleBase_BM
{ {
public float trackStartTime; public float trackStartTime;
public float trackEndTime; public float trackEndTime;
@@ -30,7 +30,7 @@ namespace Ichni.RhythmGame.Beatmap
} }
} }
public class TrackTimeSubmoduleStatic_BM : Submodule_BM public class TrackTimeSubmoduleStatic_BM : SubmoduleBase_BM
{ {
public float trackTotalTime; public float trackTotalTime;
public AnimationCurveType animationCurveType; public AnimationCurveType animationCurveType;

View File

@@ -5,7 +5,7 @@ using UnityEngine;
namespace Ichni.RhythmGame namespace Ichni.RhythmGame
{ {
public abstract partial class AnimationBase : GameElement, IHaveTimeDurationSubmodule public abstract partial class AnimationBase : GameElement, IHaveTimeDurationSubmodule, IScheduledElement
{ {
#region [] Attributes & Related Objects #region [] Attributes & Related Objects
public GameElement animatedObject; public GameElement animatedObject;
@@ -27,8 +27,7 @@ namespace Ichni.RhythmGame
{ {
base.AfterInitialize(); base.AfterInitialize();
// 【新增】受管家管控 CoreServices.UpdateScheduler.Register(UpdatePhase.Animation, this);
GameManager.Instance.animationManager.RegisterAnimation(this);
float delay = GameManager.Instance.songInformation.delay; float delay = GameManager.Instance.songInformation.delay;
if (timeDurationSubmodule.CheckTimeInDuration(-delay)) if (timeDurationSubmodule.CheckTimeInDuration(-delay))
{ {
@@ -36,6 +35,12 @@ namespace Ichni.RhythmGame
} }
} }
public override void OnDelete()
{
base.OnDelete();
CoreServices.UpdateScheduler.Unregister(UpdatePhase.Animation, this);
}
/// <summary> /// <summary>
/// 更新动画 /// 更新动画
/// </summary> /// </summary>
@@ -51,10 +56,19 @@ namespace Ichni.RhythmGame
if (timeDurationSubmodule.CheckAfterEndTime(currentSongTime)) if (timeDurationSubmodule.CheckAfterEndTime(currentSongTime))
{ {
GameManager.Instance.animationManager.UnregisterAnimation(this); CoreServices.UpdateScheduler.Unregister(UpdatePhase.Animation, this);
} }
} }
#region [IScheduledElement] Scheduler Interface
public virtual void ScheduledUpdate(UpdatePhase phase, float songTime)
{
ManualUpdate(songTime);
}
public bool IsScheduledActive => isActiveAndEnabled;
#endregion
/// <summary> /// <summary>
/// 施加时间偏移即移动所有Flexible参数的时间 /// 施加时间偏移即移动所有Flexible参数的时间
/// </summary> /// </summary>

View File

@@ -44,7 +44,7 @@ namespace Ichni.RhythmGame
if (forceUpdate || fieldOfView.returnType == FlexibleReturnType.MiddleExecuting) if (forceUpdate || fieldOfView.returnType == FlexibleReturnType.MiddleExecuting)
{ {
targetGameCamera.perspectiveAngle = fieldOfView.value; targetGameCamera.perspectiveAngle = fieldOfView.value;
targetGameCamera.cam.fieldOfView = fieldOfView.value; targetGameCamera.RefreshFOV();
} }
} }

View File

@@ -1,7 +1,5 @@
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using Ichni.RhythmGame.Beatmap;
using UnityEngine; using UnityEngine;
namespace Ichni.RhythmGame namespace Ichni.RhythmGame
@@ -90,31 +88,3 @@ namespace Ichni.RhythmGame
} }
} }
namespace Ichni.RhythmGame.Beatmap
{
public class TrackGlobalColorChange_BM : AnimationBase_BM
{
public FlexibleFloat_BM colorR, colorG, colorB, colorA;
public TrackGlobalColorChange_BM()
{
}
public TrackGlobalColorChange_BM(string elementName, Guid elementGuid, List<string> tags,
GameElement_BM attachedElement, FlexibleFloat_BM colorR, FlexibleFloat_BM colorG, FlexibleFloat_BM colorB, FlexibleFloat_BM colorA)
: base(elementName, elementGuid, tags, attachedElement)
{
this.colorR = colorR;
this.colorG = colorG;
this.colorB = colorB;
this.colorA = colorA;
}
public override void ExecuteBM()
{
matchedElement = TrackGlobalColorChange.GenerateElement(elementName, elementGuid, tags, false, GetElement(attachedElementGuid),
colorR.ConvertToGameType(), colorG.ConvertToGameType(), colorB.ConvertToGameType(), colorA.ConvertToGameType());
}
}
}

View File

@@ -45,16 +45,44 @@ namespace Ichni.RhythmGame
public override void AfterInitialize() public override void AfterInitialize()
{ {
base.AfterInitialize(); base.AfterInitialize();
// 注册 Phase 7Effect确保在 Track/TrackFollowerPhase 4/5和 NotePhase 6
// 全部更新完毕后再计算旋转覆盖,避免因位置尚未就绪导致的旋转抖动
CoreServices.UpdateScheduler.Register(UpdatePhase.Effect, this);
}
public override void OnDelete()
{
base.OnDelete();
CoreServices.UpdateScheduler.Unregister(UpdatePhase.Effect, this);
}
public override void ManualUpdate(float songTime, bool forceUpdate = false)
{
base.ManualUpdate(songTime, forceUpdate);
// 动画结束时同步注销 Phase 7
if (timeDurationSubmodule.CheckAfterEndTime(songTime))
{
CoreServices.UpdateScheduler.Unregister(UpdatePhase.Effect, this);
}
} }
#endregion #endregion
#region [] Core Animation Logic #region [] Core Animation Logic
void LateUpdate() public override void ScheduledUpdate(UpdatePhase phase, float songTime)
{ {
if (enabling.value) switch (phase)
{ {
(animatedObject as IHaveTransformSubmodule)?.UpdateLookAt(this); case UpdatePhase.Animation:
base.ScheduledUpdate(phase, songTime);
break;
case UpdatePhase.Effect:
// 在所有 Track/TrackFollower/Note 位置更新完毕后覆盖旋转
if (enabling.value)
{
(animatedObject as IHaveTransformSubmodule)?.UpdateLookAt(this);
}
break;
} }
} }

View File

@@ -1,25 +1,31 @@
namespace Ichni.RhythmGame namespace Ichni.RhythmGame
{ {
/// <summary> /// <summary>
/// 轻量级核心服务定位器,允许游戏编辑器分别注册自己的时间引擎 /// 轻量级核心服务定位器,允许游戏本体与谱面编辑器分别注册自己的时间引擎
/// </summary> /// </summary>
public static class CoreServices public static class CoreServices
{ {
public static ISongTimeProvider TimeProvider { get; set; } public static ISongTimeProvider TimeProvider { get; set; }
/// <summary>
/// 集中式元素更新调度器。
/// 所有 GameElement 子类应通过此属性访问调度器进行 Register / Unregister
/// 而非直接引用 EditorManager 或 GameManager。
/// </summary>
public static ElementUpdateScheduler UpdateScheduler { get; set; }
} }
/// <summary> /// <summary>
/// 全局时间供应器接口 /// 全局时间供应器接口
/// 无论是在游戏本体还是在谱面编辑器,一切与时间强相关的运作(特效、生成、判定 /// 无论是在游戏本体还是在谱面编辑器,一切与时间强相关的运作(特效、动画、生成)
/// 只能依赖此接口,严禁直接调用 GameManager /// 只能依赖此接口,严禁直接调用 GameManager
/// </summary> /// </summary>
public interface ISongTimeProvider public interface ISongTimeProvider
{ {
/// <summary>当前音频的播放进度时间 (秒)</summary> /// <summary>当前音频的播放进度时间(秒),已扣除 offset</summary>
float SongTime { get; } float SongTime { get; }
/// <summary>当前时间轴是否处于流转播放状态</summary> /// <summary>当前时间轴是否处于流转播放状态</summary>
bool IsPlaying { get; } bool IsPlaying { get; }
} }
} }

View File

@@ -0,0 +1,22 @@
namespace Ichni.RhythmGame
{
/// <summary>
/// 所有参与集中更新调度的元素需实现的接口。
/// 同一元素可注册到多个 <see cref="UpdatePhase"/>
/// 通过 <paramref name="phase"/> 参数区分当前所处阶段并执行对应逻辑。
/// </summary>
public interface IScheduledElement
{
/// <summary>
/// 由 <see cref="ElementUpdateScheduler"/> 在对应阶段调用。
/// </summary>
/// <param name="phase">当前执行的更新阶段</param>
/// <param name="songTime">当前音频播放时间(秒)</param>
void ScheduledUpdate(UpdatePhase phase, float songTime);
/// <summary>
/// 元素是否处于活跃状态。调度器跳过非活跃元素以节省开销。
/// </summary>
bool IsScheduledActive { get; }
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 8b0489cd9b9f44b4f9a7c73cf2b07de2

View File

@@ -2,7 +2,6 @@ using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using Ichni.RhythmGame.Beatmap; using Ichni.RhythmGame.Beatmap;
using UniRx;
using UnityEngine; using UnityEngine;
using UnityEngine.Events; using UnityEngine.Events;
@@ -21,7 +20,7 @@ namespace Ichni.RhythmGame
{ {
gameElementList = new List<GameElement>(); gameElementList = new List<GameElement>();
lowPriorityActions = new List<UnityAction>(); lowPriorityActions = new List<UnityAction>();
Observable.EveryUpdate().Subscribe(_ => ExecuteLowPriorityActions()); // UniRx Observable.EveryUpdate 已移除:低优先级操作由 ElementUpdateScheduler Phase 8 在 TickLate 中驱动
} }
public void ExecuteLowPriorityActions() public void ExecuteLowPriorityActions()

View File

@@ -0,0 +1,38 @@
namespace Ichni.RhythmGame
{
/// <summary>
/// 集中式更新调度器的阶段定义。
/// 每帧按数值升序执行,保证严格的依赖顺序:
/// 动画先于变换应用 → 变换先于 Spline 重建 → 轨道先于音符。
/// 数值留有间隔,便于未来插入新阶段。
/// </summary>
public enum UpdatePhase
{
/// <summary>判定元素激活/隐藏状态</summary>
TimeDuration = 0,
/// <summary>更新动画值,设置脏标记</summary>
Animation = 10,
/// <summary>执行 DirtyRefresh + Transform + Color</summary>
Apply = 20,
/// <summary>手动重建 Dreamteck SplineComputer同时执行 LookAt 等 Transform 后处理覆盖</summary>
SplineRebuild = 30,
/// <summary>更新轨道时间、裁剪区间</summary>
TrackCore = 40,
/// <summary>更新轨道跟踪器CrossTrackPoint / HeadPoint / PercentPoint 等)</summary>
TrackFollower = 50,
/// <summary>音符可见性、轨道位置、判定、特效</summary>
Note = 60,
/// <summary>ParticleEmitter / TimeEffectsCollection / ParticleTracker 等特效</summary>
Effect = 70,
/// <summary>SkyboxSubsetter / LowPriorityActions 等杂项</summary>
Misc = 80
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 5b8c1372937779c4ab43eeddbce7cf29

View File

@@ -1,18 +1,5 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine; using UnityEngine;
public class Dodger : MonoBehaviour public class Dodger : MonoBehaviour
{ {
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
} }

View File

@@ -6,7 +6,7 @@ using UnityEngine;
namespace Ichni.RhythmGame namespace Ichni.RhythmGame
{ {
public partial class SkyboxSubsetter : GameElement public partial class SkyboxSubsetter : GameElement, IScheduledElement
{ {
#region [] Core Components & Skybox Lists #region [] Core Components & Skybox Lists
public SkyboxBlender skyboxBlender; public SkyboxBlender skyboxBlender;
@@ -46,6 +46,18 @@ namespace Ichni.RhythmGame
skyboxSubsetter.selectedSkybox = String.Empty; skyboxSubsetter.selectedSkybox = String.Empty;
return skyboxSubsetter; return skyboxSubsetter;
} }
public override void AfterInitialize()
{
base.AfterInitialize();
CoreServices.UpdateScheduler.Register(UpdatePhase.Misc, this);
}
public override void OnDelete()
{
base.OnDelete();
CoreServices.UpdateScheduler.Unregister(UpdatePhase.Misc, this);
}
#endregion #endregion
#region [] Internal Configs & Utils #region [] Internal Configs & Utils
@@ -81,28 +93,31 @@ namespace Ichni.RhythmGame
#endregion #endregion
#region [] Main Update #region [] Main Update
private void Update() #region [IScheduledElement] Scheduler Interface
public void ScheduledUpdate(UpdatePhase phase, float songTime)
{ {
if (skyBoxThemeBundleList.Count > 1) if (skyBoxThemeBundleList.Count > 1)
{ {
float songTime = CoreServices.TimeProvider.SongTime;
float delay = GameManager.Instance.songInformation.delay; float delay = GameManager.Instance.songInformation.delay;
float finalTime = 32767; // 曲目长度 const float finalTime = 32767f; // 曲目长度上限
for (var index = 0; index < blendTimeList.Count + 1; index++) for (var index = 0; index < blendTimeList.Count + 1; index++)
{ {
float startTime = index == 0 ? -delay : blendTimeList[index - 1]; float startTime = index == 0 ? -delay : blendTimeList[index - 1];
float endTime = index >= blendTimeList.Count ? finalTime : blendTimeList[index]; float endTime = index >= blendTimeList.Count ? finalTime : blendTimeList[index];
if(songTime >= startTime && songTime < endTime && currentSkyboxIndex != index) if (songTime >= startTime && songTime < endTime && currentSkyboxIndex != index)
{ {
currentSkyboxIndex = index; currentSkyboxIndex = index;
if(currentSkyboxIndex != 0) skyboxBlender.blendSpeed = blendSpeedList[currentSkyboxIndex - 1]; if (currentSkyboxIndex != 0) skyboxBlender.blendSpeed = blendSpeedList[currentSkyboxIndex - 1];
skyboxBlender.Blend(currentSkyboxIndex, false); skyboxBlender.Blend(currentSkyboxIndex, false);
DynamicGI.UpdateEnvironment(); DynamicGI.UpdateEnvironment();
} }
} }
} }
} }
public bool IsScheduledActive => isActiveAndEnabled;
#endregion
#endregion #endregion
} }

View File

@@ -25,6 +25,12 @@ namespace Ichni.RhythmGame
public float orthographicSize; public float orthographicSize;
public float perspectiveOffset; public float perspectiveOffset;
public float zoomOffset; // 用于效果如CameraZoomEffect的临时视野偏移
public void RefreshFOV()
{
cam.fieldOfView = perspectiveAngle + perspectiveOffset + zoomOffset;
}
#endregion #endregion
#region [] Submodules & References #region [] Submodules & References
@@ -54,14 +60,14 @@ namespace Ichni.RhythmGame
float ratioDifference = UIManager.GetScreenRatio() - UIManager.StandardRatio; float ratioDifference = UIManager.GetScreenRatio() - UIManager.StandardRatio;
if (ratioDifference > 0) if (ratioDifference > 0)
{ {
gameCamera.perspectiveOffset = -22f * ratioDifference; //gameCamera.perspectiveOffset = 12.5f * ratioDifference;
} }
else else
{ {
//gameCamera.perspectiveOffset = 11f * ratioDifference; gameCamera.perspectiveOffset = -25f * ratioDifference;
} }
gameCamera.cam.fieldOfView = perspectiveAngle + gameCamera.perspectiveOffset; gameCamera.RefreshFOV();
return gameCamera; return gameCamera;
} }

View File

@@ -7,7 +7,7 @@ using Object = UnityEngine.Object;
namespace Ichni.RhythmGame namespace Ichni.RhythmGame
{ {
public partial class ParticleEmitter : GameElement, IHaveParticles, IHaveTimeDurationSubmodule, IHaveTransformSubmodule, IHaveColorSubmodule public partial class ParticleEmitter : GameElement, IHaveParticles, IHaveTimeDurationSubmodule, IHaveTransformSubmodule, IHaveColorSubmodule, IScheduledElement
{ {
#region [] Essential Configs #region [] Essential Configs
public string themeBundleName; public string themeBundleName;
@@ -85,15 +85,26 @@ namespace Ichni.RhythmGame
transformSubmodule = new TransformSubmodule(this); transformSubmodule = new TransformSubmodule(this);
colorSubmodule = new ColorSubmodule(this, Color.white, true, Color.white, 0); colorSubmodule = new ColorSubmodule(this, Color.white, true, Color.white, 0);
} }
public override void AfterInitialize()
{
base.AfterInitialize();
CoreServices.UpdateScheduler.Register(UpdatePhase.Effect, this);
}
public override void OnDelete()
{
base.OnDelete();
CoreServices.UpdateScheduler.Unregister(UpdatePhase.Effect, this);
}
#endregion #endregion
} }
#region [] Main Update & Behavior Overrides #region [] Main Update & Behavior Overrides
public partial class ParticleEmitter public partial class ParticleEmitter
{ {
private void Update() private void UpdateParticlePlayState(float songTime)
{ {
float songTime = CoreServices.TimeProvider.SongTime;
if (playTime > songTime || stopTime < songTime) if (playTime > songTime || stopTime < songTime)
{ {
particle.Stop(); particle.Stop();
@@ -107,6 +118,15 @@ namespace Ichni.RhythmGame
} }
} }
#region [IScheduledElement] Scheduler Interface
public void ScheduledUpdate(UpdatePhase phase, float songTime)
{
UpdateParticlePlayState(songTime);
}
public bool IsScheduledActive => isActiveAndEnabled;
#endregion
public override void Refresh() public override void Refresh()
{ {
base.Refresh(); base.Refresh();

View File

@@ -8,12 +8,18 @@ using UnityEngine;
namespace Ichni.RhythmGame namespace Ichni.RhythmGame
{ {
public partial class TimeEffectsCollection : GameElement, IHaveTransformSubmodule, IHaveEffectSubmodule public partial class TimeEffectsCollection : GameElement, IHaveTransformSubmodule, IHaveEffectSubmodule, IScheduledElement
{ {
#region [] Essential Configs #region [] Essential Configs
public float time; //触发效果的时间 public float time; //触发效果的时间
#endregion #endregion
#region [] Cached Effect Lists
private List<EffectBase> _priorEffects;
private List<EffectBase> _defaultEffects;
private List<EffectBase> _lateEffects;
#endregion
#region [] Submodules #region [] Submodules
public TransformSubmodule transformSubmodule { get; set; } public TransformSubmodule transformSubmodule { get; set; }
public EffectSubmodule effectSubmodule { get; set; } public EffectSubmodule effectSubmodule { get; set; }
@@ -34,31 +40,55 @@ namespace Ichni.RhythmGame
transformSubmodule = new TransformSubmodule(this); transformSubmodule = new TransformSubmodule(this);
effectSubmodule = new EffectSubmodule(this); effectSubmodule = new EffectSubmodule(this);
} }
public override void AfterInitialize()
{
base.AfterInitialize();
CacheEffectLists();
CoreServices.UpdateScheduler.Register(UpdatePhase.Effect, this);
}
public override void OnDelete()
{
base.OnDelete();
CoreServices.UpdateScheduler.Unregister(UpdatePhase.Effect, this);
}
/// <summary>
/// 缓存 effectCollection 中的 Prior/Default/Late 列表引用,
/// 避免 ScheduledUpdate 中每帧执行 Dictionary string key 查找。
/// </summary>
private void CacheEffectLists()
{
if (effectSubmodule?.effectCollection == null) return;
effectSubmodule.effectCollection.TryGetValue("Prior", out _priorEffects);
effectSubmodule.effectCollection.TryGetValue("Default", out _defaultEffects);
effectSubmodule.effectCollection.TryGetValue("Late", out _lateEffects);
}
#endregion #endregion
#region [] Main Update #region [] Main Update
private void Update() #region [IScheduledElement] Scheduler Interface
public void ScheduledUpdate(UpdatePhase phase, float songTime)
{ {
if (!GameManager.Instance.songPlayer.isUpdating || effectSubmodule == null) if (effectSubmodule == null) return;
{
return;
}
foreach (EffectBase effect in effectSubmodule.effectCollection["Prior"]) UpdateEffectList(_priorEffects, time);
{ UpdateEffectList(_defaultEffects, time);
effect.UpdateEffect(time); UpdateEffectList(_lateEffects, time);
} }
foreach (EffectBase effect in effectSubmodule.effectCollection["Default"]) private static void UpdateEffectList(List<EffectBase> effects, float effectTime)
{
if (effects == null) return;
for (int i = 0; i < effects.Count; i++)
{ {
effect.UpdateEffect(time); effects[i].UpdateEffect(effectTime);
}
foreach (EffectBase effect in effectSubmodule.effectCollection["Late"])
{
effect.UpdateEffect(time);
} }
} }
public bool IsScheduledActive => isActiveAndEnabled;
#endregion
#endregion #endregion
} }

View File

@@ -42,7 +42,7 @@ namespace Ichni.RhythmGame
public override bool CheckJudgeAvailability(InputUnit inputUnit) public override bool CheckJudgeAvailability(InputUnit inputUnit)
{ {
Vector2 inputScreenPosition = inputUnit.inputPosition; Vector2 inputScreenPosition = inputUnit.inputPosition;
Vector2 noteScreenPosition = note.GetScreenPosition(); Vector2 noteScreenPosition = note.noteScreenPosition != Vector2.zero ? note.noteScreenPosition : note.GetScreenPosition();
float scaledBaseRadius = areaRadius * CurrentScreenRatio; float scaledBaseRadius = areaRadius * CurrentScreenRatio;
float dx = Mathf.Abs(inputScreenPosition.x - noteScreenPosition.x) / ellipseXMultiplier; float dx = Mathf.Abs(inputScreenPosition.x - noteScreenPosition.x) / ellipseXMultiplier;

View File

@@ -295,6 +295,7 @@ namespace Ichni.RhythmGame
protected virtual void ExecuteJudge(NoteJudgeType judgeType, float triggerTime) protected virtual void ExecuteJudge(NoteJudgeType judgeType, float triggerTime)
{ {
isDuringJudging = false; isDuringJudging = false;
isFirstJudged = true;
judgedTriggerTime = triggerTime; judgedTriggerTime = triggerTime;
judgedType = judgeType; judgedType = judgeType;

View File

@@ -10,7 +10,7 @@ using UnityEngine.Serialization;
namespace Ichni.RhythmGame namespace Ichni.RhythmGame
{ {
public partial class Track : GameElement, IHaveTransformSubmodule, IHaveTimeDurationSubmodule public partial class Track : GameElement, IHaveTransformSubmodule, IHaveTimeDurationSubmodule, IScheduledElement
{ {
#region [] Essential Configs #region [] Essential Configs
public GameObject trackRenderer; public GameObject trackRenderer;
@@ -50,7 +50,11 @@ namespace Ichni.RhythmGame
{ {
base.AfterInitialize(); base.AfterInitialize();
// 保留 TrackManager 注册以维持 ManualLateUpdate 的 refreshedThisFrame 清除逻辑
GameManager.Instance.trackManager.RegisterTrack(this); GameManager.Instance.trackManager.RegisterTrack(this);
// 注册调度器 Phase 4TrackCore驱动 ManualUpdate
CoreServices.UpdateScheduler.Register(UpdatePhase.TrackCore, this);
CoreServices.UpdateScheduler.RegisterTrackSpline(this);
if (trackPathSubmodule != null && trackPathSubmodule.pathNodeList.Count > 3) if (trackPathSubmodule != null && trackPathSubmodule.pathNodeList.Count > 3)
{ {
@@ -77,6 +81,15 @@ namespace Ichni.RhythmGame
{ {
if(trackPathSubmodule != null) trackPathSubmodule.refreshedThisFrame = false; if(trackPathSubmodule != null) trackPathSubmodule.refreshedThisFrame = false;
} }
#region [IScheduledElement] Scheduler Interface
public void ScheduledUpdate(UpdatePhase phase, float songTime)
{
ManualUpdate(songTime);
}
public bool IsScheduledActive => isActiveAndEnabled;
#endregion
#endregion #endregion
#region [] Behavior Overrides #region [] Behavior Overrides
@@ -91,6 +104,8 @@ namespace Ichni.RhythmGame
public override void OnDelete() public override void OnDelete()
{ {
GameManager.Instance.trackManager.UnregisterTrack(this); GameManager.Instance.trackManager.UnregisterTrack(this);
CoreServices.UpdateScheduler.Unregister(UpdatePhase.TrackCore, this);
CoreServices.UpdateScheduler.UnregisterTrackSpline(this);
if (parentElement is ElementFolder folder) folder.trackList.Remove(this); if (parentElement is ElementFolder folder) folder.trackList.Remove(this);
} }
#endregion #endregion

View File

@@ -9,7 +9,7 @@ using UnityEngine;
namespace Ichni.RhythmGame namespace Ichni.RhythmGame
{ {
public partial class CrossTrackPoint : GameElement, IHaveTimeDurationSubmodule public partial class CrossTrackPoint : GameElement, IHaveTimeDurationSubmodule, IScheduledElement
{ {
#region [] Essential Configs #region [] Essential Configs
public ElementFolder trackListFolder; public ElementFolder trackListFolder;
@@ -45,10 +45,16 @@ namespace Ichni.RhythmGame
public override void AfterInitialize() public override void AfterInitialize()
{ {
GameManager.Instance.trackManager.RegisterCrossPoint(this); CoreServices.UpdateScheduler.Register(UpdatePhase.TrackFollower, this);
base.AfterInitialize(); base.AfterInitialize();
} }
public override void OnDelete()
{
base.OnDelete();
CoreServices.UpdateScheduler.Unregister(UpdatePhase.TrackFollower, this);
}
public override void SetDefaultSubmodules() public override void SetDefaultSubmodules()
{ {
timeDurationSubmodule = new TimeDurationSubmodule(this); timeDurationSubmodule = new TimeDurationSubmodule(this);
@@ -68,11 +74,20 @@ namespace Ichni.RhythmGame
trackPercent.returnType == FlexibleReturnType.After) trackPercent.returnType == FlexibleReturnType.After)
{ {
trackPositioner.SetPercent(1); trackPositioner.SetPercent(1);
GameManager.Instance.trackManager.UnregisterCrossPoint(this); CoreServices.UpdateScheduler.Unregister(UpdatePhase.TrackFollower, this);
} }
} }
} }
#region [IScheduledElement] Scheduler Interface
public void ScheduledUpdate(UpdatePhase phase, float songTime)
{
ManualUpdate(songTime);
}
public bool IsScheduledActive => isActiveAndEnabled;
#endregion
private void SetPoint() private void SetPoint()
{ {
if (nowAttachedTrackIndex != trackSwitch.value && if (nowAttachedTrackIndex != trackSwitch.value &&
@@ -82,6 +97,7 @@ namespace Ichni.RhythmGame
nowAttachedTrack = trackListFolder.trackList[trackSwitch.value]; nowAttachedTrack = trackListFolder.trackList[trackSwitch.value];
nowAttachedTrackIndex = trackSwitch.value; nowAttachedTrackIndex = trackSwitch.value;
trackPositioner.spline = trackListFolder.trackList[trackSwitch.value].trackPathSubmodule.path; trackPositioner.spline = trackListFolder.trackList[trackSwitch.value].trackPathSubmodule.path;
trackPositioner.RebuildImmediate();
} }
trackPositioner.SetPercent(trackPercent.value); trackPositioner.SetPercent(trackPercent.value);

View File

@@ -8,7 +8,7 @@ using UnityEngine;
namespace Ichni.RhythmGame namespace Ichni.RhythmGame
{ {
public partial class TrackHeadPoint : GameElement, IHaveTimeDurationSubmodule public partial class TrackHeadPoint : GameElement, IHaveTimeDurationSubmodule, IScheduledElement
{ {
#region [] Essential Configs #region [] Essential Configs
public Track track; public Track track;
@@ -53,9 +53,15 @@ namespace Ichni.RhythmGame
public override void AfterInitialize() public override void AfterInitialize()
{ {
GameManager.Instance.trackManager.RegisterHeadPoint(this); CoreServices.UpdateScheduler.Register(UpdatePhase.TrackFollower, this);
base.AfterInitialize(); base.AfterInitialize();
} }
public override void OnDelete()
{
base.OnDelete();
CoreServices.UpdateScheduler.Unregister(UpdatePhase.TrackFollower, this);
}
#endregion #endregion
#region [] Main Update #region [] Main Update
@@ -68,9 +74,18 @@ namespace Ichni.RhythmGame
if(track.timeDurationSubmodule.CheckAfterEndTime(currentSongTime)) if(track.timeDurationSubmodule.CheckAfterEndTime(currentSongTime))
{ {
GameManager.Instance.trackManager.UnregisterHeadPoint(this); CoreServices.UpdateScheduler.Unregister(UpdatePhase.TrackFollower, this);
} }
} }
#region [IScheduledElement] Scheduler Interface
public void ScheduledUpdate(UpdatePhase phase, float songTime)
{
ManualUpdate(songTime);
}
public bool IsScheduledActive => isActiveAndEnabled;
#endregion
#endregion #endregion
} }

View File

@@ -13,7 +13,7 @@ namespace Ichni.RhythmGame
/// <summary> /// <summary>
/// 在轨道上根据百分比进行运动的点 /// 在轨道上根据百分比进行运动的点
/// </summary> /// </summary>
public partial class TrackPercentPoint : GameElement, IHaveTimeDurationSubmodule public partial class TrackPercentPoint : GameElement, IHaveTimeDurationSubmodule, IScheduledElement
{ {
#region [] Essential Configs #region [] Essential Configs
public Track track; public Track track;
@@ -52,9 +52,15 @@ namespace Ichni.RhythmGame
public override void AfterInitialize() public override void AfterInitialize()
{ {
GameManager.Instance.trackManager.RegisterPercentPoint(this); CoreServices.UpdateScheduler.Register(UpdatePhase.TrackFollower, this);
base.AfterInitialize(); base.AfterInitialize();
} }
public override void OnDelete()
{
base.OnDelete();
CoreServices.UpdateScheduler.Unregister(UpdatePhase.TrackFollower, this);
}
#endregion #endregion
#region [] Main Update #region [] Main Update
@@ -73,10 +79,19 @@ namespace Ichni.RhythmGame
if (trackPercent.returnType == FlexibleReturnType.After) if (trackPercent.returnType == FlexibleReturnType.After)
{ {
trackPositioner.SetPercent(1); trackPositioner.SetPercent(1);
GameManager.Instance.trackManager.UnregisterPercentPoint(this); CoreServices.UpdateScheduler.Unregister(UpdatePhase.TrackFollower, this);
} }
} }
} }
#region [IScheduledElement] Scheduler Interface
public void ScheduledUpdate(UpdatePhase phase, float songTime)
{
ManualUpdate(songTime);
}
public bool IsScheduledActive => isActiveAndEnabled;
#endregion
#endregion #endregion
} }

View File

@@ -66,13 +66,16 @@ namespace Ichni.RhythmGame
path.sampleRate = 1; path.sampleRate = 1;
} }
if (isClosed) if (pathNodeList.Count >= 3)
{ {
path.Close(); if (isClosed)
} {
else path.Close();
{ }
path.Break(); else
{
path.Break();
}
} }
} }

View File

@@ -14,6 +14,11 @@ namespace Ichni.RhythmGame
public string materialThemeBundleName; public string materialThemeBundleName;
public string materialName; public string materialName;
public string customTextureThemeBundleName = "None";
public string customTextureName = "None";
public MeshGenerator.UVMode uvMode = MeshGenerator.UVMode.UniformClip;
public float uvRotation = 0f;
public float size = 1f;
public bool enableEmission; public bool enableEmission;
public float emissionIntensity; public float emissionIntensity;
public bool zWrite; public bool zWrite;
@@ -86,6 +91,9 @@ namespace Ichni.RhythmGame
{ {
meshGenerator.uvScale = uvScale; meshGenerator.uvScale = uvScale;
meshGenerator.uvOffset = uvOffset; meshGenerator.uvOffset = uvOffset;
meshGenerator.uvRotation = uvRotation;
meshGenerator.uvMode = uvMode;
meshGenerator.size = size;
} }
} }
#endregion #endregion

View File

@@ -32,8 +32,8 @@ namespace Ichni.RhythmGame
this.splineRenderer.updateMethod = SplineUser.UpdateMethod.Update; this.splineRenderer.updateMethod = SplineUser.UpdateMethod.Update;
this.meshRenderer.material = renderMaterial; this.meshRenderer.material = renderMaterial;
this.splineRenderer.color = Color.white; this.splineRenderer.color = Color.white;
this.splineRenderer.uvRotation = 90; this.uvRotation = 0f;
this.splineRenderer.uvMode = MeshGenerator.UVMode.UniformClip; this.uvMode = MeshGenerator.UVMode.UniformClip;
SetMesh(); SetMesh();
} }

View File

@@ -31,8 +31,8 @@ namespace Ichni.RhythmGame
this.pathGenerator.updateMethod = SplineUser.UpdateMethod.Update; this.pathGenerator.updateMethod = SplineUser.UpdateMethod.Update;
this.meshRenderer.material = renderMaterial; this.meshRenderer.material = renderMaterial;
this.pathGenerator.color = Color.white; this.pathGenerator.color = Color.white;
this.pathGenerator.uvRotation = 90; this.uvRotation = 90f;
this.pathGenerator.uvMode = MeshGenerator.UVMode.UniformClip; this.uvMode = MeshGenerator.UVMode.UniformClip;
SetMesh(); SetMesh();
} }

View File

@@ -56,7 +56,10 @@ namespace Ichni.RhythmGame
{ {
track.trackRendererSubmodule.meshGenerator.clipFrom = tailPercent; track.trackRendererSubmodule.meshGenerator.clipFrom = tailPercent;
track.trackRendererSubmodule.meshGenerator.clipTo = headPercent; track.trackRendererSubmodule.meshGenerator.clipTo = headPercent;
track.trackRendererSubmodule.meshGenerator.RebuildImmediate();
} }
//track.trackPathSubmodule.path.Rebuild(true);
} }
public float GetTrackPercent(float songTimeInTime) public float GetTrackPercent(float songTimeInTime)

View File

@@ -1,18 +1,5 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine; using UnityEngine;
public class ObjectTracker : MonoBehaviour public class ObjectTracker : MonoBehaviour
{ {
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
} }

Some files were not shown because too many files have changed in this diff Show More