This commit is contained in:
SoulliesOfficial
2026-03-14 02:30:26 -04:00
parent cf86f0ee51
commit aee62cd637
2041 changed files with 246771 additions and 129128 deletions

View File

@@ -25,6 +25,9 @@ namespace Ichni.Editor
public GameObject ConsoleUI;
public TMP_Text cueText;
bool isHide = true;
private string FillCueCommand(MethodInfo method)
{
if (method == null)
@@ -115,7 +118,15 @@ namespace Ichni.Editor
private void Update()
{
UIscale();
if (InputCommand.isFocused) InputDect();
if (InputCommand.isFocused)
{
InputDect();
}
else
{
Debug.Log("未聚焦输入框");
}
}
private void UIscale()
{
@@ -177,6 +188,8 @@ namespace Ichni.Editor
//这是史,不要看
private void InputDect()
{
Debug.Log("输入指令中");
// 向下翻历史命令
if (Keyboard.current.downArrowKey.wasPressedThisFrame)
{
@@ -192,6 +205,8 @@ namespace Ichni.Editor
}
return;
}
Debug.Log("输入指令中 - 1");
// 向上翻历史命令
if (Keyboard.current.upArrowKey.wasPressedThisFrame && historycount != 0)
@@ -200,32 +215,11 @@ namespace Ichni.Editor
InputCommand.text = historyCommand[historycount];
return;
}
Debug.Log("输入指令中 - 2");
// 提交命令
if (Keyboard.current.enterKey.wasPressedThisFrame)
{
string input = InputCommand.text; // 原始命令文本
if (string.IsNullOrWhiteSpace(input))
{
InputCommand.text = "";
return;
}
// 【修改点】:调用新方法获取最终执行的命令(已包含修正逻辑和 TransformCommand
string ExpoCommand = GetFinalCommandForExecution(input);
// print(ExpoCommand); // 调试语句,可选
GetCommand(ExpoCommand);
// 记录历史命令,使用原始命令 input
if (historyCommand.ContainsKey(historycount))
historyCommand[historycount] = input;
else
historyCommand.Add(historycount, input);
historycount++;
InputCommand.text = "";
}
CheckCtrlNumberShortcut();
}
@@ -328,11 +322,41 @@ namespace Ichni.Editor
{
SetUpFunctions();
InputCommand.onSubmit.AddListener(OnSubmitCommand);
//Test
// functionInterpreter.Eval("print(\"Hello World!\")");
// functionInterpreter.Eval("log(\"Hello World but debug!\")");
}
private void OnSubmitCommand(string input)
{
if (string.IsNullOrWhiteSpace(input))
{
InputCommand.text = "";
return;
}
// 执行转换和提交命令
string ExpoCommand = GetFinalCommandForExecution(input);
GetCommand(ExpoCommand);
// 记录历史
if (historyCommand.ContainsKey(historycount))
historyCommand[historycount] = input;
else
historyCommand.Add(historycount, input);
historycount++;
// 提交后清零输入框文本
InputCommand.text = "";
// 核心体验优化:回车后立刻强制重新激活聚焦光标,以便用户紧接着顺畅丝滑地连续敲下一条指令
InputCommand.ActivateInputField();
}
}
public partial class EditorConsole

View File

@@ -365,7 +365,7 @@ namespace Ichni.Editor
float endTime = hold.holdEndTime;
float interval = 1f / (PathnodesCount - 1);
hold.UpdateNoteInMovableTrack();
hold.UpdateNoteInMovableTrack(CoreServices.TimeProvider.SongTime);
Vector3 HoldStartPos = default;
Vector3 HoldEndPos = default;
if (hold.noteVisual is DTMNoteVisualHold dTMNoteVisualHold)
@@ -385,7 +385,7 @@ namespace Ichni.Editor
LogWindow.Log("the Hold may not be split currently", Color.yellow);
return;
}
hold.UpdateNoteInMovableTrack();
hold.UpdateNoteInMovableTrack(CoreServices.TimeProvider.SongTime);
Track NewTrack = Track.GenerateElement(hold.elementName + "_SplitTrack", Guid.NewGuid(), new List<string>(), true, parentTrack);
new TrackTimeSubmoduleMovable(NewTrack, startTime, endTime, 1, AnimationCurveType.Linear);
for (int i = 0; i < PathnodesCount; i++)

View File

@@ -14,18 +14,16 @@ namespace Ichni.Editor
{
public GameObject logTextPrefab;
List<string> savedTexts;
public List<string> savedTexts = new List<string>();
public RectTransform textRect;
public Button copyAllTextsButton;
public Button removeAllTextsButton;
public List<LogText> logTexts; // 改为 List
public List<LogText> logTexts = new List<LogText>(); // 改为 List
public int logTextCapacity = 4;
protected override void Start()
{
base.Start();
savedTexts = new List<string>();
logTexts = new List<LogText>(); // 初始化为 List
copyAllTextsButton.onClick.AddListener(CopyAllText);
removeAllTextsButton.onClick.AddListener(RemoveAllText);
}

View File

@@ -53,11 +53,9 @@ namespace Ichni.Editor
}
public void Update()
{
if (EditorManager.instance.musicPlayer.isPlaying)
if (CoreServices.TimeProvider.IsPlaying)
{
UpdateTime();
}
if (RectTransformUtility.RectangleContainsScreenPoint(GetinputArea, Mouse.current.position.ReadValue()))

Binary file not shown.

View File

@@ -1,153 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using Lean.Pool;
using UnityEngine;
namespace Ichni.RhythmGame
{
public partial class BaseColorChange : AnimationBase
{
private ColorSubmodule targetColorSubmodule;
public FlexibleFloat colorR, colorG, colorB, colorA;
public static BaseColorChange GenerateElement(string elementName, Guid id,
List<string> tags, bool isFirstGenerated, GameElement animatedObject,
FlexibleFloat colorR, FlexibleFloat colorG, FlexibleFloat colorB, FlexibleFloat colorA)
{
BaseColorChange baseColorChange = Instantiate(EditorManager.instance.basePrefabs.emptyObject)
.AddComponent<BaseColorChange>();
baseColorChange.Initialize(elementName, id, tags, isFirstGenerated, animatedObject);
baseColorChange.animatedObject = animatedObject;
baseColorChange.colorR = colorR;
baseColorChange.colorG = colorG;
baseColorChange.colorB = colorB;
baseColorChange.colorA = colorA;
baseColorChange.animationReturnType = FlexibleReturnType.Before;
baseColorChange.targetColorSubmodule = (animatedObject as IHaveColorSubmodule).colorSubmodule;
//baseColorChange.timeDurationSubmodule.SetDuration(colorR, colorG, colorB, colorA);
return baseColorChange;
}
public override void SetDefaultSubmodules()
{
timeDurationSubmodule = new TimeDurationSubmodule(this);
}
protected override void UpdateAnimation(float songTime)
{
colorR.UpdateFlexibleFloat(songTime);
colorG.UpdateFlexibleFloat(songTime);
colorB.UpdateFlexibleFloat(songTime);
colorA.UpdateFlexibleFloat(songTime);
if ((colorR.returnType is FlexibleReturnType.MiddleExecuting || colorR.isSwitchingReturnType) ||
(colorG.returnType is FlexibleReturnType.MiddleExecuting || colorG.isSwitchingReturnType) ||
(colorB.returnType is FlexibleReturnType.MiddleExecuting || colorB.isSwitchingReturnType) ||
(colorA.returnType is FlexibleReturnType.MiddleExecuting || colorA.isSwitchingReturnType))
{
animationReturnType = FlexibleReturnType.MiddleExecuting;
targetColorSubmodule.currentBaseColor = new Color(colorR.value, colorG.value, colorB.value, colorA.value);
targetColorSubmodule.baseColorDirtyMark = true;
}
else
{
animationReturnType = FlexibleReturnType.MiddleInterval;
}
}
public override void ApplyTimeOffset(float offset)
{
base.ApplyTimeOffset(offset);
colorR.animations.ForEach(anim => anim.ApplyTimeOffset(offset));
colorG.animations.ForEach(anim => anim.ApplyTimeOffset(offset));
colorB.animations.ForEach(anim => anim.ApplyTimeOffset(offset));
colorA.animations.ForEach(anim => anim.ApplyTimeOffset(offset));
}
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
base.SetUpInspector();
var container = inspector.GenerateContainer("Base Color Change");
var subcontainer = container.GenerateSubcontainer(3);
var colorRButton = inspector.GenerateButton(this, subcontainer, "Color R", () =>
{
inspector.GenerateCompositeParameterWindow(this, "Color R", nameof(colorR)).SetAsFlexibleFloat();
});
var colorGButton = inspector.GenerateButton(this, subcontainer, "Color G", () =>
{
inspector.GenerateCompositeParameterWindow(this, "Color G", nameof(colorG)).SetAsFlexibleFloat();
});
var colorBButton = inspector.GenerateButton(this, subcontainer, "Color B", () =>
{
inspector.GenerateCompositeParameterWindow(this, "Color B", nameof(colorB)).SetAsFlexibleFloat();
});
var colorAButton = inspector.GenerateButton(this, subcontainer, "Color A", () =>
{
inspector.GenerateCompositeParameterWindow(this, "Color A", nameof(colorA)).SetAsFlexibleFloat();
});
var graphicEditor = inspector.GenerateButton(this, subcontainer, "GraphicEditor", () =>
{
inspector.GenerateGraphicalFlexibleFloatWindow(this, "Base Color",
new FlexibleFloat[] { colorR, colorG, colorB, colorA }, new string[] { "R", "G", "B", "A" });
});
}
}
public partial class BaseColorChange
{
public override void SaveBM()
{
matchedBM = new BaseColorChange_BM(elementName, elementGuid, tags,
animatedObject.matchedBM as GameElement_BM, colorR.ConvertToBM(),
colorG.ConvertToBM(), colorB.ConvertToBM(), colorA.ConvertToBM());
}
}
namespace Beatmap
{
public class BaseColorChange_BM : AnimationBase_BM
{
public FlexibleFloat_BM colorR, colorG, colorB, colorA;
public BaseColorChange_BM()
{
}
public BaseColorChange_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 = BaseColorChange.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid), colorR.ConvertToGameType(),
colorG.ConvertToGameType(), colorB.ConvertToGameType(), colorA.ConvertToGameType());
}
public override GameElement DuplicateBM(GameElement parent)
{
return BaseColorChange.GenerateElement(elementName, Guid.NewGuid(), tags, false,
parent, colorR.ConvertToGameType(), colorG.ConvertToGameType(),
colorB.ConvertToGameType(), colorA.ConvertToGameType());
}
}
}
}

View File

@@ -1,150 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using Lean.Pool;
using UnityEngine;
namespace Ichni.RhythmGame
{
public partial class EmissionColorChange : AnimationBase
{
private ColorSubmodule targetColorSubmodule;
public FlexibleFloat colorR, colorG, colorB, colorI;
public static EmissionColorChange GenerateElement(string elementName, Guid id,
List<string> tags, bool isFirstGenerated, GameElement animatedObject,
FlexibleFloat colorR, FlexibleFloat colorG, FlexibleFloat colorB, FlexibleFloat colorI)
{
EmissionColorChange emissionColorChange = Instantiate(EditorManager.instance.basePrefabs.emptyObject).AddComponent<EmissionColorChange>();
emissionColorChange.Initialize(elementName, id, tags, isFirstGenerated, animatedObject);
emissionColorChange.animatedObject = animatedObject;
emissionColorChange.colorR = colorR;
emissionColorChange.colorG = colorG;
emissionColorChange.colorB = colorB;
emissionColorChange.colorI = colorI;
emissionColorChange.animationReturnType = FlexibleReturnType.Before;
emissionColorChange.targetColorSubmodule = (animatedObject as IHaveColorSubmodule).colorSubmodule;
//emissionColorChange.timeDurationSubmodule.SetDuration(colorR, colorG, colorB, colorI);
return emissionColorChange;
}
public override void SetDefaultSubmodules()
{
timeDurationSubmodule = new TimeDurationSubmodule(this);
}
protected override void UpdateAnimation(float songTime)
{
colorR.UpdateFlexibleFloat(songTime);
colorG.UpdateFlexibleFloat(songTime);
colorB.UpdateFlexibleFloat(songTime);
colorI.UpdateFlexibleFloat(songTime);
if ((colorR.returnType is FlexibleReturnType.MiddleExecuting || colorR.isSwitchingReturnType) ||
(colorG.returnType is FlexibleReturnType.MiddleExecuting || colorG.isSwitchingReturnType) ||
(colorB.returnType is FlexibleReturnType.MiddleExecuting || colorB.isSwitchingReturnType) ||
(colorI.returnType is FlexibleReturnType.MiddleExecuting || colorI.isSwitchingReturnType))
{
animationReturnType = FlexibleReturnType.MiddleExecuting;
targetColorSubmodule.currentEmissionColor = new Color(colorR.value, colorG.value, colorB.value, 1);
targetColorSubmodule.currentEmissionIntensity = colorI.value;
targetColorSubmodule.emissionColorDirtyMark = true;
}
else
{
animationReturnType = FlexibleReturnType.MiddleInterval;
}
}
public override void ApplyTimeOffset(float offset)
{
base.ApplyTimeOffset(offset);
colorR.animations.ForEach(anim => anim.ApplyTimeOffset(offset));
colorG.animations.ForEach(anim => anim.ApplyTimeOffset(offset));
colorB.animations.ForEach(anim => anim.ApplyTimeOffset(offset));
colorI.animations.ForEach(anim => anim.ApplyTimeOffset(offset));
}
}
public partial class EmissionColorChange
{
public override void SaveBM()
{
matchedBM = new EmissionColorChange_BM(elementName, elementGuid, tags, animatedObject.matchedBM as GameElement_BM,
colorR.ConvertToBM(), colorG.ConvertToBM(), colorB.ConvertToBM(), colorI.ConvertToBM());
}
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
base.SetUpInspector();
var container = inspector.GenerateContainer("Base Color Change");
var subcontainer = container.GenerateSubcontainer(3);
var colorRButton = inspector.GenerateButton(this, subcontainer, "Color R", () =>
{
inspector.GenerateCompositeParameterWindow(this, "Color R", nameof(colorR)).SetAsFlexibleFloat();
});
var colorGButton = inspector.GenerateButton(this, subcontainer, "Color G", () =>
{
inspector.GenerateCompositeParameterWindow(this, "Color G", nameof(colorG)).SetAsFlexibleFloat();
});
var colorBButton = inspector.GenerateButton(this, subcontainer, "Color B", () =>
{
inspector.GenerateCompositeParameterWindow(this, "Color B", nameof(colorB)).SetAsFlexibleFloat();
});
var colorAButton = inspector.GenerateButton(this, subcontainer, "Color A", () =>
{
inspector.GenerateCompositeParameterWindow(this, "Color I", nameof(colorI)).SetAsFlexibleFloat();
});
var graphicEditor = inspector.GenerateButton(this, subcontainer, "GraphicEditor", () =>
{
inspector.GenerateGraphicalFlexibleFloatWindow(this, "Emission Color",
new FlexibleFloat[] { colorR, colorG, colorB, colorI }, new string[] { "R", "G", "B", "I" });
});
}
}
namespace Beatmap
{
public class EmissionColorChange_BM : AnimationBase_BM
{
public FlexibleFloat_BM colorR, colorG, colorB, colorI;
public EmissionColorChange_BM()
{
}
public EmissionColorChange_BM(string elementName, Guid elementGuid, List<string> tags, GameElement_BM parentElement,
FlexibleFloat_BM colorR, FlexibleFloat_BM colorG, FlexibleFloat_BM colorB, FlexibleFloat_BM colorI) :
base(elementName, elementGuid, tags, parentElement)
{
this.colorR = colorR;
this.colorG = colorG;
this.colorB = colorB;
this.colorI = colorI;
}
public override void ExecuteBM()
{
matchedElement = EmissionColorChange.GenerateElement(elementName, elementGuid, tags, false, GetElement(attachedElementGuid),
colorR.ConvertToGameType(), colorG.ConvertToGameType(), colorB.ConvertToGameType(), colorI.ConvertToGameType());
}
public override GameElement DuplicateBM(GameElement parent)
{
return EmissionColorChange.GenerateElement(elementName, Guid.NewGuid(), tags, false, parent,
colorR.ConvertToGameType(), colorG.ConvertToGameType(), colorB.ConvertToGameType(), colorI.ConvertToGameType());
}
}
}
}

View File

@@ -1,107 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using Lean.Pool;
using UnityEngine;
namespace Ichni.RhythmGame
{
public partial class TrackTotalTimeChange : AnimationBase
{
public FlexibleFloat totalTime;
public TrackTimeSubmoduleStatic targetTrackTimeSubmoduleStatic;
public static TrackTotalTimeChange GenerateElement(string elementName, Guid id,
List<string> tags, bool isFirstGenerated, Track animatedTrack, FlexibleFloat totalTime)
{
TrackTotalTimeChange trackTotalTimeChange = Instantiate(EditorManager.instance.basePrefabs.emptyObject)
.AddComponent<TrackTotalTimeChange>();
trackTotalTimeChange.Initialize(elementName, id, tags, isFirstGenerated, animatedTrack);
trackTotalTimeChange.animatedObject = animatedTrack;
trackTotalTimeChange.targetTrackTimeSubmoduleStatic = animatedTrack.trackTimeSubmodule as TrackTimeSubmoduleStatic;
trackTotalTimeChange.totalTime = totalTime;
trackTotalTimeChange.animationReturnType = FlexibleReturnType.Before;
//trackTotalTimeChange.timeDurationSubmodule.SetDuration(totalTime);
return trackTotalTimeChange;
}
public override void SetDefaultSubmodules()
{
timeDurationSubmodule = new TimeDurationSubmodule(this);
}
protected override void UpdateAnimation(float songTime)
{
totalTime.UpdateFlexibleFloat(songTime);
if (totalTime.returnType == FlexibleReturnType.MiddleExecuting)
{
targetTrackTimeSubmoduleStatic.trackTotalTime = totalTime.value;
}
}
public override void ApplyTimeOffset(float offset)
{
base.ApplyTimeOffset(offset);
totalTime.animations.ForEach(anim => anim.ApplyTimeOffset(offset));
}
}
public partial class TrackTotalTimeChange
{
public override void SaveBM()
{
matchedBM = new TrackTotalTimeChange_BM(elementName, elementGuid, tags, animatedObject.matchedBM as Track_BM, totalTime.ConvertToBM());
}
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
base.SetUpInspector();
var container = inspector.GenerateContainer("Displacement");
var subcontainer = container.GenerateSubcontainer(3);
var positionXButton = inspector.GenerateButton(this, subcontainer, "Total Time", () =>
{
inspector.GenerateCompositeParameterWindow(this, "Total Time", nameof(totalTime)).SetAsFlexibleFloat();
});
}
}
namespace Beatmap
{
public class TrackTotalTimeChange_BM : AnimationBase_BM
{
public FlexibleFloat_BM totalTime;
public TrackTotalTimeChange_BM()
{
}
public TrackTotalTimeChange_BM(string elementName, Guid elementGuid, List<string> tags,
GameElement_BM attachedElement, FlexibleFloat_BM totalTime) :
base(elementName, elementGuid, tags, attachedElement)
{
this.totalTime = totalTime;
}
public override void ExecuteBM()
{
matchedElement = TrackTotalTimeChange.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid) as Track, totalTime.ConvertToGameType());
}
public override GameElement DuplicateBM(GameElement parent)
{
return TrackTotalTimeChange.GenerateElement(elementName, Guid.NewGuid(), tags, false,
parent as Track, totalTime.ConvertToGameType());
}
}
}
}

View File

@@ -1,166 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using Lean.Pool;
using UnityEngine;
using UnityEngine.Serialization;
namespace Ichni.RhythmGame
{
/// <summary>
/// 将物体的z轴指向目标物体注意LookAt的启用期间物体的旋转将被锁定
/// </summary>
public partial class LookAt : AnimationBase
{
public GameCamera gameCamera;
public TransformSubmodule targetTransformSubmodule;
public GameElement lookAtObject;
public FlexibleBool enabling;
public static LookAt GenerateElement(string elementName, Guid id,
List<string> tags, bool isFirstGenerated, GameElement animatedObject,
GameElement lookAtTarget, FlexibleBool enabling)
{
LookAt look = Instantiate(EditorManager.instance.basePrefabs.emptyObject).AddComponent<LookAt>();
look.Initialize(elementName, id, tags, isFirstGenerated, animatedObject);
look.animatedObject = animatedObject;
look.lookAtObject = lookAtTarget;
look.enabling = enabling;
look.animationReturnType = FlexibleReturnType.Before;
look.targetTransformSubmodule = (animatedObject as IHaveTransformSubmodule).transformSubmodule;
look.targetTransformSubmodule.lookAt = look;
look.gameCamera = EditorManager.instance.cameraManager.gameCamera;
return look;
}
public override void SetDefaultSubmodules()
{
timeDurationSubmodule = new TimeDurationSubmodule(this);
}
void LateUpdate()
{
if (enabling.value) (animatedObject as IHaveTransformSubmodule)?.UpdateLookAt(this);
}
protected override void UpdateAnimation(float songTime)
{
if (lookAtObject == null) return;
enabling.UpdateFlexibleBool(songTime);
if (!targetTransformSubmodule.eulerAnglesOffsetLock || enabling.value)
{
targetTransformSubmodule.eulerAnglesOffsetLock = enabling.value;
}
if (enabling.value)
{
animationReturnType = FlexibleReturnType.MiddleExecuting;
targetTransformSubmodule.eulerAnglesDirtyMark = true;
}
else if (animationReturnType != FlexibleReturnType.MiddleInterval)
{
animationReturnType = FlexibleReturnType.MiddleInterval;
targetTransformSubmodule.eulerAnglesDirtyMark = true;
}
}
public override void SaveBM()
{
matchedBM = new LookAt_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM,
enabling.ConvertToBM(), lookAtObject.elementGuid);
}
public override void ApplyTimeOffset(float offset)
{
base.ApplyTimeOffset(offset);
enabling.animations.ForEach(anim => anim.ApplyTimeOffset(offset));
}
public void OnDestroy()
{
targetTransformSubmodule.eulerAnglesDirtyMark = true;
}
}
public partial class LookAt
{
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Enable Control");
var effectSettings = container.GenerateSubcontainer(2);
var connectedGameElementInputField = inspector.GenerateInputField(effectSettings, "Try Get Element");
var connectGameElementButton = inspector.GenerateButton(this, effectSettings, "Connect Game Element", () =>
{
GameElement targetElement = EditorManager.instance.beatmapContainer.gameElementList
.First(e => e.elementName == connectedGameElementInputField.GetValue<string>());
if (targetElement == null)
{
LogWindow.Log("Game Element not found.", Color.yellow);
}
lookAtObject = targetElement;
//targetTransformSubmodule = (targetElement as IHaveTransformSubmodule).transformSubmodule;
inspectorMain.SetInspector(this);
});
string ShowConnection() => lookAtObject == null ? "No Game Element Connected" : "Connected With: " + lookAtObject.elementName;
var connectHintText = inspector.GenerateHintText(this, effectSettings, ShowConnection);
var enablingButton = inspector.GenerateButton(this, effectSettings, "Enabling", () =>
{
inspector.GenerateCompositeParameterWindow(this, "Enabling", nameof(enabling)).SetAsFlexibleBool();
});
}
}
namespace Beatmap
{
public class LookAt_BM : GameElement_BM
{
public FlexibleBool_BM enabling;
public Guid lookAtObjectGuid;
public LookAt_BM()
{
}
public LookAt_BM(string elementName, Guid elementGuid, List<string> tags,
GameElement_BM attachedElement, FlexibleBool_BM enabling, Guid lookAtObjectGuid)
: base(elementName, elementGuid, tags, attachedElement)
{
this.enabling = enabling;
this.lookAtObjectGuid = lookAtObjectGuid;
}
public override void ExecuteBM()
{
matchedElement = LookAt.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid), GetElement(lookAtObjectGuid), enabling.ConvertToGameType());
matchedElement.matchedBM = this;
}
public override GameElement DuplicateBM(GameElement parent)
{
return LookAt.GenerateElement(elementName, Guid.NewGuid(), tags, false, parent,
GetElement(lookAtObjectGuid), enabling.ConvertToGameType());
}
public override void AfterExecute()
{
(matchedElement as LookAt).lookAtObject = GetElement(lookAtObjectGuid);
}
}
}
}

Binary file not shown.

View File

@@ -1,145 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using Ichni.RhythmGame.Beatmap;
namespace Ichni.RhythmGame
{
[System.Serializable]
public class AnimatedBool
{
public bool value; //bool值
public float time; //当前时间
public AnimatedBool(float time, bool value)
{
this.value = value;
this.time = time;
}
public void ApplyTimeOffset(float offset)
{
time += offset;
}
}
[System.Serializable]
public class FlexibleBool
{
public bool value;
public List<AnimatedBool> animations;
public FlexibleBool()
{
animations = new List<AnimatedBool>();
}
public FlexibleBool(List<AnimatedBool> anim)
{
this.animations = anim;
}
public void Add(AnimatedBool animatedBool)
{
animations.Add(animatedBool);
}
/// <summary>
/// 在动画脚本的Update中更新Bool Value
/// </summary>
/// <param name="歌曲时间"></param>
public FlexibleReturnType UpdateFlexibleBool(float nowTime)
{
AnimatedBool nowAnimatedBool = GetAnimatedBool(nowTime); //获取当前时间点对应的AnimatedBool
value = nowAnimatedBool.value; //更新value
return FlexibleReturnType.MiddleExecuting;
}
/// <summary>
/// 获取songTime对应的AnimatedBool的时间段
/// </summary>
/// <param name="歌曲时间"></param>
/// <returns>返回距离当前时间最近的前一个AnimatedBool</returns>
AnimatedBool GetAnimatedBool(float nowTime)
{
if (animations.Count == 0)
{
return new AnimatedBool(0, false);
}
if (nowTime < animations[0].time)
{
return animations[0];
}
if (nowTime > animations[animations.Count - 1].time)
{
return animations[animations.Count - 1];
}
for (int i = 0; i < animations.Count; i++)
{
if (nowTime < animations[i].time)
{
return animations[i - 1];
}
}
return new AnimatedBool(0, false);
}
/// <summary>
/// 转换为Beatmap存档类型
/// </summary>
/// <returns></returns>
public FlexibleBool_BM ConvertToBM()
{
FlexibleBool_BM flexibleBool_BM = new FlexibleBool_BM();
foreach (AnimatedBool animatedBool in animations)
{
flexibleBool_BM.animatedBoolList.Add(new AnimatedBool(animatedBool.time, animatedBool.value));
}
return flexibleBool_BM;
}
}
namespace Beatmap
{
public class FlexibleBool_BM
{
public List<AnimatedBool> animatedBoolList;
public FlexibleBool_BM()
{
this.animatedBoolList = new List<AnimatedBool>();
}
public FlexibleBool_BM(List<AnimatedBool> animatedBoolList)
{
this.animatedBoolList = animatedBoolList;
}
public FlexibleBool ConvertToGameType()
{
FlexibleBool flexibleBool;
if (this.animatedBoolList.Count == 0)
{
flexibleBool = new FlexibleBool();
}
else
{
List<AnimatedBool> animations = new List<AnimatedBool>();
foreach (AnimatedBool animatedBool in animatedBoolList)
{
animations.Add(new AnimatedBool(animatedBool.time, animatedBool.value));
}
flexibleBool = new FlexibleBool(animations);
}
return flexibleBool;
}
}
}
}

View File

@@ -1,310 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
namespace Ichni.RhythmGame
{
[System.Serializable]
public class AnimatedFloat : IComparable<AnimatedFloat>
{
public float startValue, endValue; //起止值
public float startTime, endTime; //起止时间
public AnimationCurveType animationCurveType; //动画曲线类型
public float differenceValue => endValue - startValue; //差值
public float totalTime => endTime - startTime; //总时间
public AnimatedFloat(float startTime, float endTime, float startValue, float endValue,
AnimationCurveType animationCurveType)
{
this.startValue = startValue;
this.endValue = endValue;
this.startTime = startTime;
this.endTime = endTime;
this.animationCurveType = animationCurveType;
}
public void ApplyTimeOffset(float offset)
{
startTime += offset;
endTime += offset;
}
/// <summary>
/// 按照起始时间排序
/// </summary>
public int CompareTo(AnimatedFloat obj)
{
return startTime.CompareTo(obj.startTime);
}
}
[System.Serializable]
public class FlexibleFloat
{
public float value;
public int currentAnimationIndex;
public List<AnimatedFloat> animations;
public bool isSwitchingReturnType;
public FlexibleReturnType lastReturnType;
public FlexibleReturnType returnType;
public event Action OnDataChanged;
public FlexibleFloat(bool withFirstAnimation = false)
{
animations = new List<AnimatedFloat>();
if (withFirstAnimation)
{
animations.Add(new AnimatedFloat(0f, 1f, 0f, 0f, AnimationCurveType.Linear));
}
}
public FlexibleFloat(List<AnimatedFloat> anim)
{
animations = anim;
}
public void Add(AnimatedFloat animatedFloat)
{
animations.Add(animatedFloat);
OnDataChanged?.Invoke();
}
public void Sort()
{
animations.Sort();
OnDataChanged?.Invoke();
}
/// <summary>
/// 在动画脚本的Update中更新value
/// </summary>
/// <param name="歌曲时间"></param>
public void UpdateFlexibleFloat(float nowTime)
{
if (isSwitchingReturnType) isSwitchingReturnType = false;
AnimatedFloat nowAnimatedFloat = GetAnimatedFloat(nowTime); //获取当前时间点对应的AnimatedFloat
if (nowAnimatedFloat != null) //如果能获取到,表明当前时间点存在动画
{
if (currentAnimationIndex == animations.Count - 1 && nowTime + Time.deltaTime >= nowAnimatedFloat.endTime)
{
value = nowAnimatedFloat.endValue;
returnType = FlexibleReturnType.After;
if (lastReturnType != returnType) isSwitchingReturnType = true;
lastReturnType = returnType;
return;
}
//获取songTime时间点时基于动画曲线的AnimatedFloat比例点->01
float nowPercent = AnimationCurveEvaluator.Evaluate(nowAnimatedFloat.animationCurveType,
(nowTime - nowAnimatedFloat.startTime) / nowAnimatedFloat.totalTime);
value = nowAnimatedFloat.startValue + nowPercent * nowAnimatedFloat.differenceValue; //计算value
returnType = FlexibleReturnType.MiddleExecuting;
if (lastReturnType != returnType) isSwitchingReturnType = true;
lastReturnType = returnType;
return;
}
if (animations.Count > 0) //如果当前时间点没有动画
{
float finalStartTime = animations[0].startTime;
float finalEndTime = animations[animations.Count - 1].endTime;
if (nowTime < finalStartTime) //如果当前时间小于第一个动画的开始时间
{
nowAnimatedFloat = animations[0];
//nowPercent = 0;
if (nowAnimatedFloat != null)
{
value = nowAnimatedFloat.startValue;
}
returnType = FlexibleReturnType.Before;
if (lastReturnType != returnType) isSwitchingReturnType = true;
lastReturnType = returnType;
return;
}
if (nowTime > finalEndTime) //如果当前时间大于最后一个动画的结束时间
{
nowAnimatedFloat = animations[animations.Count - 1];
//nowPercent = 1;
if (nowAnimatedFloat != null)
{
value = nowAnimatedFloat.endValue;
}
returnType = FlexibleReturnType.After;
if (lastReturnType != returnType) isSwitchingReturnType = true;
lastReturnType = returnType;
return;
}
SetLateAnimatedFloat(nowTime); //如果当前时间点在动画之间设置currentAnimationIndex
if (currentAnimationIndex >= 0) //如果当前时间点在动画之间
{
value = animations[currentAnimationIndex].endValue;
}
returnType = FlexibleReturnType.MiddleInterval;
if (lastReturnType != returnType) isSwitchingReturnType = true;
lastReturnType = returnType;
return;
}
//如果没有动画
value = 0;
returnType = FlexibleReturnType.None;
return;
}
/// <summary>
/// 获取songTime对应的AnimatedFloat的时间段
/// </summary>
/// <param name="歌曲时间"></param>
/// <returns></returns>
AnimatedFloat GetAnimatedFloat(float nowTime)
{
for (int i = 0; i < animations.Count; i++)
{
if (nowTime >= animations[i].startTime && nowTime < animations[i].endTime)
{
currentAnimationIndex = i;
return animations[i];
}
}
return null;
}
void SetLateAnimatedFloat(float nowTime)
{
for (int i = 0; i < animations.Count - 1; i++)
{
if (nowTime >= animations[i].startTime && nowTime < animations[i + 1].startTime)
{
currentAnimationIndex = i;
return;
}
}
currentAnimationIndex = 0;
return;
}
public float GetValue(float songtime)
{
UpdateFlexibleFloat(songtime);
float a = value;
return a;
}
public (FlexibleReturnType, bool) getReturnType(float Songtime)
{
UpdateFlexibleFloat(Songtime);
return (returnType, isSwitchingReturnType);
}
public (FlexibleReturnType, bool, float) GetReturnTypeAndValue(float songtime)
{
UpdateFlexibleFloat(songtime);
return (returnType, isSwitchingReturnType, value);
}
/// <summary>
/// 转换为Beatmap存档类型
/// </summary>
public FlexibleFloat_BM ConvertToBM()
{
FlexibleFloat_BM flexibleFloat_BM = new FlexibleFloat_BM();
foreach (AnimatedFloat animatedFloat in animations)
{
flexibleFloat_BM.animatedFloatList.Add(new AnimatedFloat(animatedFloat.startTime, animatedFloat.endTime,
animatedFloat.startValue, animatedFloat.endValue, animatedFloat.animationCurveType));
}
return flexibleFloat_BM;
}
public void ApplyTimeOffset(float OffsetTime)
{
animations.ForEach(i =>
{
i.ApplyTimeOffset(OffsetTime);
});
}
}
namespace Beatmap
{
[System.Serializable]
public class FlexibleFloat_BM
{
public List<AnimatedFloat> animatedFloatList;
public FlexibleFloat_BM()
{
this.animatedFloatList = new List<AnimatedFloat>();
}
public FlexibleFloat_BM(List<AnimatedFloat> animatedFloatList)
{
this.animatedFloatList = animatedFloatList;
}
public FlexibleFloat ConvertToGameType()
{
FlexibleFloat flexibleFloat;
if (animatedFloatList.Count == 0)
{
flexibleFloat = new FlexibleFloat();
}
else
{
List<AnimatedFloat> animatedFloatList = new List<AnimatedFloat>();
foreach (AnimatedFloat animatedFloat in this.animatedFloatList)
{
animatedFloatList.Add(new AnimatedFloat(
animatedFloat.startTime, animatedFloat.endTime,
animatedFloat.startValue, animatedFloat.endValue,
animatedFloat.animationCurveType));
}
flexibleFloat = new FlexibleFloat(animatedFloatList);
}
return flexibleFloat;
}
public FlexibleFloat_BM DeepCopyBM()
{
FlexibleFloat_BM copy = new FlexibleFloat_BM();
foreach (AnimatedFloat animatedFloat in animatedFloatList)
{
copy.animatedFloatList.Add(new AnimatedFloat(
animatedFloat.startTime, animatedFloat.endTime,
animatedFloat.startValue, animatedFloat.endValue,
animatedFloat.animationCurveType));
}
return copy;
}
public void ApplyTimeOffset(float OffsetTime)
{
animatedFloatList.ForEach(i =>
{
i.ApplyTimeOffset(OffsetTime);
});
}
}
}
}

View File

@@ -1,149 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
namespace Ichni.RhythmGame
{
[System.Serializable]
public class AnimatedInt
{
public int value; //值
public float time;
public AnimatedInt()
{
}
public AnimatedInt(float time, int value)
{
this.value = value;
this.time = time;
}
public void ApplyTimeOffset(float offset)
{
time += offset;
}
}
[System.Serializable]
public class FlexibleInt
{
public int value;
public List<AnimatedInt> animations;
public FlexibleInt()
{
animations = new List<AnimatedInt>();
}
public FlexibleInt(List<AnimatedInt> anim)
{
this.animations = anim;
}
public void Add(AnimatedInt animatedInt)
{
animations.Add(animatedInt);
}
/// <summary>
/// 在动画脚本的Update中更新Int Value
/// </summary>
/// <param name="歌曲时间"></param>
public FlexibleReturnType UpdateFlexibleInt(float nowTime)
{
AnimatedInt nowAnimatedInt = GetAnimatedInt(nowTime); //获取当前时间点对应的AnimatedInt
value = nowAnimatedInt.value; //更新value
return FlexibleReturnType.MiddleExecuting;
}
/// <summary>
/// 获取songTime对应的AnimatedInt的时间段
/// </summary>
/// <param name="歌曲时间"></param>
/// <returns>返回距离当前时间最近的前一个AnimatedInt</returns>
AnimatedInt GetAnimatedInt(float nowTime)
{
if (nowTime < animations[0].time)
{
return animations[0];
}
if (nowTime > animations[animations.Count - 1].time)
{
return animations[animations.Count - 1];
}
for (int i = 0; i < animations.Count; i++)
{
if (nowTime < animations[i].time)
{
return animations[i - 1];
}
}
return new AnimatedInt(0, 0);
}
/// <summary>
/// 转换为Beatmap存档类型
/// </summary>
/// <returns></returns>
public FlexibleInt_BM ConvertToBM()
{
FlexibleInt_BM flexibleInt_BM = new FlexibleInt_BM();
foreach (AnimatedInt animatedInt in animations)
{
flexibleInt_BM.animatedIntList.Add(new AnimatedInt(animatedInt.time, animatedInt.value));
}
return flexibleInt_BM;
}
}
namespace Beatmap
{
[System.Serializable]
public class FlexibleInt_BM
{
public List<AnimatedInt> animatedIntList;
public FlexibleInt_BM()
{
this.animatedIntList = new List<AnimatedInt>();
}
public FlexibleInt_BM(List<AnimatedInt> animatedIntList)
{
this.animatedIntList = animatedIntList;
}
public FlexibleInt ConvertToGameType()
{
FlexibleInt flexibleInt;
if (animatedIntList.Count == 0)
{
flexibleInt = new FlexibleInt();
}
else
{
List<AnimatedInt> animations = new List<AnimatedInt>();
foreach (AnimatedInt animatedInt in animatedIntList)
{
animations.Add(new AnimatedInt(animatedInt.time, animatedInt.value));
}
flexibleInt = new FlexibleInt(animations);
}
return flexibleInt;
}
}
}
}

View File

@@ -1,230 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using UniRx;
using UnityEngine;
namespace Ichni.RhythmGame
{
/// <summary>
/// 含有颜色属性的次级模块,包括基础颜色(透明度)、发光颜色和发光强度
/// </summary>
public partial class ColorSubmodule : SubmoduleBase
{
public Color originalBaseColor;
public bool emissionEnabled;
public Color originalEmissionColor;
public float originalEmissionIntensity;
public Color currentBaseColor;
public Color currentEmissionColor;
public float currentEmissionIntensity;
public bool baseColorDirtyMark;
public bool emissionColorDirtyMark;
public Color GetCurrentEmissionColor()
{
float intensity = Mathf.Pow(2, currentEmissionIntensity);
Color emissionColor = currentEmissionColor * intensity;
emissionColor.a = 1;
return emissionColor;
}
public ColorSubmodule(GameElement attachedGameElement) : base(attachedGameElement)
{
this.originalBaseColor = Color.white;
this.emissionEnabled = false;
this.originalEmissionColor = Color.black;
this.originalEmissionIntensity = 0;
this.currentBaseColor = Color.white;
this.currentEmissionColor = Color.black;
this.currentEmissionIntensity = 0;
this.baseColorDirtyMark = false;
this.emissionColorDirtyMark = false;
if (!HaveSameSubmodule)
{
(attachedGameElement as IHaveColorSubmodule).colorSubmodule = this;
(attachedGameElement as IHaveColorSubmodule).SetColorObserver();
}
}
public ColorSubmodule(GameElement attachedGameElement, Color originalBaseColor) : base(attachedGameElement)
{
this.originalBaseColor = originalBaseColor;
this.emissionEnabled = false;
this.originalEmissionColor = Color.black;
this.originalEmissionIntensity = 0;
this.currentBaseColor = originalBaseColor;
this.currentEmissionColor = Color.black;
this.currentEmissionIntensity = 0;
this.baseColorDirtyMark = false;
this.emissionColorDirtyMark = false;
if (!HaveSameSubmodule)
{
(attachedGameElement as IHaveColorSubmodule).colorSubmodule = this;
(attachedGameElement as IHaveColorSubmodule).SetColorObserver();
}
}
public ColorSubmodule(GameElement attachedGameElement, Color originalBaseColor, bool emissionEnabled,
Color originalEmissionColor, float originalEmissionIntensity) : base(attachedGameElement)
{
this.originalBaseColor = originalBaseColor;
this.emissionEnabled = emissionEnabled;
this.originalEmissionColor = originalEmissionColor;
this.originalEmissionIntensity = originalEmissionIntensity;
this.currentBaseColor = originalBaseColor;
this.currentEmissionColor = originalEmissionColor;
this.currentEmissionIntensity = originalEmissionIntensity;
this.baseColorDirtyMark = false;
this.emissionColorDirtyMark = false;
if (!HaveSameSubmodule)
{
(attachedGameElement as IHaveColorSubmodule).colorSubmodule = this;
(attachedGameElement as IHaveColorSubmodule).SetColorObserver();
}
}
public override void SaveBM()
{
matchedBM = new ColorSubmodule_BM(attachedGameElement);
}
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Color");
var subcontainer = container.GenerateSubcontainer(1, 300f);
if ((attachedGameElement as IHaveColorSubmodule).haveBaseColor)
{
var baseColor = inspector.GenerateBaseColorPicker(this, subcontainer, "Base Color", nameof(originalBaseColor));
baseColor.AddListenerFunction(Refresh);
// // 新增HSV轮盘
var hsvDrawer = inspector.GenerateHsvDrawer(this, subcontainer, "HSV", nameof(originalBaseColor));
hsvDrawer.AddListenerFunction(Refresh);
baseColor.hsvDrawer = hsvDrawer;
hsvDrawer.baseColorPicker = baseColor;
if (attachedGameElement.childElementList.Exists(x => x is BaseColorChange))
{
baseColor.title.text += " (Occupied by Animation)";
baseColor.canvasGroup.interactable = false;
hsvDrawer.title.text += " (Occupied by Animation)";
hsvDrawer.gameObject.SetActive(false); // 隐藏HSV轮盘
}
}
if ((attachedGameElement as IHaveColorSubmodule).haveEmissionColor)
{
var emissionColor = inspector.GenerateEmissionColorPicker(this, subcontainer, "Emission Color",
nameof(emissionEnabled), nameof(originalEmissionColor), nameof(originalEmissionIntensity));
emissionColor.AddListenerFunction(Refresh);
if (attachedGameElement.childElementList.Exists(x => x is EmissionColorChange))
{
emissionColor.title.text += " (Occupied by Animation)";
emissionColor.canvasGroup.interactable = false;
}
}
}
public override void Refresh()
{
currentBaseColor = originalBaseColor;
currentEmissionColor = originalEmissionColor;
currentEmissionIntensity = originalEmissionIntensity;
baseColorDirtyMark = true;
emissionColorDirtyMark = true;
}
}
public interface IHaveColorSubmodule
{
public ColorSubmodule colorSubmodule { get; set; }
public virtual bool haveBaseColor => true;
public virtual bool haveEmissionColor => false;
public void SetColorObserver()
{
GameElement attachedGameElement = colorSubmodule.attachedGameElement;
Observable.EveryUpdate().Subscribe(_ =>
{
if (colorSubmodule == null)
{
return;
}
bool willRefresh = false;
if (colorSubmodule.baseColorDirtyMark)
{
//在动画物体中改变currentColor
colorSubmodule.baseColorDirtyMark = false;
willRefresh = true;
}
if (colorSubmodule.emissionColorDirtyMark)
{
//在动画物体中改变currentColor
colorSubmodule.emissionColorDirtyMark = false;
willRefresh = true;
}
if (willRefresh)
{
attachedGameElement.Refresh();
}
}).AddTo(attachedGameElement);
}
}
namespace Beatmap
{
public class ColorSubmodule_BM : Submodule_BM
{
public Color originalBaseColor;
public bool emissionEnabled;
public Color originalEmissionColor;
public float originalEmissionIntensity;
public ColorSubmodule_BM()
{
}
public ColorSubmodule_BM(GameElement attachedElement) : base(attachedElement)
{
ColorSubmodule colorSubmodule = (attachedElement as IHaveColorSubmodule).colorSubmodule;
this.originalBaseColor = colorSubmodule.originalBaseColor;
this.emissionEnabled = colorSubmodule.emissionEnabled;
this.originalEmissionColor = colorSubmodule.originalEmissionColor;
this.originalEmissionIntensity = colorSubmodule.originalEmissionIntensity;
}
public override void ExecuteBM()
{
attachedElement = GameElement_BM.GetElement(attachedElementGuid);
(attachedElement as IHaveColorSubmodule).colorSubmodule = new ColorSubmodule(attachedElement,
originalBaseColor, emissionEnabled, originalEmissionColor, originalEmissionIntensity);
}
public override void DuplicateBM(GameElement attached)
{
(attached as IHaveColorSubmodule).colorSubmodule = new ColorSubmodule(attached,
originalBaseColor, emissionEnabled, originalEmissionColor, originalEmissionIntensity);
}
}
}
}

View File

@@ -1,60 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
namespace Ichni.RhythmGame
{
public partial class NoteJudgeTriggerSubmodule : SubmoduleBase
{
public List<NoteBase> connectedNotes;
public NoteJudgeTriggerSubmodule(GameElement attachedGameElement) : base(attachedGameElement)
{
connectedNotes = new List<NoteBase>();
if (!HaveSameSubmodule)
{
(attachedGameElement as IHaveNoteJudgeTriggerSubmodule).noteJudgeTriggerSubmodule = this;
}
}
public override void SaveBM()
{
matchedBM = new NoteJudgeTriggerSubmodule_BM(attachedGameElement);
}
}
public interface IHaveNoteJudgeTriggerSubmodule
{
public NoteJudgeTriggerSubmodule noteJudgeTriggerSubmodule { get; set; }
}
namespace Beatmap
{
public class NoteJudgeTriggerSubmodule_BM : Submodule_BM
{
public NoteJudgeTriggerSubmodule_BM()
{
}
public NoteJudgeTriggerSubmodule_BM(GameElement attachedElement) : base(attachedElement)
{
}
public override void ExecuteBM()
{
attachedElement = GameElement_BM.GetElement(attachedElementGuid);
(attachedElement as IHaveNoteJudgeTriggerSubmodule).noteJudgeTriggerSubmodule = new NoteJudgeTriggerSubmodule(attachedElement);
}
public override void DuplicateBM(GameElement attached)
{
(attached as IHaveNoteJudgeTriggerSubmodule).noteJudgeTriggerSubmodule = new NoteJudgeTriggerSubmodule(attached);
}
}
}
}

View File

@@ -1,187 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using UniRx;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Events;
namespace Ichni.RhythmGame
{
public partial class TimeDurationSubmodule : SubmoduleBase
{
public bool isOverridingDuration; //是否手动设置了时间区间,开启时,子物体的时间区间将被忽略,且在自动计算区间时跳过此模块
public float startTime, endTime; //起止时间
public IDisposable timeObserver;
public TimeDurationSubmodule(GameElement attachedGameElement) : base(attachedGameElement)
{
isOverridingDuration = false;
startTime = -32767; //TODO: 换为-delay
endTime = 32767; //TODO: 换为songLength
if (!HaveSameSubmodule)
{
(attachedGameElement as IHaveTimeDurationSubmodule).timeDurationSubmodule = this;
}
}
public TimeDurationSubmodule(GameElement attachedGameElement, bool isOverridingDuration, float startTime, float endTime) :
base(attachedGameElement)
{
this.isOverridingDuration = isOverridingDuration;
this.startTime = startTime;
this.endTime = endTime;
if (!HaveSameSubmodule)
{
(attachedGameElement as IHaveTimeDurationSubmodule).timeDurationSubmodule = this;
}
}
public bool CheckTimeInDuration(float time, float offset = 0.1f)
{
return time >= startTime - offset && time <= endTime + offset;
}
public void SetDuration(float startTime, float endTime)
{
this.startTime = startTime;
this.endTime = endTime;
this.isOverridingDuration = true;
}
public void SetDuration(params FlexibleFloat[] flexibleFloats)
{
List<float> startTimes = new List<float>();
List<float> endTimes = new List<float>();
foreach (FlexibleFloat flexibleFloat in flexibleFloats)
{
flexibleFloat.Sort();
if (flexibleFloat.animations.Count > 0)
{
startTimes.Add(flexibleFloat.animations[0].startTime);
endTimes.Add(flexibleFloat.animations[^1].endTime);
}
else continue;
}
if (startTimes.Count == 0 || endTimes.Count == 0)
{
return;
}
startTime = startTimes.Min();
endTime = endTimes.Max();
}
public void SetDurationFromChildren(List<TimeDurationSubmodule> children)
{
List<float2> durations = new List<float2>();
if (children.Count == 0)
{
return;
}
foreach (var child in children)
{
durations.Add(new float2(child.startTime, child.endTime));
}
startTime = durations.Min(duration => duration.x);
endTime = durations.Max(duration => duration.y);
}
}
public partial class TimeDurationSubmodule
{
public void SetUpObserver(UnityAction enableAction, UnityAction disableAction = null)
{
timeObserver?.Dispose();
timeObserver = Observable.EveryUpdate().Subscribe(_ =>
{
float songTime = EditorManager.instance.songInformation.songTime;
if (CheckTimeInDuration(songTime, 0f) && !attachedGameElement.gameObject.activeSelf)
{
attachedGameElement.gameObject.SetActive(true);
enableAction?.Invoke();
Debug.Log($"TimeDurationSubmodule: {attachedGameElement.elementName} is active at time {songTime}, duration: [{startTime}, {endTime}]");
}
else if (!CheckTimeInDuration(songTime, 0f) && attachedGameElement.gameObject.activeSelf)
{
attachedGameElement.gameObject.SetActive(false);
disableAction?.Invoke();
}
});
}
}
public partial class TimeDurationSubmodule
{
public override void SaveBM()
{
matchedBM = new TimeDurationSubmodule_BM(attachedGameElement);
}
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Time Duration");
var subcontainer = container.GenerateSubcontainer(3);
var overrideToggle = inspector.GenerateToggle(this, subcontainer, "Override Duration", nameof(isOverridingDuration));
var startTimeInputField = inspector.GenerateInputField(this, subcontainer, "Start Time", nameof(startTime));
var endTimeInputField = inspector.GenerateInputField(this, subcontainer, "End Time", nameof(endTime));
void SetInputFieldInteractable(bool interactable)
{
startTimeInputField.inputField.interactable = interactable;
endTimeInputField.inputField.interactable = interactable;
}
SetInputFieldInteractable(isOverridingDuration);
overrideToggle.AddListenerFunction(() => SetInputFieldInteractable(isOverridingDuration));
}
}
public interface IHaveTimeDurationSubmodule
{
public TimeDurationSubmodule timeDurationSubmodule { get; set; }
}
namespace Beatmap
{
public class TimeDurationSubmodule_BM : Submodule_BM
{
public bool isOverridingDuration;
public float startTime, endTime;
public TimeDurationSubmodule_BM()
{
}
public TimeDurationSubmodule_BM(GameElement attachedElement) : base(attachedElement)
{
TimeDurationSubmodule timeDurationSubmodule = (attachedElement as IHaveTimeDurationSubmodule).timeDurationSubmodule;
isOverridingDuration = timeDurationSubmodule.isOverridingDuration;
startTime = timeDurationSubmodule.startTime;
endTime = timeDurationSubmodule.endTime;
}
public override void ExecuteBM()
{
attachedElement = GameElement_BM.GetElement(attachedElementGuid);
(attachedElement as IHaveTimeDurationSubmodule).timeDurationSubmodule = new TimeDurationSubmodule(attachedElement, isOverridingDuration, startTime, endTime);
}
public override void DuplicateBM(GameElement attached)
{
(attached as IHaveTimeDurationSubmodule).timeDurationSubmodule = new TimeDurationSubmodule(attached, isOverridingDuration, startTime, endTime);
}
}
}
}

View File

@@ -1,250 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using UniRx;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Events;
namespace Ichni.RhythmGame
{
public class TransformSubmodule : SubmoduleBase
{
public Vector3 originalPosition;
public Vector3 originalEulerAngles;
public Vector3 originalScale;
public Vector3 positionOffset;
public Vector3 eulerAnglesOffset;
public Vector3 scaleOffset;
public Vector3 currentPosition;
public Vector3 currentEulerAngles;
public Vector3 currentScale;
public bool positionDirtyMark;
public bool eulerAnglesDirtyMark;
public bool scaleDirtyMark;
public LookAt lookAt;
public bool eulerAnglesOffsetLock;
public TransformSubmodule(GameElement attachedGameElement) : base(attachedGameElement)
{
this.originalPosition = Vector3.zero;
this.originalEulerAngles = Vector3.zero;
this.originalScale = Vector3.one;
positionOffset = Vector3.zero;
eulerAnglesOffset = Vector3.zero;
scaleOffset = Vector3.zero;
currentPosition = Vector3.zero;
currentEulerAngles = Vector3.zero;
currentScale = Vector3.one;
positionDirtyMark = true;
eulerAnglesDirtyMark = true;
scaleDirtyMark = true;
eulerAnglesOffsetLock = false;
if (!HaveSameSubmodule)
{
(attachedGameElement as IHaveTransformSubmodule).transformSubmodule = this;
(attachedGameElement as IHaveTransformSubmodule).SetTransformObserver();
}
}
public TransformSubmodule(GameElement attachedGameElement,
Vector3 originalPosition, Vector3 originalEulerAngles, Vector3 originalScale) : base(attachedGameElement)
{
this.originalPosition = originalPosition;
this.originalEulerAngles = originalEulerAngles;
this.originalScale = originalScale;
positionOffset = Vector3.zero;
eulerAnglesOffset = Vector3.zero;
scaleOffset = Vector3.zero;
currentPosition = originalPosition;
currentEulerAngles = originalEulerAngles;
currentScale = originalScale;
positionDirtyMark = true;
eulerAnglesDirtyMark = true;
scaleDirtyMark = true;
eulerAnglesOffsetLock = false;
attachedGameElement.transform.localScale = currentScale;
attachedGameElement.transform.localEulerAngles = currentEulerAngles;
attachedGameElement.transform.localPosition = currentPosition;
if (!HaveSameSubmodule)
{
(attachedGameElement as IHaveTransformSubmodule).transformSubmodule = this;
(attachedGameElement as IHaveTransformSubmodule).SetTransformObserver();
}
}
public override void SaveBM()
{
matchedBM = new TransformSubmodule_BM(attachedGameElement);
}
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Transform");
var subcontainer = container.GenerateSubcontainer(1);
var originalPosInputField =
inspector.GenerateVector3InputField(this, subcontainer, "Start Position", nameof(originalPosition), true);
var originalRotInputField =
inspector.GenerateVector3InputField(this, subcontainer, "Start Rotation", nameof(originalEulerAngles), true);
var originalScaleInputField =
inspector.GenerateVector3InputField(this, subcontainer, "Start Scale", nameof(originalScale), true);
var currentPosText =
inspector.GenerateParameterText(this, subcontainer, "Current Position", nameof(currentPosition), true);
var currentRotText =
inspector.GenerateParameterText(this, subcontainer, "Current Rotation", nameof(currentEulerAngles), true);
if (attachedGameElement is PathNode or Trail) // 如果是PathNode显示法线方向
{
var currentNormalText =
inspector.GenerateHintText(this, subcontainer, () => "Normal: " + attachedGameElement.transform.forward);
}
var currentScaleText =
inspector.GenerateParameterText(this, subcontainer, "Current Scale", nameof(currentScale), true);
originalPosInputField.AddListenerFunction(Refresh);
originalRotInputField.AddListenerFunction(Refresh);
originalScaleInputField.AddListenerFunction(Refresh);
}
public override void Refresh()
{
positionDirtyMark = true;
eulerAnglesDirtyMark = true;
scaleDirtyMark = true;
}
}
public interface IHaveTransformSubmodule
{
TransformSubmodule transformSubmodule { get; set; }
/// <summary>
/// 设置物体Transform的监听顺序为Scale -> EulerAngles -> Position
/// 如果有一些特殊的物体例如CameraElementFolder需要自定义监听可以重写这个方法
/// </summary>
public void SetTransformObserver()
{
GameElement attachedGameElement = transformSubmodule.attachedGameElement;
Observable.EveryUpdate().Subscribe(_ =>
{
if (transformSubmodule == null)
{
return;
}
bool willRefresh = false;
if (transformSubmodule.scaleDirtyMark)
{
transformSubmodule.currentScale = transformSubmodule.originalScale + transformSubmodule.scaleOffset;
attachedGameElement.transform.localScale = transformSubmodule.currentScale;
transformSubmodule.scaleDirtyMark = false;
willRefresh = true;
transformSubmodule.scaleOffset = Vector3.zero;
}
if (!transformSubmodule.eulerAnglesOffsetLock && transformSubmodule.eulerAnglesDirtyMark)
{
transformSubmodule.currentEulerAngles = transformSubmodule.originalEulerAngles + transformSubmodule.eulerAnglesOffset;
attachedGameElement.transform.localEulerAngles = transformSubmodule.currentEulerAngles;
transformSubmodule.eulerAnglesDirtyMark = false;
willRefresh = true;
transformSubmodule.eulerAnglesOffset = Vector3.zero;
}
if (transformSubmodule.positionDirtyMark)
{
transformSubmodule.currentPosition = transformSubmodule.originalPosition + transformSubmodule.positionOffset;
attachedGameElement.transform.localPosition = transformSubmodule.currentPosition;
transformSubmodule.positionDirtyMark = false;
willRefresh = true;
transformSubmodule.positionOffset = Vector3.zero;
}
if (willRefresh)
{
attachedGameElement.Refresh();
}
}).AddTo(attachedGameElement);
}
public void UpdateLookAt(LookAt lookAt) // 处理LookAt
{
Transform target = lookAt.lookAtObject.transform;
Transform self = transformSubmodule.attachedGameElement.transform;
if (transformSubmodule.eulerAnglesOffsetLock && transformSubmodule.eulerAnglesDirtyMark)
{
Vector3 lookingDirection = (target.position - self.position).normalized;
Vector3 eulerAnglesOffset = Quaternion.LookRotation(lookingDirection).eulerAngles;
transformSubmodule.eulerAnglesOffset += eulerAnglesOffset;
transformSubmodule.currentEulerAngles = transformSubmodule.originalEulerAngles + transformSubmodule.eulerAnglesOffset;
self.localEulerAngles = transformSubmodule.currentEulerAngles;
transformSubmodule.eulerAnglesDirtyMark = false;
transformSubmodule.eulerAnglesOffsetLock = false;
transformSubmodule.eulerAnglesOffset = Vector3.zero;
}
}
}
namespace Beatmap
{
public class TransformSubmodule_BM : Submodule_BM
{
public Vector3 originalPosition;
public Vector3 originalEulerAngles;
public Vector3 originalScale;
public TransformSubmodule_BM()
{
}
public TransformSubmodule_BM(GameElement attachedElement) : base(attachedElement)
{
TransformSubmodule transformSubmodule = (attachedElement as IHaveTransformSubmodule).transformSubmodule;
this.originalPosition = transformSubmodule.originalPosition;
this.originalEulerAngles = transformSubmodule.originalEulerAngles;
this.originalScale = transformSubmodule.originalScale;
}
public override void ExecuteBM()
{
attachedElement = GameElement_BM.GetElement(attachedElementGuid);
(attachedElement as IHaveTransformSubmodule).transformSubmodule = new TransformSubmodule(attachedElement, originalPosition, originalEulerAngles, originalScale);
}
public override void DuplicateBM(GameElement attached)
{
(attached as IHaveTransformSubmodule).transformSubmodule = new TransformSubmodule(attached, originalPosition, originalEulerAngles, originalScale);
}
}
}
}

View File

@@ -1,56 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using Lean.Pool;
using UnityEngine;
using UnityEngine.Events;
namespace Ichni
{
public class PooledObject : MonoBehaviour, IPoolable
{
public UnityAction onSpawn;
public UnityAction onDespawn;
public void OnSpawn()
{
onSpawn?.Invoke();
}
public void OnDespawn()
{
onDespawn?.Invoke();
}
public void SetOnSpawn(UnityAction action, bool isOverride = false, bool isAdditive = false)
{
if (isOverride)
{
onSpawn = action;
}
else if (isAdditive)
{
onSpawn += action;
}
else
{
onSpawn ??= action;
}
}
public void SetOnDespawn(UnityAction action, bool isOverride = false, bool isAdditive = false)
{
if (isOverride)
{
onDespawn = action;
}
else if (isAdditive)
{
onDespawn += action;
}
else
{
onDespawn ??= action;
}
}
}
}

View File

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

View File

@@ -1,203 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Beatmap;
using Ichni.RhythmGame.Beatmap;
using UniRx;
using UnityEngine;
using UnityEngine.Events;
namespace Ichni.RhythmGame
{
public class BeatmapContainer : IBaseElement, IBeChangeInExport
{
public List<GameElement> gameElementList;
[NonSerialized]
public List<UnityAction> lowPriorityActions;
public BaseElement_BM matchedBM { get; set; }
public BaseElement_BM MatchingExportElement { get; set; }
public BeatmapContainer()
{
gameElementList = new List<GameElement>();
lowPriorityActions = new List<UnityAction>();
Observable.EveryUpdate().Subscribe(_ => ExecuteLowPriorityActions());
}
public void ExecuteLowPriorityActions()
{
if (lowPriorityActions.Count > 0)
{
lowPriorityActions.ForEach(low => low.Invoke());
lowPriorityActions.Clear();
}
}
public void SaveBM()
{
matchedBM = new BeatmapContainer_BM(gameElementList);
}
public void SetUpInspector()
{
throw new System.NotImplementedException();
}
public void Refresh()
{
throw new System.NotImplementedException();
}
public IEnumerator AfterLoadSet()
{
Trail.FreezeAllTrails(true);
foreach (var element in gameElementList)
{
element.gameObject.SetActive(false);
if (element is IHaveTransformSubmodule haveTransform)
{
TransformSubmodule transformSubmodule = haveTransform.transformSubmodule;
foreach (AnimationBase i in element.childElementList.OfType<AnimationBase>())
{
i.InvokeUpdate();
}
transformSubmodule.Refresh();
}
}
yield return null;
foreach (var element in gameElementList)
{
element.gameObject.SetActive(true);
}
}
public void SaveExportBM()
{
MatchingExportElement = new BeatmapContainer_BM(gameElementList, true);
if (((BeatmapContainer_BM)MatchingExportElement).elementList.Any(i => i is ICanNotInExport))
{
Debug.LogError("Export Error!");
}
}
}
namespace Beatmap
{
public partial class BeatmapContainer_BM : BaseElement_BM
{
public List<BaseElement_BM> elementList;
public BeatmapContainer_BM()
{
}
public BeatmapContainer_BM(List<GameElement> gameElementList, bool forExport = false)
{
elementList = new List<BaseElement_BM>();
gameElementList.ForEach(e =>
{
e.SaveBM();
e.submoduleList.RemoveAll(s => s == null);
e.submoduleList.ForEach(s => s.SaveBM());
if (forExport && e is IBeChangeInExport changeInExport)
{
changeInExport.SaveExportBM();
}
});
foreach (var gameElement in gameElementList)
{
if (gameElement.matchedBM != null)
{
if (forExport && gameElement is IBeChangeInExport changeInExport)
{
if (changeInExport.MatchingExportElement != null)
{
elementList.Add(changeInExport.MatchingExportElement);
List<BaseElement_BM> submodules = gameElement.submoduleList.ConvertAll(s => s.matchedBM);
submodules.RemoveAll(s => s == null);
submodules.ForEach(e => { e.attachedElementGuid = ((GameElement_BM)changeInExport.MatchingExportElement).elementGuid; });
elementList.AddRange(submodules);
}
}
else
{
elementList.Add(gameElement.matchedBM);
List<BaseElement_BM> submodules = gameElement.submoduleList.ConvertAll(s => s.matchedBM);
submodules.RemoveAll(s => s == null);
elementList.AddRange(submodules);
}
}
}
}
public override void ExecuteBM()
{
EditorManager.instance.beatmapContainer = new BeatmapContainer();
EditorManager.instance.beatmapContainer.matchedBM = this;
GameElement_BM.identifier.Clear();
elementList.ForEach(element =>
{
if (element == null)
{
Debug.LogError("Null element detected in elementList. Skipping execution.");
return;
}
if (LowPriorityGameElementTypes.Contains(element.GetType()))
{
return;
}
if (element is GameElement_BM gameElement)
{
GameElement_BM.identifier.Add(gameElement.elementGuid, gameElement);
}
element.ExecuteBM();
});
elementList.ForEach(element =>
{
if (element == null)
{
Debug.LogError("Null element detected in elementList during low-priority execution. Skipping execution.");
return;
}
if (LowPriorityGameElementTypes.Contains(element.GetType()))
{
element.ExecuteBM();
}
});
EditorManager.instance.beatmapContainer.ExecuteLowPriorityActions();
}
}
public partial class BeatmapContainer_BM : BaseElement_BM
{
public static readonly List<Type> LowPriorityGameElementTypes = new()
{
//typeof(NoteJudgeSubmodule_BM),
};
public static readonly List<Type> LowPriorityDataTypes = new()
{
typeof(EnableControlEffect_BM),
};
}
}
}

View File

@@ -1,57 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using Ichni.RhythmGame;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
namespace Ichni.RhythmGame
{
public class CommandScripts : IBaseElement
{
List<string> commandList;
public BaseElement_BM matchedBM { get; set; }
public CommandScripts(List<string> commandList)
{
this.commandList = commandList;
}
public void SaveBM()
{
matchedBM = new CommandScripts_BM(commandList);
}
public void SetUpInspector()
{
throw new System.NotImplementedException();
}
public void Refresh()
{
throw new System.NotImplementedException();
}
}
namespace Beatmap
{
public class CommandScripts_BM : BaseElement_BM
{
public List<string> commandList;
public CommandScripts_BM()
{
}
public CommandScripts_BM(List<string> commandList)
{
this.commandList = commandList;
}
public override void ExecuteBM()
{
EditorManager.instance.commandScripts = new CommandScripts(commandList);
}
}
}
}

Binary file not shown.

View File

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

View File

@@ -1,189 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Dreamteck.Splines;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using Lean.Pool;
using UniRx;
using UnityEngine;
using UnityEngine.Rendering.Universal;
using UnityEngine.Serialization;
namespace Ichni.RhythmGame
{
public partial class GameCamera : GameElement, IHaveTransformSubmodule, IHaveTimeDurationSubmodule
{
[FormerlySerializedAs("camera")]
public Camera gameCamera;
public Transform rotationPoint;
public Transform positionPoint;
public Transform cameraTransform;
public CameraViewType cameraViewType;
public float perspectiveAngle;
public float orthographicSize;
public TransformSubmodule transformSubmodule { get; set; }
public TimeDurationSubmodule timeDurationSubmodule { get; set; }
private static CameraManager cameraManager => EditorManager.instance.cameraManager;
public static GameCamera GenerateElement(string elementName, Guid id,
List<string> tags, bool isFirstGenerated, GameElement parentElement,
CameraViewType cameraViewType, float perspectiveAngle, float orthographicSize)
{
if (EditorManager.instance.cameraManager.haveGameCamera)
{
LogWindow.Log("Only one GameCamera can be created", Color.red);
return null;
}
GameCamera gameCamera =
Instantiate(EditorManager.instance.basePrefabs.gameCamera).GetComponent<GameCamera>();
gameCamera.Initialize(elementName, id, tags, isFirstGenerated, parentElement);
cameraManager.gameCamera = gameCamera;
gameCamera.gameCamera.GetComponent<UniversalAdditionalCameraData>().cameraStack.Add(cameraManager.backgroundCamera);
if (cameraManager.isSceneCameraActive) gameCamera.gameCamera.enabled = false;
gameCamera.parentElement = parentElement;
gameCamera.cameraViewType = cameraViewType;
gameCamera.gameCamera.orthographic = cameraViewType == CameraViewType.Orthographic;
gameCamera.perspectiveAngle = perspectiveAngle;
gameCamera.orthographicSize = orthographicSize;
gameCamera.cameraTransform = gameCamera.transform;
return gameCamera;
}
public override void SetDefaultSubmodules()
{
transformSubmodule = new TransformSubmodule(this);
}
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
base.SetUpInspector();
var container = inspector.GenerateContainer("Generate");
StandardInspectionElement.GenerateForTransform(this, container); //关于有Transform的元素
var generateAnimation = container.GenerateSubcontainer(3);
var fovAnimationButton = inspector.GenerateButton(this, generateAnimation, "Field of View",
() => CameraFieldOfView.GenerateElement("New Field of View", Guid.NewGuid(),
new List<string>(), true, this, new FlexibleFloat(new List<AnimatedFloat>
{
new AnimatedFloat(0f, 1f, 60f, 60f, AnimationCurveType.Linear)
})));
var extensionButton = inspector.GenerateButton(this, generateAnimation, "Extension",
() => GameCameraExtension.GenerateElement("New Extension", Guid.NewGuid(),
new List<string>(), true, this, 1000f));
}
public override void OnDelete()
{
if (cameraManager.gameCamera == this)
{
cameraManager.SwitchCamera();
}
}
}
public partial class GameCamera
{
public enum CameraViewType
{
Perspective = 0,
Orthographic = 1
}
}
public partial class GameCamera
{
public void SetTransformObserver()
{
Observable.EveryLateUpdate().Subscribe(_ =>
{
if (transformSubmodule == null)
{
return;
}
bool willRefresh = false;
if (!transformSubmodule.eulerAnglesOffsetLock && transformSubmodule.eulerAnglesDirtyMark)
{
transformSubmodule.currentEulerAngles = transformSubmodule.originalEulerAngles + transformSubmodule.eulerAnglesOffset;
transform.localEulerAngles = transformSubmodule.currentEulerAngles;
transformSubmodule.eulerAnglesDirtyMark = false;
willRefresh = true;
transformSubmodule.eulerAnglesOffset = Vector3.zero;
}
if (transformSubmodule.positionDirtyMark)
{
transformSubmodule.currentPosition = transformSubmodule.originalPosition + transformSubmodule.positionOffset;
transform.localPosition = transformSubmodule.currentPosition;
transformSubmodule.positionDirtyMark = false;
willRefresh = true;
transformSubmodule.positionOffset = Vector3.zero;
}
if (willRefresh)
{
Refresh();
}
}).AddTo(gameObject);
}
}
public partial class GameCamera
{
public override void SaveBM()
{
matchedBM = new GameCamera_BM(elementName, elementGuid, tags,
parentElement.matchedBM as GameElement_BM, cameraViewType, perspectiveAngle, orthographicSize);
}
}
namespace Beatmap
{
public class GameCamera_BM : GameElement_BM
{
public GameCamera.CameraViewType cameraViewType;
public float perspectiveAngle;
public float orthographicSize;
public GameCamera_BM()
{
}
public GameCamera_BM(string elementName, Guid elementGuid, List<string> tags,
GameElement_BM attachedElement, GameCamera.CameraViewType cameraViewType,
float perspectiveAngle, float orthographicSize)
: base(elementName, elementGuid, tags, attachedElement)
{
this.cameraViewType = cameraViewType;
this.perspectiveAngle = perspectiveAngle;
this.orthographicSize = orthographicSize;
}
public override void ExecuteBM()
{
matchedElement = GameCamera.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid), cameraViewType, perspectiveAngle, orthographicSize);
}
public override GameElement DuplicateBM(GameElement parent)
{
return GameCamera.GenerateElement(elementName, Guid.NewGuid(), tags, false,
parent, cameraViewType, perspectiveAngle, orthographicSize);
}
}
}
}

View File

@@ -1,87 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
using UnityEngine.Serialization;
namespace Ichni.RhythmGame
{
public partial class GameCameraExtension : GameElement
{
public GameCamera gameCamera;
public SceneCamera sceneCamera => EditorManager.instance.cameraManager.sceneCamera;
public float farClipRange = 1000f;
public static GameCameraExtension GenerateElement(string elementName, Guid id,
List<string> tags, bool isFirstGenerated, GameElement parentElement, float farClipRange)
{
GameCameraExtension gameCameraExtension = Instantiate(EditorManager.instance.basePrefabs.emptyObject)
.AddComponent<GameCameraExtension>();
gameCameraExtension.Initialize(elementName, id, tags, isFirstGenerated, parentElement);
gameCameraExtension.gameCamera = parentElement as GameCamera;
gameCameraExtension.farClipRange = farClipRange;
gameCameraExtension.ApplyExtension();
return gameCameraExtension;
}
public void ApplyExtension()
{
gameCamera.gameCamera.farClipPlane = farClipRange;
sceneCamera.sceneCamera.farClipPlane = farClipRange;
}
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
base.SetUpInspector();
var container = inspector.GenerateContainer("Settings");
var settingsSubcontainer = container.GenerateSubcontainer(3);
var farClipRangeButton = inspector.GenerateInputField(this, settingsSubcontainer, "Far Clip Range",
nameof(farClipRange)).AddListenerFunction(ApplyExtension);
}
}
public partial class GameCameraExtension
{
public override void SaveBM()
{
matchedBM = new GameCameraExtension_BM(elementName, elementGuid, tags,
parentElement.matchedBM as GameElement_BM, farClipRange);
}
}
namespace Beatmap
{
public class GameCameraExtension_BM : GameElement_BM
{
public float farClipRange;
public GameCameraExtension_BM()
{
}
public GameCameraExtension_BM(string elementName, Guid elementGuid, List<string> tags,
GameElement_BM attachedElement, float farClipRange)
: base(elementName, elementGuid, tags, attachedElement)
{
this.farClipRange = farClipRange;
}
public override void ExecuteBM()
{
matchedElement = GameCameraExtension.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid), farClipRange);
}
public override GameElement DuplicateBM(GameElement parent)
{
return GameCameraExtension.GenerateElement(elementName, Guid.NewGuid(), tags, false,
parent, farClipRange);
}
}
}
}

View File

@@ -1,378 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using Sirenix.OdinInspector;
using UnityEngine;
namespace Ichni.RhythmGame
{
public abstract partial class GameElement : SerializedMonoBehaviour, IBaseElement, IComparable<GameElement>
{
//物体名
public string elementName;
//标识 GUID
public Guid elementGuid;
//标签
public List<string> tags;
//父游戏物体
public GameElement parentElement;
//与游戏物体连接的Tab
public HierarchyTab connectedTab;
//子物体列表
public List<GameElement> childElementList = new List<GameElement>();
//次级模块
public List<SubmoduleBase> submoduleList = new List<SubmoduleBase>();
//存档类
public BaseElement_BM matchedBM { get; set; }
public virtual int HierarchyPriority => 0;
/// <summary>
/// 首次初始化
/// </summary>
/// <param name="name">物体名</param>
public virtual void Initialize(string name, Guid elementGuid, List<string> tags,
bool isFirstGenerated, GameElement parentElement)
{
this.elementName = name;
this.elementGuid = elementGuid;
this.tags = tags;
EditorManager.instance.beatmapContainer.gameElementList.Add(this);
submoduleList = new List<SubmoduleBase>();
if (isFirstGenerated)
{
SetDefaultSubmodules();
}
SetParent(parentElement);
if (parentElement == null || parentElement.connectedTab != null) EditorManager.instance.uiManager.hierarchy.GenerateTab(this, parentElement);
gameObject.name = elementName;
//GameManager.beatMapContainer.beatMapElementList.Add(this);
//serialNumber = totalSerialNumber++;
//SetTransformObserver();
}
/// <summary>
/// 设置次级模块
/// </summary>
public virtual void SetDefaultSubmodules()
{
}
public virtual void SetEditorSubmodules()
{
}
/// <summary>
/// 在所有物体生成完毕后,执行的初始化方法
/// </summary>
public virtual void AfterInitialize()
{
matchedBM?.AfterExecute();
}
/// <summary>
/// 设置父物体
/// </summary>
/// <param name="parentElement">父物体</param>
public void SetParent(GameElement parentElement)
{
if (parentElement != null)
{
parentElement.childElementList.Add(this);
this.parentElement = parentElement;
transform.SetParent(parentElement.transform);
}
}
public int CompareTo(GameElement other)
{
return HierarchyPriority.CompareTo(other.HierarchyPriority);
}
}
public abstract partial class GameElement //存档,删除,复制,粘贴
{
public virtual void Refresh()
{
if (connectedTab != null) connectedTab.tabButtonText.text = this.elementName;
gameObject.name = elementName;
}
/// <summary>
/// 用于生成存档
/// </summary>
public virtual void SaveBM()
{
throw new NotImplementedException();
}
/// <summary>
/// 当物体被删除时执行的方法
/// </summary>
public virtual void OnDelete()
{
}
/// <summary>
/// 删除物体,包括所有子物体
/// </summary>
public virtual void Delete()
{
if (childElementList is { Count: > 0 })
{
for (int i = 0; i < childElementList.Count; i++)
{
childElementList[i].Delete(); //删除子GameElement、
}
}
OnDelete();
//LogWindow.Log("Deleted element: " + elementName);
EditorManager.instance.beatmapContainer.gameElementList.Remove(this); //从保存列表中剔除
if (connectedTab != null)
{
Destroy(connectedTab.gameObject);
}
Destroy(gameObject); //销毁
}
}
public abstract partial class GameElement//Editor 专
{
public class EnableType : IBaseElement
{
public Type type;
public bool enable;
public BaseElement_BM matchedBM { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
};
public List<EnableType> enableTypes;
/// <summary>
/// 扫描childElementList中的类型并加入enableTypes去重兼容性好
/// </summary>
public void ScanAndAddEnableTypes()
{
// 初始化enableTypes列表
if (enableTypes == null)
enableTypes = new List<EnableType>();
// 记录已存在的类型,避免重复
HashSet<Type> existingTypes = new HashSet<Type>();
foreach (var et in enableTypes)
{
if (et != null && et.type != null)
existingTypes.Add(et.type);
}
// 遍历所有子元素类型若未添加则加入enableTypes
foreach (var child in childElementList)
{
var childType = child.GetType();
if (!existingTypes.Contains(childType))
{
enableTypes.Add(new EnableType
{
type = childType,
enable = true
});
existingTypes.Add(childType);
}
}
}
public virtual void SetUpInspector() //被点击时设置第一层Inspector
{
ScanAndAddEnableTypes();
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Element Info");
//基础信息
var info = container.GenerateSubcontainer(3);
var nameInputField = inspector.GenerateInputField(this, info, GetType().Name + "'s Name", nameof(elementName));
var guidText = inspector.GenerateParameterText(this, info, "Element GUID", nameof(elementGuid));
var tagsListButton = inspector.GenerateButton(this, info, "Tags List", () =>
{
inspector.GenerateCompositeParameterWindow(this, "Tags List", nameof(tags)).SetAsStringList();
});
// 只用反射方式生成enableTypes的UI
if (enableTypes != null && enableTypes.Count > 0)
{
var elcontainer = inspector.GenerateContainer("Enable Children Display");
var enableTypeContainer = elcontainer.GenerateSubcontainer(3);
var type = enableTypes.GetType().GetGenericArguments()[0];
int elcount = 0;
for (int idx = 0; idx < enableTypes.Count; idx++)
{
elcount++;
if (elcount > 3)
{
elcount = 0;
enableTypeContainer = elcontainer.GenerateSubcontainer(3);
}
var et = enableTypes[idx];
inspector.GenerateToggle(
et,
enableTypeContainer,
et.type.Name,
nameof(et.enable) // 传递字段名字符串
);
}
}
//次级模块
foreach (var submodule in submoduleList)
{
submodule.SetUpInspector();
}
}
/// <summary>
/// 获取所有子GameElement
/// </summary>
/// <param name="includeThis">是否包括自身</param>
public List<GameElement> GetAllGameElementsFromThis(bool includeThis = true)
{
void GetAllChildrenRecursively(GameElement parent, List<GameElement> elements)
{
foreach (var child in parent.childElementList)
{
elements.Add(child);
GetAllChildrenRecursively(child, elements);
}
}
List<GameElement> gameElements = new List<GameElement> { this };
GetAllChildrenRecursively(this, gameElements);
if (!includeThis) gameElements.Remove(this);
return gameElements;
}
/// <summary>
/// 根据enableTypes筛选子元素只返回enable为true的类型对应的子元素
/// </summary>
public List<GameElement> GetChildrenByTypes()
{
if (enableTypes == null || enableTypes.Count == 0)
return new List<GameElement>();
var enabledTypes = new HashSet<Type>();
foreach (var et in enableTypes)
{
if (et.enable) enabledTypes.Add(et.type);
}
// 问题1只匹配类型本身不能处理继承关系如子类/接口)
// 问题2如果childElementList有null元素会抛异常
// 问题3如果enableTypes有重复type没影响但没必要
// 更健壮的写法如下支持继承和接口避免null
return childElementList.FindAll(child =>
child != null && enabledTypes.Any(t => t.IsAssignableFrom(child.GetType()))
);
}
}
namespace Beatmap
{
[System.Serializable]
public abstract class GameElement_BM : BaseElement_BM
{
[System.NonSerialized]
public static Dictionary<Guid, GameElement_BM> identifier = new(); //存档类的标识符
[System.NonSerialized]
public GameElement matchedElement; //存档类对应的游戏物体
public string elementName;
public List<string> tags;
public Guid elementGuid;
public GameElement_BM()
{
}
public GameElement_BM(string elementName, Guid elementGuid, List<string> tags, GameElement_BM attachedElement)
{
this.elementName = elementName;
this.elementGuid = elementGuid;
this.tags = tags;
this.attachedElementGuid = attachedElement?.elementGuid ?? Guid.Empty;
identifier.TryAdd(this.elementGuid, this);
}
public static GameElement_BM GetElementBM(Guid id)
{
if (identifier.TryGetValue(id, out GameElement_BM element_BM))
{
return element_BM;
}
return null;
}
public static GameElement GetElement(Guid id)
{
if (identifier.TryGetValue(id, out GameElement_BM element_BM))
{
return element_BM.matchedElement;
}
return null;
}
/// <summary>
/// 复制物体
/// </summary>
/// <param name="attached">父物体</param>
public abstract GameElement DuplicateBM(GameElement attached);
public static List<BaseElement_BM> GetAllAttachedBaseElements(GameElement_BM gameElement, List<BaseElement_BM> clip)
{
Guid elementGuid = gameElement.elementGuid;
List<BaseElement_BM> result = new List<BaseElement_BM>();
foreach (BaseElement_BM element in clip)
{
if (element == null)
{
continue;
}
if (element.attachedElementGuid == elementGuid)
{
result.Add(element);
}
}
return result;
}
}
}
}

View File

@@ -1,102 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using Lean.Pool;
using MoreMountains.Feedbacks;
using MoreMountains.FeedbacksForThirdParty;
using Sirenix.OdinInspector;
using UnityEngine;
namespace Ichni.RhythmGame
{
public class BloomEffect : EffectBase
{
public float duration;
public float peak;
public AnimationCurve intensityCurve;
public BloomEffect(float duration, float peak, AnimationCurve intensityCurve)
{
this.effectTime = 0;
this.duration = duration;
this.peak = peak;
this.intensityCurve = intensityCurve;
}
public override void Adjust()
{
MMF_Player effect = LeanPool.Spawn(EditorManager.instance.basePrefabs.bloomEffect).GetComponent<MMF_Player>();
effect.GetFeedbackOfType<MMF_Bloom_URP>().ShakeDuration = duration;
effect.GetFeedbackOfType<MMF_Bloom_URP>().RemapIntensityOne = peak;
effect.GetFeedbackOfType<MMF_Bloom_URP>().ShakeIntensity = intensityCurve;
effect.PlayFeedbacks();
LeanPool.Despawn(effect.gameObject, duration);
}
public override EffectBase_BM ConvertToBM()
{
return new BloomEffect_BM(duration, peak, intensityCurve);
}
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Bloom Shake");
var effectSettings = container.GenerateSubcontainer(3);
var effectTimeField = inspector.GenerateInputField(this, effectSettings, "Bloom Time", nameof(duration));
var bloomPeakField = inspector.GenerateInputField(this, effectSettings, "Bloom Peak", nameof(peak));
var intensityCurveButton = inspector.GenerateButton(this, effectSettings, "Intensity Curve", () =>
{
var intensityCurveWindow =
inspector.GenerateCompositeParameterWindow(this, "Intensity Curve", nameof(intensityCurve)).SetAsCustomCurve();
});
SetRemove(effectSettings);
}
public override void CopyParametersFrom(EffectBase other)
{
if (other is BloomEffect o)
{
this.duration = o.duration;
this.peak = o.peak;
// 深拷贝曲线,避免引用同一个对象
this.intensityCurve = o.intensityCurve != null ? new AnimationCurve(o.intensityCurve.keys) : null;
}
}
}
namespace Beatmap
{
public class BloomEffect_BM : EffectBase_BM
{
public float duration;
public float peak;
public AnimationCurve intensityCurve;
public BloomEffect_BM()
{
}
public BloomEffect_BM(float duration, float peak, AnimationCurve intensityCurve)
{
this.effectTime = 0;
this.duration = duration;
this.peak = peak;
this.intensityCurve = intensityCurve;
}
public override EffectBase ConvertToGameType(GameElement attachedGameElement)
{
return new BloomEffect(duration, peak, intensityCurve)
{
attachedGameElement = attachedGameElement
};
}
}
}
}

View File

@@ -1,97 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using Lean.Pool;
using MoreMountains.Feedbacks;
using MoreMountains.FeedbacksForThirdParty;
using UnityEngine;
namespace Ichni.RhythmGame
{
public class ChromaticAberrationEffect : EffectBase
{
public float duration;
public float peak;
public AnimationCurve intensityCurve;
public ChromaticAberrationEffect(float duration, float peak, AnimationCurve intensityCurve)
{
this.effectTime = 0;
this.duration = duration;
this.peak = peak;
this.intensityCurve = intensityCurve;
}
public override void CopyParametersFrom(EffectBase other)
{
if (other is ChromaticAberrationEffect otherEffect)
{
this.duration = otherEffect.duration;
this.peak = otherEffect.peak;
this.intensityCurve = otherEffect.intensityCurve != null ? new AnimationCurve(otherEffect.intensityCurve.keys) : null;
}
}
public override void Adjust()
{
MMF_Player effect = LeanPool.Spawn(EditorManager.instance.basePrefabs.chromaticAberrationEffect).GetComponent<MMF_Player>();
effect.GetFeedbackOfType<MMF_ChromaticAberration_URP>().Duration = duration;
effect.GetFeedbackOfType<MMF_ChromaticAberration_URP>().RemapIntensityOne = peak;
effect.GetFeedbackOfType<MMF_ChromaticAberration_URP>().Intensity = intensityCurve;
effect.PlayFeedbacks();
LeanPool.Despawn(effect.gameObject, duration);
}
public override EffectBase_BM ConvertToBM()
{
return new ChromaticAberrationEffect_BM(duration, peak, intensityCurve);
}
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Chromatic Aberration");
var effectSettings = container.GenerateSubcontainer(3);
var effectTimeField = inspector.GenerateInputField(this, effectSettings, "Duration", nameof(duration));
var bloomPeakField = inspector.GenerateInputField(this, effectSettings, "Peak Value", nameof(peak));
var intensityCurveButton = inspector.GenerateButton(this, effectSettings, "Intensity Curve", () =>
{
var intensityCurveWindow =
inspector.GenerateCompositeParameterWindow(this, "Intensity Curve", nameof(intensityCurve)).SetAsCustomCurve();
});
SetRemove(effectSettings);
}
}
namespace Beatmap
{
public class ChromaticAberrationEffect_BM : EffectBase_BM
{
public float duration;
public float peak;
public AnimationCurve intensityCurve;
public ChromaticAberrationEffect_BM()
{
}
public ChromaticAberrationEffect_BM(float duration, float peak, AnimationCurve intensityCurve)
{
this.effectTime = 0;
this.duration = duration;
this.peak = peak;
this.intensityCurve = intensityCurve;
}
public override EffectBase ConvertToGameType(GameElement attachedGameElement)
{
return new ChromaticAberrationEffect(duration, peak, intensityCurve)
{
attachedGameElement = attachedGameElement
};
}
}
}
}

View File

@@ -1,142 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
namespace Ichni.RhythmGame
{
public class EnableControlEffect : EffectBase
{
public GameElement connectedGameElement;
public string connectedVariableName;
public int enableValue;
public bool useExpression;
public string expression;
public EnableControlEffect(GameElement connectedGameElement, string connectedVariableName,
int enableValue, bool useExpression, string expression)
{
this.effectTime = 0;
this.connectedGameElement = connectedGameElement;
this.connectedVariableName = connectedVariableName;
this.enableValue = enableValue;
this.useExpression = useExpression;
this.expression = expression;
}
public override void CopyParametersFrom(EffectBase other)
{
if (other is EnableControlEffect otherEffect)
{
this.connectedGameElement = otherEffect.connectedGameElement;
this.connectedVariableName = otherEffect.connectedVariableName;
this.enableValue = otherEffect.enableValue;
this.useExpression = otherEffect.useExpression;
this.expression = otherEffect.expression;
}
}
public override void Recover()
{
if (connectedGameElement == null) return;
connectedGameElement.gameObject.SetActive(false);
}
public override void Adjust()
{
if (connectedGameElement == null) return;
if (!useExpression)
{
int value = EditorManager.instance.variablesContainer.GetVariable(connectedVariableName);
connectedGameElement.gameObject.SetActive(value == enableValue);
}
else
{
}
}
public override EffectBase_BM ConvertToBM()
{
connectedGameElement.SaveBM();
return new EnableControlEffect_BM(connectedGameElement.elementGuid,
connectedVariableName, enableValue, useExpression, expression);
}
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Enable Control");
var effectSettings = container.GenerateSubcontainer(3);
var connectedGameElementInputField = inspector.GenerateInputField(effectSettings, "Game Element Name");
var connectGameElementButton = inspector.GenerateButton(this, effectSettings, "Connect Game Element", () =>
{
connectedGameElement = EditorManager.instance.beatmapContainer.gameElementList
.First(e => e.elementName == connectedGameElementInputField.GetValue<string>());
if (connectedGameElement == null)
{
LogWindow.Log("Game Element not found.", Color.red);
}
inspectorMain.SetInspector(connectedGameElement);
});
string ShowConnection() => connectedGameElement == null ? "No Game Element Connected" : "Connected With: " + connectedGameElement.elementName;
var connectHintText = inspector.GenerateHintText(this, effectSettings, ShowConnection);
var connectedVariableNameInputField = inspector.GenerateInputField(this, effectSettings, "Connected Variable Name", nameof(connectedVariableName));
var enableValueInputField = inspector.GenerateInputField(this, effectSettings, "Enable Value", nameof(enableValue));
// 自定义表达式暂时不可用
var useExpressionToggle = inspector.GenerateToggle(this, effectSettings, "Use Expression", nameof(useExpression));
useExpressionToggle.toggle.interactable = false;
var expressionInputField = inspector.GenerateInputField(this, effectSettings, "Expression", nameof(expression));
expressionInputField.inputField.interactable = false;
SetRemove(effectSettings);
}
}
namespace Beatmap
{
public class EnableControlEffect_BM : EffectBase_BM
{
public Guid connectedGameElementGuid;
public string connectedVariableName;
public int enableValue;
public bool useExpression;
public string expression;
public EnableControlEffect_BM()
{
}
public EnableControlEffect_BM(Guid connectedGameElementGuid, string connectedVariableName,
int enableValue, bool useExpression, string expression)
{
this.connectedGameElementGuid = connectedGameElementGuid;
this.connectedVariableName = connectedVariableName;
this.enableValue = enableValue;
this.useExpression = useExpression;
this.expression = expression;
}
public override EffectBase ConvertToGameType(GameElement attachedGameElement)
{
return new EnableControlEffect(GameElement_BM.GetElement(connectedGameElementGuid), connectedVariableName,
enableValue, useExpression, expression)
{
attachedGameElement = attachedGameElement
};
}
}
}
}

View File

@@ -1,122 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
namespace Ichni.RhythmGame
{
public class PixelateEffect : EffectBase
{
public float duration;
public float bottomX;
public float bottomY;
public AnimationCurve intensityCurve;
public PixelateEffect(float duration, float bottomX, float bottomY, AnimationCurve intensityCurve)
{
this.effectTime = duration;
this.duration = duration;
this.bottomX = bottomX;
this.bottomY = bottomY;
this.intensityCurve = intensityCurve;
}
public override void CopyParametersFrom(EffectBase other)
{
if (other is PixelateEffect otherEffect)
{
this.duration = otherEffect.duration;
this.bottomX = otherEffect.bottomX;
this.bottomY = otherEffect.bottomY;
this.intensityCurve = otherEffect.intensityCurve != null ? new AnimationCurve(otherEffect.intensityCurve.keys) : null;
}
}
public override void Recover()
{
EditorManager.instance.postProcessingManager.SetPixelateStrength(Screen.width, Screen.height);
EditorManager.instance.postProcessingManager.SetFeatureActive(false);
}
public override void Disrupt()
{
EditorManager.instance.postProcessingManager.SetPixelateStrength(Screen.width, Screen.height);
EditorManager.instance.postProcessingManager.SetFeatureActive(false);
}
public override void PreExecute()
{
EditorManager.instance.postProcessingManager.SetFeatureActive(true);
EditorManager.instance.postProcessingManager.SetPixelateStrength(Screen.width, Screen.height);
}
public override void Execute()
{
float x = Mathf.Lerp(Screen.width, bottomX, intensityCurve.Evaluate(effectProgressPercent));
float y = Mathf.Lerp(Screen.height, bottomY, intensityCurve.Evaluate(effectProgressPercent));
// Debug.Log(x + ", " + y);
EditorManager.instance.postProcessingManager.SetPixelateStrength(x, y);
}
public override void Adjust()
{
EditorManager.instance.postProcessingManager.SetPixelateStrength(Screen.width, Screen.height);
EditorManager.instance.postProcessingManager.SetFeatureActive(false);
}
public override EffectBase_BM ConvertToBM()
{
return new PixelateEffect_BM(duration, bottomX, bottomY, intensityCurve);
}
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Pixelate Effect");
var effectSettings = container.GenerateSubcontainer(3);
var effectTimeField = inspector.GenerateInputField(this, effectSettings, "Effect Time", nameof(duration));
var bottomXField = inspector.GenerateInputField(this, effectSettings, "Bottom X", nameof(bottomX));
var bottomYField = inspector.GenerateInputField(this, effectSettings, "Bottom Y", nameof(bottomY));
var intensityCurveButton = inspector.GenerateButton(this, effectSettings, "Intensity Curve", () =>
{
var intensityCurveWindow =
inspector.GenerateCompositeParameterWindow(this, "Intensity Curve", nameof(intensityCurve)).SetAsCustomCurve();
});
var clearButton = inspector.GenerateButton(this, effectSettings, "Clear Pixelate", () =>
{
EditorManager.instance.postProcessingManager.SetFeatureActive(false);
});
SetRemove(effectSettings);
}
}
namespace Beatmap
{
public class PixelateEffect_BM : EffectBase_BM
{
public float duration;
public float bottomX;
public float bottomY;
public AnimationCurve intensityCurve;
public PixelateEffect_BM(float duration, float bottomX, float bottomY, AnimationCurve intensityCurve)
{
this.effectTime = duration;
this.duration = duration;
this.bottomX = bottomX;
this.bottomY = bottomY;
this.intensityCurve = intensityCurve;
}
public override EffectBase ConvertToGameType(GameElement attachedGameElement)
{
return new PixelateEffect(duration, bottomX, bottomY, intensityCurve)
{
attachedGameElement = attachedGameElement
};
}
}
}
}

View File

@@ -1,117 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
namespace Ichni.RhythmGame
{
public class RadialBlurEffect : EffectBase
{
private readonly PostProcessingController nbController;
public float duration;
public int sampleLevel;
public float position;
public float fadeRange;
public float peakIntensity;
public AnimationCurve intensityCurve;
public RadialBlurEffect(float duration, int sampleLevel, float position, float fadeRange, float peakIntensity, AnimationCurve intensityCurve)
{
this.effectTime = duration;
this.duration = duration;
this.sampleLevel = sampleLevel;
this.position = position;
this.fadeRange = fadeRange;
this.peakIntensity = peakIntensity;
this.intensityCurve = intensityCurve;
this.nbController = EditorManager.instance.postProcessingManager.nbController;
}
public override void Recover()
{
nbController.radialBlurToggle = false;
}
public override void Disrupt()
{
nbController.radialBlurToggle = false;
}
public override void PreExecute()
{
nbController.radialBlurToggle = true;
nbController.radialBlurSampleCount = sampleLevel;
nbController.radialBlurPos = position;
nbController.radialBlurRange = fadeRange;
}
public override void Execute()
{
float intensity = Mathf.Lerp(0, peakIntensity, intensityCurve.Evaluate(effectProgressPercent));
nbController.radialBlurIntensity = intensity;
}
public override void Adjust()
{
nbController.radialBlurToggle = false;
}
public override EffectBase_BM ConvertToBM()
{
return new RadialBlurEffect_BM(duration, sampleLevel, position, fadeRange, peakIntensity, intensityCurve);
}
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Radial Blur Effect");
var effectSettings = container.GenerateSubcontainer(3);
var effectTimeField = inspector.GenerateInputField(this, effectSettings, "Effect Time", nameof(duration));
var sampleLevelField = inspector.GenerateInputField(this, effectSettings, "Sample Level", nameof(sampleLevel));
var positionField = inspector.GenerateInputField(this, effectSettings, "Position", nameof(position));
var fadeRangeField = inspector.GenerateInputField(this, effectSettings, "Fade Range", nameof(fadeRange));
var peakIntensityField = inspector.GenerateInputField(this, effectSettings, "Peak Intensity", nameof(peakIntensity));
var intensityCurveButton = inspector.GenerateButton(this, effectSettings, "Intensity Curve", () =>
{
var intensityCurveWindow =
inspector.GenerateCompositeParameterWindow(this, "Intensity Curve", nameof(intensityCurve)).SetAsCustomCurve();
});
SetRemove(effectSettings);
}
}
namespace Beatmap
{
public class RadialBlurEffect_BM : EffectBase_BM
{
public float duration;
public int sampleLevel;
public float position;
public float fadeRange;
public float peakIntensity;
public AnimationCurve intensityCurve;
public RadialBlurEffect_BM(float duration, int sampleLevel, float position, float fadeRange, float peakIntensity, AnimationCurve intensityCurve)
{
this.effectTime = duration;
this.duration = duration;
this.sampleLevel = sampleLevel;
this.position = position;
this.fadeRange = fadeRange;
this.peakIntensity = peakIntensity;
this.intensityCurve = intensityCurve;
}
public override EffectBase ConvertToGameType(GameElement attachedGameElement)
{
return new RadialBlurEffect(duration, sampleLevel, position, fadeRange, peakIntensity, intensityCurve)
{
attachedGameElement = attachedGameElement,
};
}
}
}
}

View File

@@ -1,92 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
namespace Ichni.RhythmGame
{
public class SetIntegerEffect : EffectBase
{
public string targetVariableName;
public int targetValue;
public bool isRandom;
public int minValue;
public int maxValue;
public SetIntegerEffect(string targetVariableName, int targetValue, bool isRandom, int minValue, int maxValue)
{
this.effectTime = 0;
this.targetVariableName = targetVariableName;
this.targetValue = targetValue;
this.isRandom = isRandom;
this.minValue = minValue;
this.maxValue = maxValue;
}
public override void Recover()
{
EditorManager.instance.variablesContainer.RevertVariable(targetVariableName);
}
public override void Adjust()
{
EditorManager.instance.variablesContainer.SetVariable(targetVariableName, isRandom ? Random.Range(minValue, maxValue + 1) : targetValue);
}
public override EffectBase_BM ConvertToBM()
{
return new SetIntegerEffect_BM(targetVariableName, targetValue, isRandom, minValue, maxValue);
}
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Set Integer");
var effectSettings = container.GenerateSubcontainer(3);
var targetVariableNameInputField = inspector.GenerateInputField(this, effectSettings, "Target Variable Name", nameof(targetVariableName));
var targetValueInputField = inspector.GenerateInputField(this, effectSettings, "Target Value", nameof(targetValue));
var isRandomToggle = inspector.GenerateToggle(this, effectSettings, "Is Random", nameof(isRandom));
var minValueInputField = inspector.GenerateInputField(this, effectSettings, "Min Value", nameof(minValue));
var maxValueInputField = inspector.GenerateInputField(this, effectSettings, "Max Value", nameof(maxValue));
SetRemove(effectSettings);
}
}
namespace Beatmap
{
public class SetIntegerEffect_BM : EffectBase_BM
{
public string targetVariableName;
public int targetValue;
public bool isRandom;
public int minValue;
public int maxValue;
public SetIntegerEffect_BM()
{
}
public SetIntegerEffect_BM(string targetVariableName, int targetValue, bool isRandom, int minValue, int maxValue)
{
this.effectTime = 0;
this.targetVariableName = targetVariableName;
this.targetValue = targetValue;
this.isRandom = isRandom;
this.minValue = minValue;
this.maxValue = maxValue;
}
public override EffectBase ConvertToGameType(GameElement attachedGameElement)
{
return new SetIntegerEffect(targetVariableName, targetValue, isRandom, minValue, maxValue)
{
attachedGameElement = attachedGameElement
};
}
}
}
}

View File

@@ -1,93 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using Sirenix.OdinInspector;
using UnityEngine;
namespace Ichni.RhythmGame
{
public partial class TimeEffectsCollection : GameElement, IHaveTransformSubmodule, IHaveEffectSubmodule
{
public TransformSubmodule transformSubmodule { get; set; }
public EffectSubmodule effectSubmodule { get; set; }
public float time; //触发效果的时间
public static TimeEffectsCollection GenerateElement(string name, Guid guid, List<string> tags,
bool isFirstGenerated, GameElement parentElement, float time)
{
TimeEffectsCollection timeEffectsCollection = Instantiate(EditorManager.instance.basePrefabs.emptyObject)
.AddComponent<TimeEffectsCollection>();
timeEffectsCollection.Initialize(name, guid, tags, isFirstGenerated, parentElement);
timeEffectsCollection.time = time;
return timeEffectsCollection;
}
public override void SetDefaultSubmodules()
{
transformSubmodule = new TransformSubmodule(this);
effectSubmodule = new EffectSubmodule(this);
}
private void Update()
{
effectSubmodule.effectCollection["Prior"].ForEach(effect => effect.UpdateEffect(time));
effectSubmodule.effectCollection["Default"].ForEach(effect => effect.UpdateEffect(time));
effectSubmodule.effectCollection["Late"].ForEach(effect => effect.UpdateEffect(time));
}
}
public partial class TimeEffectsCollection
{
public override void SaveBM()
{
matchedBM = new TimeEffectsCollection_BM(elementName, elementGuid, tags,
parentElement.matchedBM as GameElement_BM, this);
}
public override void SetUpInspector()
{
base.SetUpInspector();
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Time Effects Collection");
var collectionSettings = container.GenerateSubcontainer(3);
var timeInputField = inspector.GenerateInputField(this, collectionSettings, "Time", nameof(time));
}
}
namespace Beatmap
{
public class TimeEffectsCollection_BM : GameElement_BM
{
public float time;
public TimeEffectsCollection_BM()
{
}
public TimeEffectsCollection_BM(string elementName, Guid elementGuid, List<string> tags,
GameElement_BM attachedElement, TimeEffectsCollection timeEffectsCollection)
: base(elementName, elementGuid, tags, attachedElement)
{
time = timeEffectsCollection.time;
}
public override void ExecuteBM()
{
matchedElement = TimeEffectsCollection.GenerateElement(elementName, Guid.NewGuid(),
tags, false, GetElement(attachedElementGuid), time);
}
public override GameElement DuplicateBM(GameElement attached)
{
return TimeEffectsCollection.GenerateElement(elementName, Guid.NewGuid(),
tags, false, attached, time);
}
}
}
}

View File

@@ -1,115 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using MoreMountains.Feedbacks;
using MoreMountains.FeedbacksForThirdParty;
using UnityEngine;
using UnityEngine.Rendering.Universal;
namespace Ichni.RhythmGame
{
public class VignetteEffect : EffectBase
{
public float duration;
public float peak;
public float smoothness;
public Color color;
public AnimationCurve intensityCurve;
public VignetteEffect(float duration, float peak, float smoothness, Color color, AnimationCurve intensityCurve)
{
this.effectTime = 0;
this.duration = duration;
this.peak = peak;
this.smoothness = smoothness;
this.color = color;
this.intensityCurve = intensityCurve;
}
public override void CopyParametersFrom(EffectBase other)
{
if (other is VignetteEffect otherEffect)
{
this.duration = otherEffect.duration;
this.peak = otherEffect.peak;
this.smoothness = otherEffect.smoothness;
this.color = otherEffect.color;
this.intensityCurve = otherEffect.intensityCurve != null ? new AnimationCurve(otherEffect.intensityCurve.keys) : null;
}
}
public override void Adjust()
{
MMF_Player effect = Lean.Pool.LeanPool.Spawn(EditorManager.instance.basePrefabs.vignetteEffect).GetComponent<MMF_Player>();
effect.GetFeedbackOfType<MMF_Vignette_URP>().Duration = duration;
effect.GetFeedbackOfType<MMF_Vignette_URP>().RemapIntensityOne = peak;
effect.GetFeedbackOfType<MMF_Vignette_URP>().Intensity = intensityCurve;
if (EditorManager.instance.postProcessingManager.globalVolume.profile.TryGet(out Vignette vignette))
{
vignette.smoothness.value = smoothness;
vignette.color.value = color;
}
effect.PlayFeedbacks();
Lean.Pool.LeanPool.Despawn(effect.gameObject, duration);
}
public override EffectBase_BM ConvertToBM()
{
return new VignetteEffect_BM(duration, peak, smoothness, color, intensityCurve);
}
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Vignette");
var effectSettings = container.GenerateSubcontainer(3);
var durationField = inspector.GenerateInputField(this, effectSettings, "Duration", nameof(duration));
var peakField = inspector.GenerateInputField(this, effectSettings, "Peak Value", nameof(peak));
var smoothnessField = inspector.GenerateInputField(this, effectSettings, "Smoothness", nameof(smoothness));
var intensityCurveButton = inspector.GenerateButton(this, effectSettings, "Intensity Curve", () =>
{
var intensityCurveWindow =
inspector.GenerateCompositeParameterWindow(this, "Intensity Curve", nameof(intensityCurve)).SetAsCustomCurve();
});
var colorSettings = container.GenerateSubcontainer(1);
var colorField = inspector.GenerateBaseColorPicker(this, colorSettings, "Color", nameof(color));
SetRemove(effectSettings);
}
}
namespace Beatmap
{
public class VignetteEffect_BM : EffectBase_BM
{
public float duration;
public float peak;
public float smoothness;
public Color color;
public AnimationCurve intensityCurve;
public VignetteEffect_BM()
{
}
public VignetteEffect_BM(float duration, float peak, float smoothness, Color color, AnimationCurve intensityCurve)
{
this.effectTime = 0;
this.duration = duration;
this.peak = peak;
this.smoothness = smoothness;
this.color = color;
this.intensityCurve = intensityCurve;
}
public override EffectBase ConvertToGameType(GameElement attachedGameElement)
{
return new VignetteEffect(duration, peak, smoothness, color, intensityCurve)
{
attachedGameElement = attachedGameElement
};
}
}
}
}

View File

@@ -1,207 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
using UnityEngine.Serialization;
namespace Ichni.RhythmGame
{
public partial class BackgroundSetter : GameElement
{
public bool useSkybox;
public string skyboxThemeBundleName;
public string skyboxMaterialName;
public Material skyboxMaterial;
public string backgroundSpriteName;
public Sprite backgroundSprite;
public SkyboxSubsetter skyboxSubsetter;
public static BackgroundSetter GenerateElement(string elementName, Guid id, List<string> tags,
bool isFirstGenerated, GameElement parentElement, bool useSkybox, string skyboxThemeBundleName,
string skyboxMaterialName, string backgroundSpriteName)
{
if (EditorManager.instance.backgroundSetter != null)
{
LogWindow.Log("There is already a Background Setter in the scene.", Color.red);
return null;
}
BackgroundSetter backgroundSetter = Instantiate(EditorManager.instance.basePrefabs.emptyObject)
.AddComponent<BackgroundSetter>();
EditorManager.instance.backgroundSetter = backgroundSetter;
backgroundSetter.Initialize(elementName, id, tags, isFirstGenerated, parentElement);
backgroundSetter.useSkybox = useSkybox;
backgroundSetter.skyboxThemeBundleName = skyboxThemeBundleName;
backgroundSetter.skyboxMaterialName = skyboxMaterialName;
backgroundSetter.backgroundSpriteName = backgroundSpriteName;
return backgroundSetter;
}
public override void Refresh()
{
EditorManager.instance.backgroundController.EnableBackground(!useSkybox);
if (useSkybox && skyboxSubsetter == null)
{
SetSkybox(skyboxThemeBundleName, skyboxMaterialName);
}
else
{
SetBackgroundSprite(backgroundSpriteName);
}
}
}
public partial class BackgroundSetter
{
public override void SaveBM()
{
matchedBM = new BackgroundSetter_BM(elementName, elementGuid, tags, null,
useSkybox, skyboxThemeBundleName, skyboxMaterialName, backgroundSpriteName);
}
// 新增:用于在 Inspector 中显示的列表数据
[HideInInspector] private List<string> themeBundleListForSelection;
[HideInInspector] private List<string> skyboxNameListForSelection;
private void UpdateSelectionLists()
{
themeBundleListForSelection = ThemeBundleManager.instance.loadedThemeBundleList.ConvertAll(x => x.themeBundleName);
skyboxNameListForSelection = new List<string>();
if (!string.IsNullOrEmpty(skyboxThemeBundleName) &&
ThemeBundleManager.instance.TryGetThemeBundle(skyboxThemeBundleName, out ThemeBundle themeBundle))
{
skyboxNameListForSelection = themeBundle.assetList_Material.ConvertAll(x => x.name);
}
}
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
Inspector inspectorMain = EditorManager.instance.uiManager.inspector; // 引用主检查器用于刷新
var container = inspector.GenerateContainer("Background Setter");
var backgroundSettings = container.GenerateSubcontainer(3);
// 1. 开关
var useSkyboxToggle = inspector.GenerateToggle(this, backgroundSettings, "Use Skybox", nameof(useSkybox));
// 刷新可选列表
UpdateSelectionLists();
// 2. 天空盒资源包下拉框 (同步 SkyboxSubsetter 逻辑)
var themeDropdown = inspector.GenerateDropdown(this, backgroundSettings, "Skybox Theme Bundle",
themeBundleListForSelection, nameof(skyboxThemeBundleName));
themeDropdown.AddListenerFunction(() =>
{
UpdateSelectionLists();
inspectorMain.SetInspector(this); // 选择包后刷新 UI 以加载材质列表
});
// 3. 天空盒材质下拉框 (同步 SkyboxSubsetter 逻辑)
var materialDropdown = inspector.GenerateDropdown(this, backgroundSettings, "Skybox Material",
skyboxNameListForSelection, nameof(skyboxMaterialName));
if (string.IsNullOrEmpty(skyboxThemeBundleName) || skyboxNameListForSelection.Count == 0)
{
materialDropdown.dropdown.interactable = false;
}
// 4. 背景图片输入框 (保持原样)
var backgroundSpriteField = inspector.GenerateInputField(this, backgroundSettings, "Background Sprite", nameof(backgroundSpriteName));
// 5. 应用按钮
var applyButton = inspector.GenerateButton(this, backgroundSettings, "Apply", Refresh);
// 控制交互性
void SetInputFields(bool value)
{
themeDropdown.dropdown.interactable = value;
materialDropdown.dropdown.interactable = value && !string.IsNullOrEmpty(skyboxThemeBundleName);
backgroundSpriteField.inputField.interactable = !value;
}
SetInputFields(useSkybox);
useSkyboxToggle.AddListenerFunction(() =>
{
EditorManager.instance.backgroundController.EnableBackground(!useSkybox);
SetInputFields(useSkybox);
});
// 生成 Skybox Subsetter 的按钮部分
var generateContainer = inspector.GenerateContainer("Advanced Controls");
var generateSubContainer = generateContainer.GenerateSubcontainer(3);
inspector.GenerateButton(this, generateSubContainer, "Create Skybox Controller", () =>
{
if (skyboxSubsetter == null)
{
SkyboxSubsetter.GenerateElement("New Skybox Subsetter", Guid.NewGuid(), new List<string>(), true, this,
new List<string>(), new List<string>(), new List<float>(), new List<float>());
}
else
{
LogWindow.Log("There is already a Skybox Subsetter in the scene.", Color.yellow);
}
});
}
}
public partial class BackgroundSetter
{
private void SetSkybox(string themeBundleName, string materialName)
{
skyboxThemeBundleName = themeBundleName;
skyboxMaterialName = materialName;
skyboxMaterial = ThemeBundleManager.instance.GetObject<Material>(themeBundleName, materialName);
if (skyboxMaterial == null) skyboxMaterial = EditorManager.instance.basePrefabs.defaultSkyboxMaterial;
EditorManager.instance.backgroundController.SetSkybox(skyboxMaterial);
}
private void SetBackgroundSprite(string spriteName)
{
string path = EditorManager.instance.projectInformation.projectPath + "/Sprites/" + spriteName + ".png";
backgroundSprite = ES3.FileExists(path) ? ES3.Load<Sprite>(path) : EditorManager.instance.basePrefabs.defaultBackground;
EditorManager.instance.backgroundController.SetBackground(backgroundSprite);
}
}
namespace Beatmap
{
public class BackgroundSetter_BM : GameElement_BM
{
public bool useSkybox;
public string skyboxThemeBundleName;
public string skyboxMaterialName;
public string backgroundSpriteName;
public BackgroundSetter_BM()
{
}
public BackgroundSetter_BM(string elementName, Guid elementGuid, List<string> tags, GameElement_BM attachedElement,
bool useSkybox, string skyboxThemeBundleName, string skyboxMaterialName, string backgroundSpriteName)
: base(elementName, elementGuid, tags, attachedElement)
{
this.useSkybox = useSkybox;
this.skyboxThemeBundleName = skyboxThemeBundleName;
this.skyboxMaterialName = skyboxMaterialName;
this.backgroundSpriteName = backgroundSpriteName;
}
public override void ExecuteBM()
{
matchedElement = BackgroundSetter.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid), useSkybox, skyboxThemeBundleName, skyboxMaterialName, backgroundSpriteName);
}
public override GameElement DuplicateBM(GameElement attached)
{
return BackgroundSetter.GenerateElement(elementName, Guid.NewGuid(), tags, false, attached,
useSkybox, skyboxThemeBundleName, skyboxMaterialName, backgroundSpriteName);
}
}
}
}

View File

@@ -1,316 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Ichni.Editor;
using Ichni.RhythmGame;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
using UnityEngine.Serialization;
using UnityEngine.UI;
using Object = UnityEngine.Object;
namespace Ichni.RhythmGame
{
public partial class SkyboxSubsetter : GameElement
{
public SkyboxBlender skyboxBlender;
public List<string> skyBoxThemeBundleList;
public List<string> skyboxNameList;
public List<Material> skyboxMaterialList;
public List<float> blendSpeedList;
public List<float> blendTimeList;
public int currentSkyboxIndex = 0;
public List<string> themeBundleListForSelection;
public List<string> skyboxNameListForSelection;
public string selectedThemeBundle;
public string selectedSkybox;
public static SkyboxSubsetter GenerateElement(string elementName, Guid id, List<string> tags,
bool isFirstGenerated, GameElement parentElement, List<string> themeBundleList, List<string> skyboxList,
List<float> blendTimeList, List<float> blendSpeedList)
{
SkyboxSubsetter skyboxSubsetter = Instantiate(EditorManager.instance.basePrefabs.emptyObject)
.AddComponent<SkyboxSubsetter>();
EditorManager.instance.backgroundSetter.skyboxSubsetter = skyboxSubsetter;
skyboxSubsetter.Initialize(elementName, id, tags, isFirstGenerated, parentElement);
skyboxSubsetter.skyBoxThemeBundleList = themeBundleList;
skyboxSubsetter.skyboxNameList = skyboxList;
skyboxSubsetter.skyboxMaterialList = new List<Material>();
skyboxSubsetter.blendTimeList = blendTimeList;
skyboxSubsetter.blendSpeedList = blendSpeedList;
skyboxSubsetter.SetUpBlender();
skyboxSubsetter.themeBundleListForSelection = ThemeBundleManager.instance.loadedThemeBundleList.ConvertAll(x => x.themeBundleName);
skyboxSubsetter.skyboxNameListForSelection = new List<string>();
skyboxSubsetter.selectedThemeBundle = String.Empty;
skyboxSubsetter.selectedSkybox = String.Empty;
return skyboxSubsetter;
}
private void SetUpBlender()
{
skyboxBlender = gameObject.AddComponent<SkyboxBlender>();
skyboxBlender.loop = false;
skyboxBlender.timeToWait = 0f;
skyboxBlender.updateLighting = false;
skyboxBlender.updateReflections = false;
skyboxBlender.skyboxMaterials = new List<Material>();
for (int i = 0; i < skyBoxThemeBundleList.Count; i++)
{
Material skybox = ThemeBundleManager.instance.GetObject<Material>(skyBoxThemeBundleList[i], skyboxNameList[i]);
skyboxMaterialList.Add(skybox);
skyboxBlender.skyboxMaterials.Add(skybox);
}
skyboxBlender.makeFirstMaterialSkybox = true;
skyboxBlender.InspectorAndAwakeChanges();
}
private void AddSkybox(string skyboxThemeBundleName, string skyboxObjectName)
{
Material skybox = ThemeBundleManager.instance.GetObject<Material>(skyboxThemeBundleName, skyboxObjectName);
if (skybox != null)
{
skyBoxThemeBundleList.Add(skyboxThemeBundleName);
skyboxNameList.Add(skyboxObjectName);
skyboxMaterialList.Add(skybox);
skyboxBlender.skyboxMaterials.Add(skybox);
}
}
private void Update()
{
if (skyBoxThemeBundleList.Count > 1)
{
float songTime = EditorManager.instance.songInformation.songTime;
float delay = EditorManager.instance.songInformation.delay;
float finalTime = EditorManager.instance.songInformation.songLength;
for (var index = 0; index < blendTimeList.Count + 1; index++)
{
float startTime = index == 0 ? -delay : blendTimeList[index - 1];
float endTime = index >= blendTimeList.Count ? finalTime : blendTimeList[index];
if (songTime >= startTime && songTime < endTime && currentSkyboxIndex != index)
{
bool isSmaller = index < currentSkyboxIndex;
currentSkyboxIndex = index;
if (currentSkyboxIndex != 0) skyboxBlender.blendSpeed = isSmaller ? 9999f : blendSpeedList[currentSkyboxIndex - 1];
skyboxBlender.Blend(currentSkyboxIndex, false);
DynamicGI.UpdateEnvironment();
}
}
}
}
public override void SaveBM()
{
matchedBM = new SkyboxSubsetter_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM,
skyBoxThemeBundleList, skyboxNameList, blendTimeList, blendSpeedList);
}
/// <summary>
/// 刷新 skyboxMaterialList 和 skyboxBlender.skyboxMaterials使其与 theme/name 列表同步。
/// </summary>
public void RefreshSkyboxes()
{
skyboxMaterialList.Clear();
skyboxBlender.skyboxMaterials.Clear();
for (int i = 0; i < skyBoxThemeBundleList.Count && i < skyboxNameList.Count; i++)
{
var mat = ThemeBundleManager.instance.GetObject<Material>(skyBoxThemeBundleList[i], skyboxNameList[i]);
skyboxMaterialList.Add(mat);
skyboxBlender.skyboxMaterials.Add(mat);
}
skyboxBlender.InspectorAndAwakeChanges();
}
}
public partial class SkyboxSubsetter
{
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Skybox Subsetter");
DynamicUISubcontainer mainSettings = container.GenerateSubcontainer(3);
var blendSpeedListButton = inspector.GenerateButton(this, mainSettings, "Blend Speed List", () =>
{
inspector.GenerateCompositeParameterWindow(this, "Blend Speed List", nameof(blendSpeedList))
.SetAsFloatList();
});
var blendTimeListButton = inspector.GenerateButton(this, mainSettings, "Blend Time List", () =>
{
inspector.GenerateCompositeParameterWindow(this, "Blend Time List", nameof(blendTimeList))
.SetAsFloatList();
});
DynamicUISubcontainer materialSettings = container.GenerateSubcontainer(3);
// 新增显示skybox配置情况//这他妈是什么
for (int i = 0; i < (skyBoxThemeBundleList?.Count ?? 0); i++)
{
try
{
DynamicUISubcontainer Textsettings = container.GenerateSubcontainer(3);
// 安全访问元素:检查索引是否在所有列表的有效范围内
string bundleName = i < skyBoxThemeBundleList.Count ? skyBoxThemeBundleList[i] : "<Missing Bundle>";
string name = i < skyboxNameList.Count ? skyboxNameList[i] : "<Missing Name>";
if (i > 0)
{
inspector.GenerateInputField(this, Textsettings, "Time", $"{nameof(blendTimeList)}.{i - 1}");
inspector.GenerateInputField(this, Textsettings, "Speed", $"{nameof(blendSpeedList)}.{i - 1}");
}
else
{
inspector.GenerateHintText(this, Textsettings, "The First");
inspector.GenerateHintText(this, Textsettings, "0");
}
inspector.GenerateHintText(this, Textsettings, $"{i + 1}. {name}");
// inspector.GenerateInputField(this, Textsettings, "B", $"skyBoxThemeBundleList.{i}").AddListenerFunction(RefreshSkyboxes);
// inspector.GenerateInputField(this, Textsettings, "N", $"skyboxNameList.{i}").AddListenerFunction(RefreshSkyboxes);
inspector.GenerateDropdown(this, Textsettings, "B", themeBundleListForSelection, $"{nameof(skyBoxThemeBundleList)}.{i}")
.AddListenerFunction(() => inspectorMain.SetInspector(this));
List<string> skyboxNameListForSelection = new List<string>();
string selectedThemeBundleL = skyBoxThemeBundleList[i];
if (selectedThemeBundleL != String.Empty && ThemeBundleManager.instance.TryGetThemeBundle(selectedThemeBundleL, out ThemeBundle themeBundleLoop))
{
skyboxNameListForSelection = themeBundleLoop.assetList_Material.ConvertAll(x => x.name);
var objectNameDropdown =
inspector.GenerateDropdown(this, Textsettings, "Material Name", skyboxNameListForSelection, $"{nameof(skyboxNameList)}.{i}")
.AddListenerFunction(() => inspectorMain.SetInspector(this))
.AddListenerFunction(RefreshSkyboxes);
}
// else
// {
// var objectNameDropdown =
// inspector.GenerateDropdown(this, Textsettings, "Material Name", new List<string>(), $"{nameof(skyboxNameList)}.{i}");
// objectNameDropdown.dropdown.interactable = false;
// } // 如果没有选择主题包,则材质名称下拉框不可用
// inspector.GenerateDropdown(this, Textsettings, "N", skyboxNameListForSelection, $"skyboxNameList.{i}")
// .AddListenerFunction(RefreshSkyboxes);
// 创建局部变量解决闭包问题
int index = i;
inspector.GenerateButton(this, Textsettings, "Remove Skybox", () =>
{
try
{
// 移除前检查所有列表的索引有效性
if (index < skyBoxThemeBundleList.Count)
skyBoxThemeBundleList.RemoveAt(index);
else
Debug.LogError($"Cannot remove: skyBoxThemeBundleList index {index} out of range");
if (index < skyboxNameList.Count)
skyboxNameList.RemoveAt(index);
else
Debug.LogError($"Cannot remove: skyboxNameList index {index} out of range");
if (index < skyboxMaterialList.Count)
skyboxMaterialList.RemoveAt(index);
else
Debug.LogError($"Cannot remove: skyboxMaterialList index {index} out of range");
if (index < skyboxBlender.skyboxMaterials.Count)
skyboxBlender.skyboxMaterials.RemoveAt(index);
else
Debug.LogError($"Cannot remove: skyboxMaterials index {index} out of range");
inspectorMain.SetInspector(this);
}
catch (Exception ex)
{
Debug.LogError($"Error during removal: {ex.Message}");
}
});
}
catch (Exception ex)
{
Debug.LogError($"Error generating UI for index {i}: {ex.Message}");
}
}
Debug.Log((mainSettings == null) + " " + (themeBundleListForSelection == null) + " " + (selectedThemeBundle == null));
var themeBundleDropdown =
inspector.GenerateDropdown(this, materialSettings, "Theme Bundle", themeBundleListForSelection, nameof(selectedThemeBundle))
.AddListenerFunction(() => inspectorMain.SetInspector(this));
if (selectedThemeBundle != String.Empty && ThemeBundleManager.instance.TryGetThemeBundle(selectedThemeBundle, out ThemeBundle themeBundle))
{
skyboxNameListForSelection = themeBundle.assetList_Material.ConvertAll(x => x.name);
var objectNameDropdown =
inspector.GenerateDropdown(this, materialSettings, "Material Name", skyboxNameListForSelection, nameof(selectedSkybox))
.AddListenerFunction(() => inspectorMain.SetInspector(this));
}
else
{
var objectNameDropdown =
inspector.GenerateDropdown(this, materialSettings, "Material Name", new List<string>(), nameof(selectedSkybox));
objectNameDropdown.dropdown.interactable = false;
} // 如果没有选择主题包,则材质名称下拉框不可用
var setMaterialButton = inspector.GenerateButton(this, materialSettings, "Add Skybox", () =>
{
AddSkybox(selectedThemeBundle, selectedSkybox);
inspectorMain.SetInspector(this);
});
if (selectedThemeBundle == String.Empty || selectedSkybox == String.Empty)
{
setMaterialButton.button.interactable = false;
}
}
}
namespace Beatmap
{
public class SkyboxSubsetter_BM : GameElement_BM
{
public List<string> skyBoxThemeBundleList;
public List<string> skyboxNameList;
public List<float> blendTimeList;
public List<float> blendSpeedList;
public SkyboxSubsetter_BM()
{
}
public SkyboxSubsetter_BM(string elementName, Guid elementGuid, List<string> tags, GameElement_BM attachedElement,
List<string> skyBoxThemeBundleList, List<string> skyboxNameList, List<float> blendTimeList, List<float> blendSpeedList)
: base(elementName, elementGuid, tags, attachedElement)
{
this.skyBoxThemeBundleList = skyBoxThemeBundleList;
this.skyboxNameList = skyboxNameList;
this.blendTimeList = blendTimeList;
this.blendSpeedList = blendSpeedList;
}
public override void ExecuteBM()
{
matchedElement = SkyboxSubsetter.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid), skyBoxThemeBundleList, skyboxNameList, blendTimeList, blendSpeedList);
}
public override GameElement DuplicateBM(GameElement attached)
{
return SkyboxSubsetter.GenerateElement(elementName, Guid.NewGuid(), tags, false,
attached, skyBoxThemeBundleList, skyboxNameList, blendTimeList, blendSpeedList);
}
}
}
}

View File

@@ -1,114 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using Unity.VisualScripting;
using UnityEngine;
namespace Ichni.RhythmGame
{
public partial class VariablesContainer : GameElement
{
public Dictionary<string, int> originalVariables;
public Dictionary<string, int> currentVariables;
public static VariablesContainer GenerateElement(string elementName, Guid id, List<string> tags, bool isFirstGenerated,
GameElement parentElement, Dictionary<string, int> variables)
{
if (EditorManager.instance.variablesContainer != null)
{
LogWindow.Log("There is already a Variables Container in the scene.", Color.red);
return null;
}
VariablesContainer variablesContainer =
Instantiate(EditorManager.instance.basePrefabs.emptyObject).AddComponent<VariablesContainer>();
EditorManager.instance.variablesContainer = variablesContainer;
variablesContainer.Initialize(elementName, id, tags, isFirstGenerated, parentElement);
variablesContainer.originalVariables = new Dictionary<string, int>(variables);
variablesContainer.currentVariables = new Dictionary<string, int>(variables);
return variablesContainer;
}
public void SetVariable(string variableName, int value)
{
currentVariables[variableName] = value;
}
public int GetVariable(string variableName)
{
return currentVariables[variableName];
}
public void RevertVariable(string variableName)
{
currentVariables[variableName] = originalVariables[variableName];
}
public void RevertAllVariables()
{
currentVariables = new Dictionary<string, int>(originalVariables);
}
}
public partial class VariablesContainer
{
public override void SaveBM()
{
matchedBM = new VariablesContainer_BM(elementName, elementGuid, tags, null, originalVariables);
}
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Variables Container");
var subcontainer = container.GenerateSubcontainer(3);
var originalVariablesButton = inspector.GenerateButton(this, subcontainer, "Original Variables", () =>
{
var ov =
inspector.GenerateCompositeParameterWindow(this, "Original Variables List", nameof(originalVariables))
.SetAsStringIntDictionary()
.AddListenerFunction(RevertAllVariables);
});
var currentVariablesButton = inspector.GenerateButton(this, subcontainer, "Current Variables", () =>
{
var cv =
inspector.GenerateCompositeParameterWindow(this, "Current Variables List", nameof(currentVariables))
.SetAsStringIntDictionary();
});
}
}
namespace Beatmap
{
public class VariablesContainer_BM : GameElement_BM
{
public Dictionary<string, int> originalVariables;
public VariablesContainer_BM()
{
}
public VariablesContainer_BM(string elementName, Guid elementGuid, List<string> tags, GameElement_BM parentElement,
Dictionary<string, int> originalVariables) : base(elementName, elementGuid, tags, parentElement)
{
this.originalVariables = new Dictionary<string, int>(originalVariables);
}
public override void ExecuteBM()
{
matchedElement = VariablesContainer.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid), originalVariables);
}
public override GameElement DuplicateBM(GameElement attached)
{
return VariablesContainer.GenerateElement(elementName, Guid.NewGuid(), tags, false, attached, originalVariables);
}
}
}
}

View File

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

View File

@@ -1,180 +0,0 @@
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);
if (!HaveSameSubmodule)
{
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>();
if (!HaveSameSubmodule)
{
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("Audio 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

@@ -1,75 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
namespace Ichni.RhythmGame
{
public class FullScreenNearTimeJudgeUnit : NoteJudgeUnit
{
protected override GameObject GetHintImagePrefab() => EditorManager.instance.basePrefabs.fullscreenNearTimeHint;
public FullScreenNearTimeJudgeUnit(NoteBase note) : base(note)
{
}
public override void UpdateJudge()
{
if (note is Hold hold)
{
if (hold.isFinalJudged) return;
}
else
{
if (note.isFirstJudged) return;
}
Vector2 noteScreenPosition = note.noteScreenPosition;
RectTransform canvasRect = EditorManager.instance.judgeHintCanvas.GetComponent<RectTransform>();
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRect, noteScreenPosition, null, out Vector2 uiPosition))
{
judgeHintImage.anchoredPosition = uiPosition;
}
}
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Full Screen Near Time Judge Unit");
var judgeModuleSettings = container.GenerateSubcontainer(3);
var isShowingJudgeField =
inspector.GenerateToggle(this, judgeModuleSettings, "Is Showing Judge", nameof(isShowingJudge))
.AddListenerFunction(() => SetShowingJudge(isShowingJudge));
var removeButton = inspector.GenerateButton(this, judgeModuleSettings, "Remove", () =>
{
SetShowingJudge(false);
note.noteJudgeSubmodule.judgeUnitList.Remove(this);
inspectorMain.SetInspector(note);
});
}
public override NoteJudgeUnit_BM ConvertToBM()
{
return new FullScreenNearTimeJudgeUnit_BM();
}
}
namespace Beatmap
{
public class FullScreenNearTimeJudgeUnit_BM : NoteJudgeUnit_BM
{
public FullScreenNearTimeJudgeUnit_BM()
{
}
public override NoteJudgeUnit ConvertToGameType(NoteBase attachedNote)
{
return new FullScreenNearTimeJudgeUnit(attachedNote);
}
}
}
}

View File

@@ -1,127 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
namespace Ichni.RhythmGame
{
public partial class NoteJudgeSubmodule : SubmoduleBase
{
public List<NoteJudgeUnit> judgeUnitList;
private NoteBase note => attachedGameElement as NoteBase;
public NoteJudgeSubmodule(NoteBase attachedGameElement) : base(attachedGameElement)
{
judgeUnitList = new List<NoteJudgeUnit>();
if (!HaveSameSubmodule)
{
this.note.noteJudgeSubmodule = this;
}
}
public NoteJudgeSubmodule(NoteBase attachedGameElement, List<NoteJudgeUnit_BM> judgeUnitList_BM) : base(attachedGameElement)
{
judgeUnitList = new List<NoteJudgeUnit>();
foreach (NoteJudgeUnit_BM judgeUnitBM in judgeUnitList_BM)
{
judgeUnitList.Add(judgeUnitBM.ConvertToGameType(attachedGameElement));
}
if (!HaveSameSubmodule)
{
this.note.noteJudgeSubmodule = this;
}
}
}
public partial class NoteJudgeSubmodule
{
public override void SaveBM()
{
matchedBM = new NoteJudgeSubmodule_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 effectNameInputField = inspector.GenerateInputField(submoduleSettings, "Judge Unit Name");
var addJudgeUnitButton = inspector.GenerateButton(this, submoduleSettings, "Add Judge Unit",
() =>
{
AddJudgeUnit(effectNameInputField.GetValue<string>());
inspectorMain.SetInspector(note);
});
foreach (var judgeUnit in judgeUnitList)
{
judgeUnit.SetUpInspector();
}
}
}
public partial class NoteJudgeSubmodule
{
private static Dictionary<string, Func<NoteJudgeUnit>> JudgeUnitCollection(NoteBase note) =>
new Dictionary<string, Func<NoteJudgeUnit>>()
{
{ "TouchArea",()=> new TouchAreaJudgeUnit(note, 600) },
{ "FullScreenNearTime",()=> new FullScreenNearTimeJudgeUnit(note) },
{ "TriggerConnect",()=> new TriggerConnectJudgeUnit(note, null) }
};
public NoteJudgeUnit AddJudgeUnit(string judgeUnitName)
{
if (JudgeUnitCollection(note).TryGetValue(judgeUnitName, out var newJudgeUnit))
{
judgeUnitList.Add(newJudgeUnit());
return newJudgeUnit();
}
else
{
LogWindow.Log("Judge Unit Type not found.", Color.red);
return null;
}
}
}
namespace Beatmap
{
public class NoteJudgeSubmodule_BM : Submodule_BM
{
public List<NoteJudgeUnit_BM> judgeUnitList;
public NoteJudgeSubmodule_BM()
{
}
public NoteJudgeSubmodule_BM(GameElement attachedElement, NoteJudgeSubmodule noteJudgeSubmodule) : base(attachedElement)
{
judgeUnitList = new List<NoteJudgeUnit_BM>();
foreach (var judgeUnit in noteJudgeSubmodule.judgeUnitList)
{
judgeUnitList.Add(judgeUnit.ConvertToBM());
}
}
public override void ExecuteBM()
{
attachedElement = GameElement_BM.GetElement(attachedElementGuid);
(attachedElement as NoteBase).noteJudgeSubmodule = new NoteJudgeSubmodule(attachedElement as NoteBase, judgeUnitList);
}
public override void DuplicateBM(GameElement attached)
{
(attached as NoteBase).noteJudgeSubmodule = new NoteJudgeSubmodule(attached as NoteBase, judgeUnitList);
}
}
}
}

View File

@@ -1,89 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
using UnityEngine.UI;
namespace Ichni.RhythmGame
{
public class TouchAreaJudgeUnit : NoteJudgeUnit
{
public float areaRadius;
protected override GameObject GetHintImagePrefab() => EditorManager.instance.basePrefabs.areaHint;
private float CurrentScreenRatio() => Screen.height / 1080f;
public TouchAreaJudgeUnit(NoteBase note, float areaRadius) : base(note)
{
this.areaRadius = areaRadius;
}
public override void UpdateJudge()
{
if (note is Hold hold)
{
if (hold.isFinalJudged) return;
}
else
{
if (note.isFirstJudged) return;
}
Vector2 noteScreenPosition = note.noteScreenPosition;
RectTransform canvasRect = EditorManager.instance.judgeHintCanvas.GetComponent<RectTransform>();
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRect, noteScreenPosition, null, out Vector2 uiPosition))
{
judgeHintImage.anchoredPosition = uiPosition;
judgeHintImage.sizeDelta = new Vector2(areaRadius * 2, areaRadius * 2) * CurrentScreenRatio();
}
}
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Touch Area Judge Unit");
var judgeModuleSettings = container.GenerateSubcontainer(3);
var isShowingJudgeField =
inspector.GenerateToggle(this, judgeModuleSettings, "Is Showing Judge", nameof(isShowingJudge))
.AddListenerFunction(() => SetShowingJudge(isShowingJudge));
var areaRadiusField = inspector.GenerateInputField(this, judgeModuleSettings, "Area Radius", nameof(areaRadius));
var removeButton = inspector.GenerateButton(this, judgeModuleSettings, "Remove", () =>
{
SetShowingJudge(false);
note.noteJudgeSubmodule.judgeUnitList.Remove(this);
inspectorMain.SetInspector(note);
});
}
public override NoteJudgeUnit_BM ConvertToBM()
{
return new TouchAreaJudgeUnit_BM(areaRadius);
}
}
namespace Beatmap
{
public class TouchAreaJudgeUnit_BM : NoteJudgeUnit_BM
{
public float areaRadius;
public TouchAreaJudgeUnit_BM()
{
}
public TouchAreaJudgeUnit_BM(float areaRadius)
{
this.areaRadius = areaRadius;
}
public override NoteJudgeUnit ConvertToGameType(NoteBase attachedNote)
{
return new TouchAreaJudgeUnit(attachedNote, areaRadius);
}
}
}
}

View File

@@ -1,108 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using TMPro;
using UnityEngine;
namespace Ichni.RhythmGame
{
public class TriggerConnectJudgeUnit : NoteJudgeUnit
{
public GameElement connectedJudgeTrigger;
protected override GameObject GetHintImagePrefab() => EditorManager.instance.basePrefabs.triggerHint;
public TriggerConnectJudgeUnit(NoteBase note, GameElement judgeTrigger) : base(note)
{
this.connectedJudgeTrigger = judgeTrigger;
}
protected override void SetShowingJudge(bool isShowing)
{
if(connectedJudgeTrigger == null) return;
base.SetShowingJudge(isShowing);
if (judgeHintImage != null)
{
judgeHintImage.GetComponent<TMP_Text>().text = connectedJudgeTrigger.elementName;
}
}
public override void UpdateJudge()
{
if(note.isFirstJudged || connectedJudgeTrigger == null) return;
Vector2 noteScreenPosition = note.noteScreenPosition;
RectTransform canvasRect = EditorManager.instance.judgeHintCanvas.GetComponent<RectTransform>();
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRect, noteScreenPosition, null, out Vector2 uiPosition))
{
judgeHintImage.anchoredPosition = uiPosition;
}
}
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Trigger Connect Judge Unit");
var judgeModuleSettings = container.GenerateSubcontainer(3);
var isShowingJudgeField =
inspector.GenerateToggle(this, judgeModuleSettings, "Is Showing Judge", nameof(isShowingJudge))
.AddListenerFunction(() => SetShowingJudge(isShowingJudge));
var triggerNameField = inspector.GenerateInputField(judgeModuleSettings, "Trigger Name");
var connectTriggerButton = inspector.GenerateButton(this, judgeModuleSettings, "Connect Trigger", () =>
{
GameElement trigger = EditorManager.instance.operationManager.FindingModule.FindGameElementByName(triggerNameField.GetValue<string>());
if (trigger is not IHaveNoteJudgeTriggerSubmodule)
{
LogWindow.Log("The element you are trying to connect is not a Note Judge Trigger.");
return;
}
connectedJudgeTrigger = trigger;
(trigger as IHaveNoteJudgeTriggerSubmodule).noteJudgeTriggerSubmodule.connectedNotes.Add(note);
});
var removeButton = inspector.GenerateButton(this, judgeModuleSettings, "Remove", () =>
{
SetShowingJudge(false);
note.noteJudgeSubmodule.judgeUnitList.Remove(this);
inspectorMain.SetInspector(note);
});
}
public override NoteJudgeUnit_BM ConvertToBM()
{
return new TriggerConnectJudgeUnit_BM(connectedJudgeTrigger.elementGuid);
}
}
namespace Beatmap
{
public class TriggerConnectJudgeUnit_BM : NoteJudgeUnit_BM
{
public Guid connectedTriggerID;
public TriggerConnectJudgeUnit_BM()
{
}
public TriggerConnectJudgeUnit_BM(Guid connectedTriggerID)
{
this.connectedTriggerID = connectedTriggerID;
}
public override NoteJudgeUnit ConvertToGameType(NoteBase attachedNote)
{
Debug.Log(GameElement_BM.GetElement(connectedTriggerID));
return new TriggerConnectJudgeUnit(attachedNote, GameElement_BM.GetElement(connectedTriggerID));
}
}
}
}

View File

@@ -1,28 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Ichni.RhythmGame
{
public abstract class NoteBadEffect : NoteEffectBase
{
}
namespace Beatmap
{
public abstract class NoteBadEffect_BM : NoteEffectBase_BM
{
public NoteBadEffect_BM()
{
}
public NoteBadEffect_BM(float effectTime) : base(effectTime)
{
}
}
}
}

View File

@@ -1,30 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
namespace Ichni.RhythmGame
{
public abstract class NoteEffectBase : EffectBase
{
public NoteBase note;
public NoteVisualBase noteVisual;
}
namespace Beatmap
{
public abstract class NoteEffectBase_BM : EffectBase_BM
{
public NoteEffectBase_BM()
{
}
public NoteEffectBase_BM(float effectTime) : base(effectTime)
{
}
}
}
}

View File

@@ -1,28 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Ichni.RhythmGame
{
public abstract class NoteGeneralJudgeEffect : NoteEffectBase
{
}
namespace Beatmap
{
public abstract class NoteGeneralJudgeEffect_BM : NoteEffectBase_BM
{
public NoteGeneralJudgeEffect_BM()
{
}
public NoteGeneralJudgeEffect_BM(float effectTime) : base(effectTime)
{
}
}
}
}

View File

@@ -1,28 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Ichni.RhythmGame
{
public abstract class NoteGoodEffect : NoteEffectBase
{
}
namespace Beatmap
{
public abstract class NoteGoodEffect_BM : NoteEffectBase_BM
{
public NoteGoodEffect_BM()
{
}
public NoteGoodEffect_BM(float effectTime) : base(effectTime)
{
}
}
}
}

View File

@@ -1,30 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Ichni.RhythmGame
{
public abstract class NoteHoldingEffect : NoteEffectBase
{
public float GetHoldingTime()
{
return (note as Hold).holdEndTime - note.exactJudgeTime;
}
}
namespace Beatmap
{
public abstract class NoteHoldingEffect_BM : NoteEffectBase_BM
{
public NoteHoldingEffect_BM()
{
}
public NoteHoldingEffect_BM(float effectTime) : base(effectTime)
{
}
}
}
}

View File

@@ -1,29 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Ichni.RhythmGame
{
public abstract class NoteMissEffect : NoteEffectBase
{
}
namespace Beatmap
{
public abstract class NoteMissEffect_BM : NoteEffectBase_BM
{
public NoteMissEffect_BM()
{
}
public NoteMissEffect_BM(float effectTime) : base(effectTime)
{
}
}
}
}

View File

@@ -1,29 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Ichni.RhythmGame.ThemeBundles.Basic;
using UnityEngine;
namespace Ichni.RhythmGame
{
public abstract class NotePerfectEffect : NoteEffectBase
{
}
namespace Beatmap
{
public abstract class NotePerfectEffect_BM : NoteEffectBase_BM
{
public NotePerfectEffect_BM()
{
}
public NotePerfectEffect_BM(float effectTime) : base(effectTime)
{
}
}
}
}

View File

@@ -1,122 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Dreamteck.Splines;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using Lean.Pool;
using Unity.VisualScripting;
using UnityEngine;
namespace Ichni.RhythmGame
{
public partial class Flick : NoteBase
{
public List<Vector2> availableFlickDirections;
public float flickBufferAngle = 60f;
public static Flick GenerateElement(string elementName, Guid id, List<string> tags, bool isFirstGenerated,
GameElement parentElement, float exactJudgeTime, List<Vector2> directions)
{
Flick flick = Instantiate(EditorManager.instance.basePrefabs.flickNote, parentElement.transform)
.GetComponent<Flick>();
flick.Initialize(elementName, id, tags, EditorManager.instance.useNotePrefab ? false : isFirstGenerated, parentElement);
flick.exactJudgeTime = exactJudgeTime;
flick.availableFlickDirections = directions;
if (parentElement.TryGetComponent(out Track track))
{
if (track.trackTimeSubmodule != null)
{
flick.track = track;
flick.trackPositioner = flick.AddComponent<SplinePositioner>();
flick.trackPositioner.spline = track.trackPathSubmodule.path;
flick.isOnTrack = true;
flick.UpdateNoteInTrack();
}
else
{
throw new System.Exception("如果Note要生成在Track上Track必须有TrackTimeSubmodule组件。");
}
}
else
{
flick.track = null;
flick.isOnTrack = false;
}
if (EditorManager.instance.useNotePrefab && isFirstGenerated)
{
EditorManager.instance.projectManager.notePrefabManager.LoadNotePrefab(flick, GetNoteTypeName(flick) + "_Prefab");
}
if (isFirstGenerated) flick.AfterInitialize();
return flick;
}
}
public partial class Flick
{
public override void SetDefaultSubmodules()
{
base.SetDefaultSubmodules();
noteAudioSubmodule ??= new NoteAudioSubmodule(this, "DefaultFlick");
}
public override void SaveBM()
{
matchedBM = new Flick_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM,
exactJudgeTime, availableFlickDirections);
}
public override void SetUpInspector()
{
base.SetUpInspector();
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
var flickSpecial = inspector.GenerateContainer("Flick Special");
var flickSpecialSubcontainer = flickSpecial.GenerateSubcontainer(3);
var availableDirectionsButton =
inspector.GenerateButton(this, flickSpecialSubcontainer, "Available Directions", () =>
{
var widthCurveWindow = inspector.GenerateCompositeParameterWindow(this, "Available Directions", nameof(availableFlickDirections));
widthCurveWindow.SetAsFlexibleFloat();
});
}
}
namespace Beatmap
{
public class Flick_BM : NoteBase_BM
{
public List<Vector2> availableFlickDirections;
public Flick_BM()
{
}
public Flick_BM(string elementName, Guid elementGuid, List<string> tags, GameElement_BM attachedElement,
float exactJudgeTime,
List<Vector2> directions) : base(elementName, elementGuid, tags, attachedElement, exactJudgeTime)
{
availableFlickDirections = directions;
}
public override void ExecuteBM()
{
matchedElement = Flick.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid), exactJudgeTime, availableFlickDirections);
}
public override GameElement DuplicateBM(GameElement parent)
{
return Flick.GenerateElement(elementName, Guid.NewGuid(), tags, false, parent,
exactJudgeTime, availableFlickDirections);
}
}
}
}

View File

@@ -1,344 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Dreamteck.Splines;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using UniRx;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.InputSystem;
namespace Ichni.RhythmGame
{
public partial class Hold : NoteBase
{
public static List<Hold> holdingHoldList = new();
public float holdEndTime;
public float holdingTime;
public bool isHolding;
public bool isFinalJudged;
public static Hold GenerateElement(string elementName, Guid id, List<string> tags, bool isFirstGenerated,
GameElement parentElement, float exactJudgeTime, float holdEndTime)
{
Hold hold = Instantiate(EditorManager.instance.basePrefabs.holdNote, parentElement.transform)
.GetComponent<Hold>();
hold.Initialize(elementName, id, tags, EditorManager.instance.useNotePrefab ? false : isFirstGenerated, parentElement);
hold.exactJudgeTime = exactJudgeTime;
hold.holdEndTime = holdEndTime;
hold.holdingTime = 0;
if (parentElement.TryGetComponent(out Track track))
{
if (track.trackTimeSubmodule != null)
{
hold.track = track;
hold.trackPositioner = hold.AddComponent<SplinePositioner>();
hold.trackPositioner.spline = track.trackPathSubmodule.path;
hold.trackPositioner.updateMethod = SplineUser.UpdateMethod.LateUpdate;
hold.isOnTrack = true;
hold.UpdateNoteInTrack();
Observable.NextFrame().Subscribe(_ =>
{
hold.UpdateNoteInTrack();
track.Refresh();
track.trackPathSubmodule?.path.RebuildImmediate();
});
}
else
{
throw new Exception("如果Note要生成在Track上Track必须有TrackTimeSubmodule组件。");
}
}
else
{
hold.track = null;
hold.isOnTrack = false;
}
if (EditorManager.instance.useNotePrefab && isFirstGenerated)
{
EditorManager.instance.projectManager.notePrefabManager.LoadNotePrefab(hold, GetNoteTypeName(hold) + "_Prefab");
}
if (isFirstGenerated) hold.AfterInitialize();
return hold;
}
}
public partial class Hold
{
public override void UpdateNoteInMovableTrack()
{
if (!isHolding && !isFinalJudged)
{
base.UpdateNoteInMovableTrack();
}
if (noteVisual is INoteVisualHold noteVisualHold)
{
noteVisualHold.UpdateHoldInMovableTrack();
}
}
public override void UpdateNoteInStaticTrack()
{
base.UpdateNoteInStaticTrack();
if (noteVisual is INoteVisualHold noteVisualHold)
{
noteVisualHold.UpdateHoldInStaticTrack();
}
}
}
public partial class Hold
{
public override void SetDefaultSubmodules()
{
base.SetDefaultSubmodules();
noteAudioSubmodule ??= new NoteAudioSubmodule(this, new List<string>() { "DefaultEndHold" },
new List<string>(), new List<string>(),
new List<string>(), new List<string>(),
new List<string>() { "DefaultStartHold" });
}
public override void SaveBM()
{
matchedBM = new Hold_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM, exactJudgeTime, holdEndTime);
}
public override void SetUpInspector()
{
base.SetUpInspector();
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
var holdSpecial = inspector.GenerateContainer("Hold");
var holdSpecialSubcontainer = holdSpecial.GenerateSubcontainer(3);
var holdEndTimeInputField = inspector.GenerateInputField(this, holdSpecialSubcontainer, "holdEndTime", nameof(holdEndTime), true);
var holdingTimeInputField = inspector.GenerateInputField(holdSpecialSubcontainer, "holdingTime", (holdEndTime - exactJudgeTime).ToString());
holdEndTimeInputField.AddListenerFunction(() =>
{
holdingTimeInputField.inputField.text = (holdEndTime - exactJudgeTime).ToString();
noteVisual?.effectSubmodule.effectCollection["Holding"].ForEach(effect =>
{
effect.effectTime = holdEndTime - exactJudgeTime;
});
});
holdingTimeInputField.AddListenerFunction(() =>
{
holdEndTime = float.Parse(holdingTimeInputField.inputField.text) + exactJudgeTime;
holdEndTimeInputField.inputField.text = holdEndTime.ToString();
holdEndTimeInputField.inputField.onEndEdit.Invoke(holdEndTimeInputField.inputField.text);
});
inspector.MarkedElements["ExactJudgeTime"].AddListenerFunction(() =>
{
noteVisual?.effectSubmodule.effectCollection["Holding"].ForEach(effect =>
{
effect.effectTime = holdEndTime - exactJudgeTime;
});
// 新增根据holdingTimeInputField的值更新holdEndTime
float holdingTimeValue;
if (float.TryParse(holdingTimeInputField.inputField.text, out holdingTimeValue))
{
holdEndTime = exactJudgeTime + holdingTimeValue;
holdEndTimeInputField.inputField.text = holdEndTime.ToString();
}
});
}
}
public partial class Hold
{
public override void Update()
{
if (Keyboard.current.hKey.wasPressedThisFrame)
{
foreach (KeyValuePair<string, List<EffectBase>> effect in noteVisual.effectSubmodule.effectCollection)
{
effect.Value.ForEach(x => x.Disrupt());
}
}
float songTime = EditorManager.instance.songInformation.songTime;
// 边界检查
if (holdEndTime < exactJudgeTime)
{
LogWindow.Log("Hold end time is earlier than exact judge time.", Color.red);
return;
}
// 1. 重置逻辑:当时间回退到判定时间之前
if (isFirstJudged && songTime < exactJudgeTime)
{
isFirstJudged = false;
isHolding = false;
isFinalJudged = false;
holdingTime = 0;
// 移除音频播放 - 重置时不应该播放任何音频
}
// 2. 状态恢复当时间从结束状态回退到hold区间内
if (isFinalJudged && songTime >= exactJudgeTime && songTime <= holdEndTime)
{
isFirstJudged = true;
isHolding = true;
isFinalJudged = false;
holdingTime = songTime - exactJudgeTime; // 修复更新holdingTime
}
// 3. 处理hold过程中的逻辑
if (isHolding)
{
holdingTime = songTime - exactJudgeTime;
// 检查hold是否结束
if (songTime >= holdEndTime && !isFinalJudged)
{
isHolding = false;
isFinalJudged = true;
// 可以考虑在这里播放hold结束的音频
// noteAudioSubmodule?.PlayHoldEndAudio();
}
}
// 4. 第一次判定:进入判定区间
if (!isFirstJudged && songTime >= exactJudgeTime)
{
isFirstJudged = true;
// 检查是否可以开始hold
if (songTime <= holdEndTime)
{
// 播放开始判定的音频
noteAudioSubmodule?.PlayNoteJudgeAudios(EditorManager.instance.currentJudgeType);
// 如果需要在这里播放hold开始音频
// noteAudioSubmodule.PlayHoldStartAudio();
isHolding = true;
holdingTime = songTime - exactJudgeTime;
}
}
if (noteJudgeSubmodule != null && !EditorManager.instance.cameraManager.isSceneCameraActive)
{
foreach (NoteJudgeUnit unit in noteJudgeSubmodule.judgeUnitList.Where(unit => unit.isShowingJudge))
{
unit.UpdateJudge();
}
}
if (noteVisual != null)
{
noteVisual.effectSubmodule.effectCollection["Generate"].ForEach(e => e.UpdateEffect(exactJudgeTime));
noteVisual.effectSubmodule.effectCollection["StartHold"].ForEach(e => e.UpdateEffect(exactJudgeTime));
noteVisual.effectSubmodule.effectCollection["Holding"].ForEach(e => e.UpdateEffect(exactJudgeTime));
noteVisual.effectSubmodule.effectCollection["GeneralJudge"].ForEach(e => e.UpdateEffect(holdEndTime));
switch (EditorManager.instance.currentJudgeType)
{
case NoteJudgeType.Perfect:
noteVisual.effectSubmodule.effectCollection["Perfect"].ForEach(e => e.UpdateEffect(holdEndTime));
break;
case NoteJudgeType.Good:
noteVisual.effectSubmodule.effectCollection["Good"].ForEach(e => e.UpdateEffect(holdEndTime));
break;
case NoteJudgeType.Bad:
noteVisual.effectSubmodule.effectCollection["Bad"].ForEach(e => e.UpdateEffect(holdEndTime));
break;
case NoteJudgeType.Miss:
noteVisual.effectSubmodule.effectCollection["Miss"].ForEach(e => e.UpdateEffect(holdEndTime));
break;
}
noteVisual.effectSubmodule.effectCollection["AfterJudge"].ForEach(e => e.UpdateEffect(holdEndTime));
if (EditorManager.instance.cameraManager.haveGameCamera)
{
noteScreenPosition = EditorManager.instance.cameraManager.gameCamera.gameCamera.WorldToScreenPoint(noteVisual.noteVisualPosition);
}
}
// 优化持有列表的添加和移除
if (isHolding)
{
if (!holdingHoldList.Contains(this))
holdingHoldList.Add(this);
}
else
{
if (holdingHoldList.Contains(this))
holdingHoldList.Remove(this);
}
}
public void SetFinishEffects()//一定在播放完之后再搞这个
{
noteVisual.effectSubmodule.effectCollection["Holding"].ForEach(e => e.Adjust());
// noteVisual.effectSubmodule.effectCollection["GeneralJudge"].ForEach(e => e.Adjust());
// switch (EditorManager.instance.currentJudgeType)
// {
// case NoteJudgeType.Perfect:
// noteVisual.effectSubmodule.effectCollection["Perfect"].ForEach(e => e.Adjust());
// break;
// case NoteJudgeType.Good:
// noteVisual.effectSubmodule.effectCollection["Good"].ForEach(e => e.Adjust());
// break;
// case NoteJudgeType.Bad:
// noteVisual.effectSubmodule.effectCollection["Bad"].ForEach(e => e.Adjust());
// break;
// case NoteJudgeType.Miss:
// noteVisual.effectSubmodule.effectCollection["Miss"].ForEach(e => e.Adjust());
// break;
// }
}
private void LateUpdate()
{
if (isOnTrack)
{
UpdateNoteInTrack();
}
}
}
namespace Beatmap
{
public class Hold_BM : NoteBase_BM
{
public float holdEndTime;
public Hold_BM()
{
}
public Hold_BM(string elementName, Guid elementGuid, List<string> tags, GameElement_BM attachedElement, float exactJudgeTime, float holdEndTime)
: base(elementName, elementGuid, tags, attachedElement, exactJudgeTime)
{
this.holdEndTime = holdEndTime;
}
public override void ExecuteBM()
{
matchedElement = Hold.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid), exactJudgeTime, holdEndTime);
}
public override GameElement DuplicateBM(GameElement parent)
{
return Hold.GenerateElement(elementName, Guid.NewGuid(), tags, false, parent, exactJudgeTime, holdEndTime);
}
}
}
}

View File

@@ -1,349 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Dreamteck.Splines;
using Ichni.Editor;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.Serialization;
namespace Ichni.RhythmGame
{
public abstract partial class NoteBase : GameElement, IHaveTimeDurationSubmodule, IComparable<NoteBase>
{
[Title("Basic Info")]
public float exactJudgeTime;
[Title("Track Info")]
public bool isOnTrack;
public Track track;
public SplinePositioner trackPositioner;
[Title("NoteVisual")]
public NoteVisualBase noteVisual;
[Title("Submodules")]
public TimeDurationSubmodule timeDurationSubmodule { get; set; }
public NoteJudgeSubmodule noteJudgeSubmodule { get; set; }
public NoteAudioSubmodule noteAudioSubmodule { get; set; }
[Title("In-Game Info")]
public Vector2 noteScreenPosition;
[FormerlySerializedAs("isJudged")] public bool isFirstJudged;
public override int HierarchyPriority => -10;
public override void Initialize(string name, Guid elementGuid, List<string> tags, bool isFirstGenerated, GameElement parentElement)
{
base.Initialize(name, elementGuid, tags, isFirstGenerated, parentElement);
Update();
}
public override void AfterInitialize()
{
base.AfterInitialize();
AddinNoteManager();
}
public void AddinNoteManager(bool isNewOne = true)
{
float beyondTime = 0f;
foreach (EffectBase effectBase in noteVisual.effectSubmodule.effectCollection["Generate"])
{
if (effectBase is NoteGenerateEffect ge)
{
ge.Recover();
beyondTime = Mathf.Max(beyondTime, ge.generateTime);
}
else
{
effectBase.Recover();
}
}
float finishTime = 0f;
List<EffectBase> finishEffects = new List<EffectBase>();
finishEffects.AddRange(noteVisual.effectSubmodule.effectCollection["GeneralJudge"]);
finishEffects.AddRange(noteVisual.effectSubmodule.effectCollection["Perfect"]);
finishEffects.AddRange(noteVisual.effectSubmodule.effectCollection["Good"]);
finishEffects.AddRange(noteVisual.effectSubmodule.effectCollection["Bad"]);
finishEffects.AddRange(noteVisual.effectSubmodule.effectCollection["Miss"]);
foreach (EffectBase effectBase in finishEffects)
{
finishTime = Mathf.Max(finishTime, effectBase.effectTime);
}
if (exactJudgeTime - beyondTime - 0.5f > -EditorManager.instance.songInformation.delay)
{
gameObject.SetActive(false);
// if (this is Hold hold)
// {
// EditorManager.instance.noteManager.RegisterNote(hold, hold.exactJudgeTime - beyondTime - 0.1f, + finishTime + 0.5f);
// }
if (isNewOne) EditorManager.instance.noteManager.RegisterNote(this, exactJudgeTime - beyondTime - 0.1f, (this is Hold hold ? hold.holdEndTime : exactJudgeTime) + finishTime + 0.1f);
else NoteManager.instance.ChangeNoteInfo(this, exactJudgeTime - beyondTime - 0.1f, (this is Hold hold ? hold.holdEndTime : exactJudgeTime) + finishTime + 0.1f);
}
}
/// <summary>
/// 在MovableTrack上更新Note的位置注意HoldNote需要重写这个方法
/// </summary>
public virtual void UpdateNoteInMovableTrack()
{
TrackTimeSubmoduleMovable trackTimeSubmoduleMovable = track.trackTimeSubmodule as TrackTimeSubmoduleMovable;
trackPositioner.SetPercent(trackTimeSubmoduleMovable.GetTrackPercent(exactJudgeTime));
}
/// <summary>
/// 在StaticTrack上更新Note的位置注意HoldNote需要重写这个方法
/// </summary>
public virtual void UpdateNoteInStaticTrack()
{
float songTime = EditorManager.instance.songInformation.songTime;
TrackTimeSubmoduleStatic trackTimeSubmoduleStatic = track.trackTimeSubmodule as TrackTimeSubmoduleStatic;
float startMove = exactJudgeTime - trackTimeSubmoduleStatic.trackTotalTime;
float percent = AnimationCurveEvaluator.Evaluate(trackTimeSubmoduleStatic.animationCurveType, (songTime - startMove) / trackTimeSubmoduleStatic.trackTotalTime);
percent = Mathf.Max(percent, 0);
percent = Mathf.Min(percent, 1);
trackPositioner.SetPercent(1 - percent);
}
public override void SetDefaultSubmodules()
{
timeDurationSubmodule ??= new TimeDurationSubmodule(this);
noteJudgeSubmodule ??= new NoteJudgeSubmodule(this);
}
public override void Refresh()
{
base.Refresh();
if (noteVisual != null)
{
noteVisual.Refresh();
}
AddinNoteManager(false);
foreach (SampleWindow i in SampleWindow.instances.Where(i => i.gameElement)) i.OnceSpawnNote();
}
public virtual void Update()
{
var editor = EditorManager.instance;
var cameraManager = editor.cameraManager;
float songTime = editor.songInformation.songTime;
// 轨道位置更新
if (isOnTrack && track.trackTimeSubmodule is TrackTimeSubmoduleStatic)
{
UpdateNoteInStaticTrack();
}
// 判定状态更新
if (isFirstJudged && songTime < exactJudgeTime)
{
isFirstJudged = false;
if (noteVisual != null) noteVisual.GetComponent<Collider>().enabled = !isFirstJudged;
}
else if (!isFirstJudged && songTime >= exactJudgeTime)
{
noteAudioSubmodule?.PlayNoteJudgeAudios(editor.currentJudgeType);
isFirstJudged = true;
if (noteVisual != null) noteVisual.GetComponent<Collider>().enabled = !isFirstJudged;
}
// 判定单元更新
if (noteJudgeSubmodule != null && !cameraManager.isSceneCameraActive)
{
foreach (var unit in noteJudgeSubmodule.judgeUnitList)
{
if (unit.isShowingJudge) unit.UpdateJudge();
}
}
// 视觉效果更新
if (noteVisual != null)
{
var effects = noteVisual.effectSubmodule.effectCollection;
UpdateEffectList(effects["Generate"]);
UpdateEffectList(effects["GeneralJudge"]);
if (editor.currentJudgeType == NoteJudgeType.Perfect)
{
UpdateEffectList(effects["Perfect"]);
}
else if (editor.currentJudgeType == NoteJudgeType.Good)
{
UpdateEffectList(this is Tap or Hold ? effects["Good"] : effects["Perfect"]);
}
else if (editor.currentJudgeType == NoteJudgeType.Bad)
{
UpdateEffectList(this is Tap or Hold ? effects["Bad"] : effects["Perfect"]);
}
else if (editor.currentJudgeType == NoteJudgeType.Miss)
{
UpdateEffectList(effects["Miss"]);
}
UpdateEffectList(effects["AfterJudge"]);
// 屏幕位置更新(降低频率)
if (cameraManager.haveGameCamera)//&& Time.frameCount % 3 == 0)
{
noteScreenPosition = cameraManager.gameCamera.gameCamera.WorldToScreenPoint(noteVisual.noteVisualPosition);
}
// 碰撞体状态
}
}
// 辅助方法:更新效果列表
private void UpdateEffectList(List<EffectBase> effects)
{
for (int i = 0; i < effects.Count; i++)
{
effects[i].UpdateEffect(exactJudgeTime);
}
}
public void ExecuteStartJudge()
{
}
public void UpdateNoteInTrack()
{
if (isOnTrack && track.trackTimeSubmodule != null)
{
if (track.trackTimeSubmodule is TrackTimeSubmoduleMovable)
{
UpdateNoteInMovableTrack();
}
else if (track.trackTimeSubmodule is TrackTimeSubmoduleStatic)
{
UpdateNoteInStaticTrack();
}
}
}
public override void SetUpInspector()
{
//
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Element Info");
//基础信息
var info = container.GenerateSubcontainer(3);
var nameInputField = inspector.GenerateInputField(this, info, GetType().Name + "'s Name", nameof(elementName));
var guidText = inspector.GenerateParameterText(this, info, "Element GUID", nameof(elementGuid));
var tagsListButton = inspector.GenerateButton(this, info, "Tags List", () =>
{
inspector.GenerateCompositeParameterWindow(this, "Tags List", nameof(tags)).SetAsStringList();
});
if (noteVisual != null)
{
noteVisual.transformSubmodule.SetUpInspector();
}
//次级模块
foreach (var submodule in submoduleList)
{
submodule.SetUpInspector();
}
//为了设置便捷Transform编辑手动更改原方法而不是用Base
var infoContainer = inspector.GenerateContainer("Note Info");
var noteBaseSettings = infoContainer.GenerateSubcontainer(3);
var exactJudgeTimeInputField =
inspector.GenerateInputField(this, noteBaseSettings, "exactJudgeTime", nameof(exactJudgeTime))
.AddListenerFunction(UpdateNoteInTrack).Mark("ExactJudgeTime");
var saveNotePrefabButton =
inspector.GenerateButton(this, noteBaseSettings, "Save Note Prefab", () =>
{
EditorManager.instance.projectManager.notePrefabManager.SaveNotePrefab(this, GetNoteTypeName(this) + "_Prefab");
});
var noteScreenPositionText = inspector.GenerateHintText(this, noteBaseSettings,
() => "Note Screen Position: " + noteScreenPosition);
var noteVisualContainer = inspector.GenerateContainer("Note Visual");
var noteVisualGeneration = noteVisualContainer.GenerateSubcontainer(3);
var generateNoteVisualButton = inspector.GenerateButton(this, noteVisualGeneration, "Generate Note Visual", () =>
{
TemporaryObject.GenerateElement("New Note Visual", Guid.NewGuid(), new List<string>(), true, this);
});
if (noteVisual != null)
{
generateNoteVisualButton.button.interactable = false;
}
}
public override void OnDelete()
{
base.OnDelete();
if (parentElement != null)
{
if (EditorManager.instance.uiManager.inspector.connectedGameElement == parentElement)
{
EditorManager.instance.uiManager.timeline.SetTimeLine(parentElement);
}
foreach (SampleWindow i in SampleWindow.instances.Where(i => i.gameElement)) i.OnceSpawnNote();
}
}
public int CompareTo(NoteBase other)
{
return exactJudgeTime.CompareTo(other.exactJudgeTime);
}
}
public abstract partial class NoteBase
{
public enum NoteJudgeType
{
Perfect,
Good,
Bad,
Miss
}
public static string GetNoteTypeName(NoteBase note)
{
return note switch
{
Tap => "Tap",
Stay => "Stay",
Hold => "Hold",
Flick => "Flick",
_ => throw new NotImplementedException("Note type not recognized")
};
}
}
namespace Beatmap
{
public abstract class NoteBase_BM : GameElement_BM
{
public float exactJudgeTime;
public NoteBase_BM()
{
}
public NoteBase_BM(string elementName, Guid elementGuid, List<string> tags, GameElement_BM attachedElement, float exactJudgeTime)
: base(elementName, elementGuid, tags, attachedElement)
{
this.exactJudgeTime = exactJudgeTime;
}
public override void ExecuteBM()
{
throw new NotImplementedException();
}
public override GameElement DuplicateBM(GameElement parent)
{
throw new NotImplementedException();
}
}
}
}

View File

@@ -1,107 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Ichni.Editor;
using UnityEngine;
using UnityEngine.Serialization;
namespace Ichni.RhythmGame
{
public abstract class NoteVisualBase : SubstantialObject, IHaveEffectSubmodule, IHaveSelectSubmodule
{
public NoteBase note;
public bool isHighlighted;
public GameObject noteMain;
public GameObject judgeEffect;
public List<GameObject> notePartList;
public List<GameObject> extraPartList;
public List<GameObject> effectPrefabList;
public virtual Vector3 noteVisualPosition => noteMain.transform.position;
public EffectSubmodule effectSubmodule { get; set; }
public SelectSubmodule selectSubmodule { get; set; }
public static NoteVisualBase GenerateElement(string elementName, Guid id, List<string> tags,
bool isFirstGenerated, string themeBundleName, string objectName, GameElement parentElement, bool isHighlighted)
{
NoteVisualBase noteVisual = SubstantialObject.GenerateElement(elementName, id, tags,
isFirstGenerated, themeBundleName, objectName, parentElement).GetComponent<NoteVisualBase>();
noteVisual.isHighlighted = isHighlighted;
noteVisual.SetHighlight();
noteVisual.SetEditorSubmodules();
return noteVisual;
}
public override void SetDefaultSubmodules()
{
base.SetDefaultSubmodules();
effectSubmodule = new EffectSubmodule(this, EffectSubmodule.EffectSubmodulePreset.Note);
}
public override void SetEditorSubmodules()
{
selectSubmodule ??= new SelectSubmodule(this, note);
}
public override void SetUpInspector()
{
base.SetUpInspector();
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Generate");
StandardInspectionElement.GenerateForTransform(this, container);
var settings = inspector.GenerateContainer("Settings");
var settingsSubcontainer = settings.GenerateSubcontainer(3);
var highlightToggle =
inspector.GenerateToggle(this, settingsSubcontainer, "Highlight", nameof(isHighlighted))
.AddListenerFunction(SetHighlight);
}
public virtual void Recover()
{
}
public virtual void SetHighlight()
{
}
}
namespace Beatmap
{
public abstract class NoteVisualBase_BM : SubstantialObject_BM
{
public bool isHighlighted;
public NoteVisualBase_BM()
{
}
public NoteVisualBase_BM(string elementName, Guid id, List<string> tags,
GameElement_BM parent, string themeBundleName, string objectName, bool isHighlighted) :
base(elementName, id, tags, parent, themeBundleName, objectName)
{
this.isHighlighted = isHighlighted;
}
public override void ExecuteBM()
{
throw new NotImplementedException();
}
public override GameElement DuplicateBM(GameElement parent)
{
throw new NotImplementedException();
}
}
}
}

View File

@@ -1,173 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Dreamteck.Splines;
using Ichni;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using Lean.Pool;
using Sirenix.OdinInspector;
using UnityEngine;
namespace Ichni.RhythmGame
{
public partial class PathNode : GameElement, IHaveTransformSubmodule, IHaveTimeDurationSubmodule, IHaveColorSubmodule, IHaveSelectSubmodule
{
public Track track;
public SplinePoint node;
public int index => track.trackPathSubmodule.pathNodeList.IndexOf(this);
public TransformSubmodule transformSubmodule { get; set; }
public TimeDurationSubmodule timeDurationSubmodule { get; set; }
public ColorSubmodule colorSubmodule { get; set; }
public bool haveEmissionColor => false;
public override int HierarchyPriority => -100;
public SelectSubmodule selectSubmodule { get; set; }
[Title("Editor独有参数")]
[SerializeField]
[HideInPlayMode]
private GameObject pathNodeSphere;
public bool isShowingSphere;
public static PathNode GenerateElement(string elementName, Guid id, List<string> tags, bool isFirstGenerated,
Track track, bool isShowingSphere, int index = -1)
{
PathNode pathNode = Instantiate(EditorManager.instance.basePrefabs.pathNode, track.transform)
.GetComponent<PathNode>();
pathNode.Initialize(elementName, id, tags, isFirstGenerated, track);
pathNode.track = track;
pathNode.isShowingSphere = isShowingSphere;
pathNode.SetPathNodeSphere(isShowingSphere);
if (index < 0)
{
track.trackPathSubmodule.pathNodeList.Add(pathNode);
}
else
{
track.trackPathSubmodule.pathNodeList.Insert(index, pathNode);
}
pathNode.SetEditorSubmodules();
return pathNode;
}
public override void SetDefaultSubmodules()
{
transformSubmodule = new TransformSubmodule(this);
timeDurationSubmodule = new TimeDurationSubmodule(this);
colorSubmodule = new ColorSubmodule(this);
}
public override void SetEditorSubmodules()
{
selectSubmodule ??= new SelectSubmodule(this, this);
}
public override void AfterInitialize()
{
base.AfterInitialize();
Refresh();
}
}
public partial class PathNode
{
public override void Refresh()
{
base.Refresh();
Vector3 position = transformSubmodule.currentPosition;
Vector3 normal = Quaternion.Euler(transformSubmodule.currentEulerAngles) * Vector3.up;
float size = transformSubmodule.currentScale.x;
Color color = colorSubmodule.currentBaseColor;
MaterialPropertyBlock materialPropertyBlock = new MaterialPropertyBlock();
materialPropertyBlock.SetColor("_Color", color);
pathNodeSphere.GetComponent<Renderer>()?.SetPropertyBlock(materialPropertyBlock);
transform.localPosition = position;
transform.localRotation = Quaternion.LookRotation(normal);
transform.localScale = Vector3.one * size;
node = new SplinePoint(position, Vector3.up, normal, size, color);
track.trackPathSubmodule.SetPathNode(this);
}
public void OnDestroy()
{
track.trackPathSubmodule.pathNodeList.Remove(this);
track.trackPathSubmodule.SetPathPoints();
track.Refresh();
//print("PathNode " + elementName + " destroyed.");
}
}
public partial class PathNode
{
public override void SaveBM()
{
matchedBM = new Beatmap.PathNode_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM, isShowingSphere);
}
public void SetPathNodeSphere(bool isShowing)
{
isShowingSphere = isShowing;
pathNodeSphere.SetActive(isShowing);
}
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
base.SetUpInspector();
var container = inspector.GenerateContainer("Path Node");
var pathNodeSettings = container.GenerateSubcontainer(3);
var indexText = inspector.GenerateHintText(this, pathNodeSettings, "Index: " + index);
var isShowingSphereToggle =
inspector.GenerateToggle(this, pathNodeSettings, "Is Showing Sphere", nameof(isShowingSphere))
.AddListenerFunction(() => SetPathNodeSphere(isShowingSphere));
var generateAnimation = container.GenerateSubcontainer(3);
StandardInspectionElement.GenerateForTransform(this, container);
var generateBaseColorChangeButton = inspector.GenerateButton(this, generateAnimation, "Base Color Change",
() => BaseColorChange.GenerateElement("New Base Color Change", Guid.NewGuid(), new List<string>(), true,
this,
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.r, colorSubmodule.originalBaseColor.r, animationCurveType: AnimationCurveType.Linear) }),
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.g, colorSubmodule.originalBaseColor.g, animationCurveType: AnimationCurveType.Linear) }),
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.b, colorSubmodule.originalBaseColor.b, animationCurveType: AnimationCurveType.Linear) }),
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.a, colorSubmodule.originalBaseColor.a, animationCurveType: AnimationCurveType.Linear) })
));
}
}
namespace Beatmap
{
public class PathNode_BM : GameElement_BM
{
public bool isShowingSphere;
public PathNode_BM()
{
}
public PathNode_BM(string elementName, Guid elementGuid, List<string> tags, GameElement_BM attachedElement,
bool isShowingSphere)
: base(elementName, elementGuid, tags, attachedElement)
{
this.isShowingSphere = isShowingSphere;
}
public override void ExecuteBM()
{
matchedElement = PathNode.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid) as Track, isShowingSphere);
}
public override GameElement DuplicateBM(GameElement parent)
{
return PathNode.GenerateElement(elementName, Guid.NewGuid(), tags, false, parent as Track, isShowingSphere);
}
}
}
}

View File

@@ -1,195 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Dreamteck.Splines;
using Ichni.Editor;
using Ichni.RhythmGame;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
namespace Ichni.RhythmGame
{
public partial class CrossTrackPoint : GameElement, IHaveTimeDurationSubmodule
{
public ElementFolder trackListFolder;
public Track nowAttachedTrack;
private int nowAttachedTrackIndex;
public SplinePositioner trackPositioner;
public FlexibleInt trackSwitch;
public FlexibleFloat trackPercent;
public TimeDurationSubmodule timeDurationSubmodule { get; set; }
public bool MotionAngles = false;
public static CrossTrackPoint GenerateElement(string elementName, Guid id, List<string> tags,
bool isFirstGenerated, ElementFolder elementFolder, FlexibleInt trackSwitch, FlexibleFloat trackPercent)
{
CrossTrackPoint point = Instantiate(EditorManager.instance.basePrefabs.emptyObject, elementFolder.transform)
.AddComponent<CrossTrackPoint>();
point.Initialize(elementName, id, tags, isFirstGenerated, elementFolder);
point.trackPositioner = point.gameObject.AddComponent<SplinePositioner>();
point.nowAttachedTrackIndex = -1;
point.trackListFolder = elementFolder;
point.trackSwitch = trackSwitch;
point.trackPercent = trackPercent;
point.trackPositioner.motion.rotationOffset = Vector3.zero;
point.trackPositioner.motion.applyRotation = false;
return point;
}
public override void SetDefaultSubmodules()
{
timeDurationSubmodule = new TimeDurationSubmodule(this);
}
private void Update()
{
if (trackPercent.animations.Count > 0)
{
trackSwitch.UpdateFlexibleInt(EditorManager.instance.songInformation.songTime);
trackPercent.UpdateFlexibleFloat(EditorManager.instance.songInformation.songTime);
SetPoint();
}
}
private void SetPoint()
{
if (nowAttachedTrackIndex != trackSwitch.value &&
trackSwitch.value >= 0 &&
trackSwitch.value < trackListFolder.trackList.Count)
{
nowAttachedTrack = trackListFolder.trackList[trackSwitch.value];
nowAttachedTrackIndex = trackSwitch.value;
trackPositioner.spline = trackListFolder.trackList[trackSwitch.value].trackPathSubmodule.path;
}
trackPositioner.SetPercent(trackPercent.value);
}
private void PasteTrackList()
{
List<Track> trackList = (parentElement as ElementFolder).trackList;
trackSwitch = new FlexibleInt();
trackPercent = new FlexibleFloat();
foreach (Track track in trackList)
{
TrackTimeSubmoduleMovable trackTimeSubmodule = track.trackTimeSubmodule as TrackTimeSubmoduleMovable;
trackSwitch.animations.Add(new AnimatedInt(trackTimeSubmodule.trackStartTime,
trackList.IndexOf(track)));
trackPercent.animations.Add(new AnimatedFloat(trackTimeSubmodule.trackStartTime,
trackTimeSubmodule.trackEndTime, 0, 1, trackTimeSubmodule.animationCurveType));
}
}
}
public partial class CrossTrackPoint
{
public override void SaveBM()
{
matchedBM = new CrossTrackPoint_BM(elementName, elementGuid, tags,
parentElement.matchedBM as GameElement_BM, trackSwitch, trackPercent)
{
MotionAngles = this.MotionAngles
};
}
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
base.SetUpInspector();
var container = inspector.GenerateContainer("Cross Track Point");
var pointSettings = container.GenerateSubcontainer(3);
var trackSwitchButton = inspector.GenerateButton(this, pointSettings, "Track Switch", () =>
{
inspector.GenerateCompositeParameterWindow(this, "Track Switch", nameof(trackSwitch)).SetAsFlexibleInt();
});
var trackPercentButton = inspector.GenerateButton(this, pointSettings, "Track Percent", () =>
{
inspector.GenerateCompositeParameterWindow(this, "Track Percent", nameof(trackPercent)).SetAsFlexibleFloat();
});
var pasteTrackListButton = inspector.GenerateButton(this, pointSettings, "Paste Track List", PasteTrackList);
// 新增MotionAngles开关
var motionAnglesToggle = inspector.GenerateToggle(this, pointSettings, "Motion With Angles", nameof(MotionAngles));
var generation = container.GenerateSubcontainer(3);
var generateCameraButton = inspector.GenerateButton(this, generation, "Game Camera",
() => GameCamera.GenerateElement("New Game Camera", Guid.NewGuid(), new List<string>(),
true, this, GameCamera.CameraViewType.Perspective, 60, 10));
var generateTrailButton = inspector.GenerateButton(this, generation, "Trail",
() => Trail.GenerateElement("New Trail", Guid.NewGuid(), new List<string>(),
true, this, 1, true, 1,
AnimationCurve.Constant(0, 1, 1), ColorExtensions.DefaultGradient(), "", ""));
var environmentObjectButton = inspector.GenerateButton(this, generation, "Environment Object",
() => TemporaryObject.GenerateElement("New Environment Object", Guid.NewGuid(), new List<string>(),
true, this));
var generateParticleEmitterButton = inspector.GenerateButton(this, generation, "Generate Particle Emitter", () =>
{
ParticleEmitter.GenerateElement("New Particle Emitter", Guid.NewGuid(), new List<string>(), true,
this, "", "",false,0, 1, ParticleSystemSimulationSpace.World,
10, 5, 1, 1 ,true, Vector3.zero);
});
}
public override void Refresh()
{
base.Refresh();
if (trackPositioner != null && trackPositioner.motion != null)
trackPositioner.motion.applyRotation = MotionAngles;
this.transform.eulerAngles = Vector3.zero;
}
}
namespace Beatmap
{
public class CrossTrackPoint_BM : GameElement_BM
{
public FlexibleInt trackSwitch;
public FlexibleFloat trackPercent;
public bool MotionAngles = false;
public CrossTrackPoint_BM()
{
}
public CrossTrackPoint_BM(string elementName, Guid elementGuid, List<string> tags,
GameElement_BM attachedElement, FlexibleInt trackSwitch, FlexibleFloat trackPercent)
: base(elementName, elementGuid, tags, attachedElement)
{
this.trackSwitch = trackSwitch;
this.trackPercent = trackPercent;
}
public override void ExecuteBM()
{
var element = CrossTrackPoint.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid) as ElementFolder, trackSwitch, trackPercent);
matchedElement = element;
// 还原MotionAngles
if (element is CrossTrackPoint ctp && this != null)
{
ctp.MotionAngles = this.MotionAngles;
}
}
public override GameElement DuplicateBM(GameElement parent)
{
var newElement = CrossTrackPoint.GenerateElement(elementName, Guid.NewGuid(), tags, false,
parent as ElementFolder, trackSwitch, trackPercent);
// 复制MotionAngles
if (newElement is CrossTrackPoint ctp)
{
ctp.MotionAngles = this.MotionAngles;
}
return newElement;
}
}
}
}

View File

@@ -1,132 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Dreamteck.Splines;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using Lean.Pool;
using UnityEngine;
using UnityEngine.Serialization;
namespace Ichni.RhythmGame
{
public partial class TrackHeadPoint : GameElement, IHaveTimeDurationSubmodule
{
public Track track;
public TrackTimeSubmoduleMovable trackTimeSubmoduleMovable;
public SplinePositioner trackPositioner;
public TimeDurationSubmodule timeDurationSubmodule { get; set; }
public bool motionApplyRotation;
public Vector3 motionEulerAngles;
private float SongTime => EditorManager.instance.songInformation.songTime;
public static TrackHeadPoint GenerateElement(string elementName, Guid id, List<string> tags,
bool isFirstGenerated, Track track, bool motionApplyRotation, Vector3 motionEulerAngles)
{
TrackHeadPoint head = Instantiate(EditorManager.instance.basePrefabs.emptyObject, track.transform).AddComponent<TrackHeadPoint>();
head.Initialize(elementName, id, tags, isFirstGenerated, track);
head.track = track;
head.trackPositioner = head.gameObject.AddComponent<SplinePositioner>();
head.trackPositioner.spline = track.trackPathSubmodule.path;
head.trackTimeSubmoduleMovable = track.trackTimeSubmodule as TrackTimeSubmoduleMovable;
head.motionApplyRotation = motionApplyRotation;
head.trackPositioner.motion.applyRotation = motionApplyRotation;
head.motionEulerAngles = motionEulerAngles;
head.trackPositioner.motion.rotationOffset = motionEulerAngles;
return head;
}
public override void SetDefaultSubmodules()
{
timeDurationSubmodule = new TimeDurationSubmodule(this);
}
public void Update()
{
if (track.timeDurationSubmodule.CheckTimeInDuration(SongTime))
{
trackPositioner.SetPercent(trackTimeSubmoduleMovable.headPercent);
}
}
}
public partial class TrackHeadPoint
{
public override void SaveBM()
{
// 保存MotionAngles到BM
matchedBM = new TrackHeadPoint_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM,
motionApplyRotation, motionEulerAngles);
}
public override void SetUpInspector()
{
base.SetUpInspector();
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Track Percent Point");
var motionAngles0 = container.GenerateSubcontainer(3);
var motionAnglesApplyToggle = inspector.GenerateToggle(this, motionAngles0, "Motion With Angles", nameof(motionApplyRotation))
.AddListenerFunction(() => trackPositioner.motion.applyRotation = motionApplyRotation);
var motionAngles1 = container.GenerateSubcontainer(1);
var motionAnglesValueInputField = inspector.GenerateVector3InputField(this, motionAngles1, "Motion Angles", nameof(motionEulerAngles))
.AddListenerFunction(()=> trackPositioner.motion.rotationOffset = motionEulerAngles);
var generation = container.GenerateSubcontainer(3);
var generateTrailButton = inspector.GenerateButton(this, generation, "Generate Trail", () =>
{
Trail.GenerateElement("New Trail", Guid.NewGuid(), new List<string>(), true,
this, 1, true, 1,
AnimationCurve.Constant(0, 1, 1), ColorExtensions.DefaultGradient(), "", "");
});
var environmentObjectButton = inspector.GenerateButton(this, generation, "Environment Object",
() => TemporaryObject.GenerateElement("New Environment Object", Guid.NewGuid(), new List<string>(),
true, this));
var generateParticleEmitterButton = inspector.GenerateButton(this, generation, "Generate Particle Emitter", () =>
{
ParticleEmitter.GenerateElement("New Particle Emitter", Guid.NewGuid(), new List<string>(), true,
this, "", "",false,0, 1, ParticleSystemSimulationSpace.World,
10, 5, 1, 1 ,true, Vector3.zero);
});
}
}
namespace Beatmap
{
public class TrackHeadPoint_BM : GameElement_BM
{
// 新增属性
public bool motionApplyRotation = false;
public Vector3 motionEulerAngles = Vector3.zero;
public TrackHeadPoint_BM()
{
}
public TrackHeadPoint_BM(string elementName, Guid elementGuid, List<string> tags,
GameElement_BM attachedElement, bool motionApplyRotation, Vector3 motionEulerAngles)
: base(elementName, elementGuid, tags, attachedElement)
{
this.motionApplyRotation = motionApplyRotation;
this.motionEulerAngles = motionEulerAngles;
}
public override void ExecuteBM()
{
matchedElement = TrackHeadPoint.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid) as Track, motionApplyRotation, motionEulerAngles);
}
public override GameElement DuplicateBM(GameElement parent)
{
return TrackHeadPoint.GenerateElement(elementName, Guid.NewGuid(), tags,
false, parent as Track, motionApplyRotation, motionEulerAngles);
}
}
}
}

View File

@@ -1,164 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Dreamteck.Splines;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using Lean.Pool;
using UniRx;
using UnityEngine;
namespace Ichni.RhythmGame
{
/// <summary>
/// 在轨道上根据百分比进行运动的点
/// </summary>
public partial class TrackPercentPoint : GameElement, IHaveTimeDurationSubmodule
{
public Track track;
public SplinePositioner trackPositioner;
public FlexibleFloat trackPercent;
public TimeDurationSubmodule timeDurationSubmodule { get; set; }
public bool MotionAngles = false;
public static TrackPercentPoint GenerateElement(string elementName, Guid id, List<string> tags,
bool isFirstGenerated,
Track track, FlexibleFloat trackPercent)
{
TrackPercentPoint point = Instantiate(EditorManager.instance.basePrefabs.emptyObject, track.transform)
.AddComponent<TrackPercentPoint>();
point.Initialize(elementName, id, tags, isFirstGenerated, track);
point.track = track;
point.trackPositioner = point.gameObject.AddComponent<SplinePositioner>();
point.trackPositioner.spline = track.trackPathSubmodule.path;
point.trackPercent = trackPercent;
point.trackPositioner.motion.rotationOffset = Vector3.zero;
point.trackPositioner.motion.applyRotation = false;
return point;
}
public override void SetDefaultSubmodules()
{
timeDurationSubmodule = new TimeDurationSubmodule(this);
}
public void Update()
{
if (trackPercent.animations.Count > 0)
{
trackPercent.UpdateFlexibleFloat(EditorManager.instance.songInformation.songTime);
if (trackPercent.returnType == FlexibleReturnType.MiddleExecuting)
{
float finalValue = trackPercent.value;
if (finalValue > 1 && finalValue > Mathf.Floor(finalValue)) finalValue -= Mathf.Floor(finalValue);
trackPositioner.SetPercent(finalValue);
}
}
}
}
public partial class TrackPercentPoint
{
public override void SaveBM()
{
matchedBM = new TrackPercentPoint_BM(elementName, elementGuid, tags,
parentElement.matchedBM as GameElement_BM,
trackPercent.ConvertToBM());
((TrackPercentPoint_BM)matchedBM).MotionAngles = this.MotionAngles;
}
public override void SetUpInspector()
{
base.SetUpInspector();
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Track Percent Point");
var pointSettings = container.GenerateSubcontainer(3);
var trackPercentButton = inspector.GenerateButton(this, pointSettings, "Track Percent",
() => { inspector.GenerateCompositeParameterWindow(this, "Track Percent", nameof(trackPercent)).SetAsFlexibleFloat(); });
// 新增MotionAngles开关
var motionAnglesToggle = inspector.GenerateToggle(this, pointSettings, "Motion With Angles", nameof(MotionAngles));
var generation = container.GenerateSubcontainer(3);
var generateTrailButton = inspector.GenerateButton(this, generation, "Generate Trail", () =>
{
Trail.GenerateElement("New Trail", Guid.NewGuid(), new List<string>(), true,
this, 1, true, 1,
AnimationCurve.Constant(0, 1, 1), ColorExtensions.DefaultGradient(), "", "");
});
var environmentObjectButton = inspector.GenerateButton(this, generation, "Environment Object",
() => TemporaryObject.GenerateElement("New Environment Object", Guid.NewGuid(), new List<string>(),
true, this));
var generateParticleEmitterButton = inspector.GenerateButton(this, generation, "Generate Particle Emitter", () =>
{
ParticleEmitter.GenerateElement("New Particle Emitter", Guid.NewGuid(), new List<string>(), true,
this, "", "", false, 0, 1, ParticleSystemSimulationSpace.World,
10, 5, 1, 1, true, Vector3.zero);
});
}
public override void Refresh()
{
base.Refresh();
this.transform.eulerAngles = Vector3.zero;
if (trackPositioner != null && trackPositioner.motion != null)
trackPositioner.motion.applyRotation = MotionAngles;
}
}
namespace Beatmap
{
public class TrackPercentPoint_BM : GameElement_BM
{
public FlexibleFloat_BM trackPercent;
public bool MotionAngles = false;
public TrackPercentPoint_BM()
{
}
public TrackPercentPoint_BM(string elementName, Guid elementGuid, List<string> tags,
GameElement_BM attachedElement, FlexibleFloat_BM trackPercent)
: base(elementName, elementGuid, tags, attachedElement)
{
this.trackPercent = trackPercent;
}
public override void ExecuteBM()
{
var element = TrackPercentPoint.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid) as Track, trackPercent.ConvertToGameType());
matchedElement = element;
// 还原MotionAngles
if (element is TrackPercentPoint tpp && this != null)
{
tpp.MotionAngles = this.MotionAngles;
}
}
public override GameElement DuplicateBM(GameElement parent)
{
var newElement = TrackPercentPoint.GenerateElement(elementName, Guid.NewGuid(), tags, false,
parent as Track, trackPercent.ConvertToGameType());
// 复制MotionAngles
if (newElement is TrackPercentPoint tpp)
{
tpp.MotionAngles = this.MotionAngles;
}
return newElement;
}
}
}
}

View File

@@ -1,204 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Dreamteck.Splines;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using Unity.VisualScripting;
using UnityEngine;
namespace Ichni.RhythmGame
{
public partial class TrackPathSubmodule : TrackSubmodule
{
public SplineComputer path;
public SplineRenderer trackDisplay;
public List<PathNode> pathNodeList;
public Track.TrackSpaceType trackSpaceType;
public Track.TrackSamplingType trackSamplingType;
public bool isClosed;
public bool isShowingDisplay;
public TrackPathSubmodule(Track track, Track.TrackSpaceType trackSpaceType,
Track.TrackSamplingType trackSamplingType, bool isClosed, bool isShowingDisplay) : base(track)
{
this.path = track.AddComponent<SplineComputer>();
this.pathNodeList = new List<PathNode>();
this.trackSpaceType = trackSpaceType;
this.trackSamplingType = trackSamplingType;
this.isClosed = isClosed;
this.path.sampleRate = 16;
this.path.updateMode = SplineComputer.UpdateMode.LateUpdate;
SetUpSplineComputer(this.trackSpaceType, this.trackSamplingType);
//闭合路径在PathNode生成时执行在初始化的情况下PathNode数量为0不会执行闭合操作
this.isShowingDisplay = isShowingDisplay;
this.trackDisplay = UnityEngine.Object.Instantiate(EditorManager.instance.basePrefabs.trackDisplay, track.transform).GetComponent<SplineRenderer>();
this.trackDisplay.spline = path;
this.trackDisplay.size = 0.1f;
this.SetDisplay(isShowingDisplay);
if (!HaveSameSubmodule)
{
this.track.trackPathSubmodule = this;
}
}
}
public partial class TrackPathSubmodule
{
private void SetUpSplineComputer(Track.TrackSpaceType trackSpaceType, Track.TrackSamplingType trackSamplingType)
{
path.type = (Spline.Type)trackSpaceType;
path.sampleMode = (SplineComputer.SampleMode)(int)trackSamplingType;
path.space = SplineComputer.Space.Local;
}
public void ClosePath()
{
if (isClosed && pathNodeList.Count > 2)
{
path.Close();
}
else
{
path.Break();
}
}
public void SetTrackSpaceType(int spaceType)
{
int SpaceType = spaceType;
if (spaceType == 2) SpaceType++;
trackSpaceType = (Track.TrackSpaceType)SpaceType;
path.type = (Spline.Type)SpaceType;
}
public void SetPathNode(PathNode point)
{
path.SetPoint(point.index, point.node, SplineComputer.Space.Local);
}
public void SetDisplay(bool isShowing)
{
this.isShowingDisplay = isShowing;
trackDisplay.gameObject.SetActive(isShowing);
}
public override void Refresh()
{
EditorRefresh();
path.Rebuild(true);
}
public void EditorRefresh()
{
SetTrackSpaceType((int)trackSpaceType);
SetUpSplineComputer(trackSpaceType, trackSamplingType);
ClosePath();
}
public void SortPathnodeInChildren()//emm待用吧
{
Debug.Log("TrackSort");
track.childElementList.Sort((x, y) =>
{
// 处理两个都是索引类的情况
if (x is PathNode idxX && y is PathNode idxY)
return idxX.index.CompareTo(idxY.index);
// 处理两个都是非索引类的情况 - 保持原顺序
if (x is not PathNode && y is not PathNode)
return 0;
// 混合类型处理:索引类排在前面
return x is PathNode ? 1 : -1;
});
}
}
public partial class TrackPathSubmodule
{
public void SetPathPoints()
{
path.SetPoints(new SplinePoint[0]);
foreach (var pathNode in pathNodeList)
{
SetPathNode(pathNode);
}
}
public override void SaveBM()
{
matchedBM = new TrackPathSubmodule_BM(attachedGameElement, this);
}
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Track Path");
var trackPathSubmoduleSettings = container.GenerateSubcontainer(3);
var trackSpaceDropdown =
inspector.GenerateDropdown(this, trackPathSubmoduleSettings, "Space Type", typeof(Track.TrackSpaceType), nameof(trackSpaceType));
var trackSamplingDropdown =
inspector.GenerateDropdown(this, trackPathSubmoduleSettings, "Sampling Type", typeof(Track.TrackSamplingType), nameof(trackSamplingType));
var isClosedToggle =
inspector.GenerateToggle(this, trackPathSubmoduleSettings, "Is Closed", nameof(isClosed))
.AddListenerFunction(ClosePath);
var generatePathNodeButton = inspector.GenerateButton(this, trackPathSubmoduleSettings, "Generate Path Node", () =>
{
PathNode.GenerateElement("New Path Node", Guid.NewGuid(), new List<string>(), true, track, true);
});
var showDisplayToggle = inspector.GenerateToggle(this, trackPathSubmoduleSettings, "Show Display", nameof(isShowingDisplay))
.AddListenerFunction(() => SetDisplay(isShowingDisplay));
}
}
namespace Beatmap
{
public class TrackPathSubmodule_BM : Submodule_BM
{
public Track.TrackSpaceType trackSpaceType;
public Track.TrackSamplingType trackSamplingType;
public bool isClosed;
public bool isShowingDisplay;
public TrackPathSubmodule_BM()
{
}
public TrackPathSubmodule_BM(GameElement attachedElement, TrackPathSubmodule trackPathSubmodule) : base(
attachedElement)
{
this.trackSpaceType = trackPathSubmodule.trackSpaceType;
this.trackSamplingType = trackPathSubmodule.trackSamplingType;
this.isClosed = trackPathSubmodule.isClosed;
this.isShowingDisplay = trackPathSubmodule.isShowingDisplay;
}
public override void ExecuteBM()
{
attachedElement = GameElement_BM.GetElement(attachedElementGuid);
Track track = attachedElement as Track;
track.trackPathSubmodule = new TrackPathSubmodule(track, trackSpaceType, trackSamplingType, isClosed, isShowingDisplay);
}
public override void DuplicateBM(GameElement attached)
{
Track track = attached as Track;
track.trackPathSubmodule = new TrackPathSubmodule(track, trackSpaceType, trackSamplingType, isClosed, isShowingDisplay);
}
}
}
}

View File

@@ -1,591 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Dreamteck.Splines;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using Unity.VisualScripting;
using UnityEngine;
using Inspector = Ichni.Editor.Inspector;
using Object = UnityEngine.Object;
namespace Ichni.RhythmGame
{
public partial class TrackRendererSubmodule : TrackSubmodule
{
protected int submoduleNameIndex = 0;
protected readonly string[] submoduleName = { "Auto Orient", "Path Generator", "Tube Generator", "Surface" };
public MeshGenerator meshGenerator;
public MeshRenderer meshRenderer;
public Material renderMaterial;
public string materialThemeBundleName;
public string materialName;
public bool enableEmission;
public float emissionIntensity;
public bool zWrite;
public Vector2 uvScale;
public Vector2 uvOffset;
public TrackRendererSubmodule(Track track, bool enableEmission, float emissionIntensity, bool zWrite,
Vector2 uvScale, Vector2 uvOffset) : base(track)
{
this.enableEmission = enableEmission;
this.emissionIntensity = emissionIntensity;
this.materialThemeBundleName = String.Empty;
this.materialName = String.Empty;
this.zWrite = zWrite;
this.uvScale = uvScale;
this.uvOffset = uvOffset;
if (!HaveSameSubmodule)
{
this.track.trackRendererSubmodule = this;
}
}
public void ApplyMaterial(string materialThemeBundleName, string materialName)
{
this.materialThemeBundleName = materialThemeBundleName;
this.materialName = materialName;
Material mat = ThemeBundleManager.instance.GetObject<Material>(materialThemeBundleName, materialName);
if (mat == null)
{
mat = EditorManager.instance.basePrefabs.defaultTrackMaterial;
}
renderMaterial = mat;
meshRenderer.material = renderMaterial;
}
public override void Refresh()
{
// 使用 MaterialPropertyBlock 替代直接操作 material
var block = new MaterialPropertyBlock();
meshRenderer.GetPropertyBlock(block);
// ZWrite
block.SetFloat("_ZWrite", zWrite ? 1f : 0f);
// Emission
if (enableEmission)
{
meshRenderer.material.EnableKeyword("_EMISSION_ON");
block.SetColor("_EmissionColor", Color.white * Mathf.Pow(2, emissionIntensity));
}
else
{
meshRenderer.material.DisableKeyword("_EMISSION_ON");
block.SetColor("_EmissionColor", Color.black);
}
// UV仍然直接设置到 meshGenerator
SetUV();
meshRenderer.SetPropertyBlock(block);
if (track.trackTimeSubmodule is TrackTimeSubmoduleMovable trackTimeSubmoduleMovable)
{
meshGenerator.clipFrom = trackTimeSubmoduleMovable.tailPercent;
meshGenerator.clipTo = trackTimeSubmoduleMovable.headPercent;
}
else
{
meshGenerator.clipFrom = 0;
meshGenerator.clipTo = 1;
}
}
public override void OnDelete()
{
base.OnDelete();
Object.Destroy(meshGenerator);
Object.Destroy(meshRenderer);
}
public override void SaveBM()
{
throw new System.NotImplementedException();
}
}
public partial class TrackRendererSubmodule
{
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Track Renderer " + submoduleName[submoduleNameIndex] + (meshGenerator.baked ? " (Baked)" : ""));
var zWriteSettings = container.GenerateSubcontainer(3);
var zWriteToggle =
inspector.GenerateToggle(this, zWriteSettings, "Enable ZWrite", nameof(zWrite))
.AddListenerFunction(SetEnableZWrite);
var emissionSettings = container.GenerateSubcontainer(3);
var enableEmissionToggle =
inspector.GenerateToggle(this, emissionSettings, "Enable Emission", nameof(enableEmission))
.AddListenerFunction(SetEnableEmission);
var emissionIntensityInputField =
inspector.GenerateInputField(this, emissionSettings, "Emission Intensity", nameof(emissionIntensity))
.AddListenerFunction(SetEmissionIntensity);
var uvSettings = container.GenerateSubcontainer(1);
var uvScaleInputField =
inspector.GenerateVector2InputField(this, uvSettings, "UV Scale", nameof(uvScale))
.AddListenerFunction(SetUV);
var uvOffsetInputField =
inspector.GenerateVector2InputField(this, uvSettings, "UV Offset", nameof(uvOffset))
.AddListenerFunction(SetUV);
var materialSettings = container.GenerateSubcontainer(3);
var themeBundleDropdown = inspector
.GenerateDropdown(this, materialSettings, "Theme Bundle", ThemeBundleManager.instance.selectedThemeBundleList, nameof(materialThemeBundleName))
.AddListenerFunction(() => inspectorMain.SetInspector(track));
if (materialThemeBundleName != String.Empty && ThemeBundleManager.instance.TryGetThemeBundle(materialThemeBundleName, out ThemeBundle themeBundle))
{
List<string> materialNameList = themeBundle.assetList_Material.ConvertAll(x => x.name);
var objectNameDropdown = inspector.GenerateDropdown(this, materialSettings, "Material Name", materialNameList, nameof(materialName))
.AddListenerFunction(() => inspectorMain.SetInspector(track));
}
else
{
var objectNameDropdown = inspector.GenerateDropdown(this, materialSettings, "Material Name", new List<string>(), nameof(materialName));
objectNameDropdown.dropdown.interactable = false;
}
var applyMaterialButton = inspector.GenerateButton(this, materialSettings, "Apply Material", () => { ApplyMaterial(materialThemeBundleName, materialName); });
var delete = container.GenerateSubcontainer(3);
var deleteButton = inspector.GenerateButton(this, delete, "Delete", () =>
{
Delete();
track.trackRendererSubmodule = null;
inspectorMain.SetInspector(track);
track.Refresh();
});
}
protected void SetEnableEmission()
{
// 仅保留关键字控制,具体颜色由 Refresh 的 property block 控制
if (enableEmission)
{
meshRenderer.material.EnableKeyword("_EMISSION_ON");
}
else
{
meshRenderer.material.DisableKeyword("_EMISSION_ON");
}
}
protected void SetEnableZWrite()
{
var block = new MaterialPropertyBlock();
meshRenderer.GetPropertyBlock(block);
// ZWrite
block.SetFloat("_ZWrite", zWrite ? 1f : 0f);
meshRenderer.SetPropertyBlock(block);
}
protected void SetEmissionIntensity()
{
var block = new MaterialPropertyBlock();
meshRenderer.GetPropertyBlock(block);
// Emission
if (enableEmission)
{
meshRenderer.material.EnableKeyword("_EMISSION_ON");
block.SetColor("_EmissionColor", Color.white * Mathf.Pow(2, emissionIntensity));
}
else
{
meshRenderer.material.DisableKeyword("_EMISSION_ON");
block.SetColor("_EmissionColor", Color.black);
}
meshRenderer.SetPropertyBlock(block);
}
protected void SetUV()
{
meshGenerator.uvScale = uvScale;
meshGenerator.uvOffset = uvOffset;
}
}
#region AutoOrient
public class TrackRendererSubmoduleAutoOrient : TrackRendererSubmodule
{
public SplineRenderer splineRenderer;
public TrackRendererSubmoduleAutoOrient(Track track, bool enableEmission, float emissionIntensity, bool zWrite,
Vector2 uvScale, Vector2 uvOffset, Material material = null) :
base(track, enableEmission, emissionIntensity, zWrite, uvScale, uvOffset)
{
this.splineRenderer = track.AddComponent<SplineRenderer>();
this.meshRenderer = splineRenderer.GetComponent<MeshRenderer>();
this.meshGenerator = splineRenderer;
this.renderMaterial = material == null ? EditorManager.instance.basePrefabs.defaultTrackMaterial : material;
this.splineRenderer.spline = track.trackPathSubmodule.path;
this.splineRenderer.doubleSided = true;
this.splineRenderer.clipFrom = 0;
this.splineRenderer.clipTo = 1;
this.splineRenderer.updateMethod = SplineUser.UpdateMethod.Update;
this.meshRenderer.material = renderMaterial;
this.splineRenderer.color = Color.white;
this.splineRenderer.uvRotation = 90;
this.splineRenderer.uvMode = MeshGenerator.UVMode.UniformClip;
this.submoduleNameIndex = 0; // Auto Orient is the first submodule
}
public override void SaveBM()
{
matchedBM = new TrackRendererSubmoduleAutoOrient_BM(attachedGameElement, this);
}
}
namespace Beatmap
{
public class TrackRendererSubmoduleAutoOrient_BM : Submodule_BM
{
public string materialThemeBundleName;
public string materialName;
public bool enableEmission;
public float emissionIntensity;
public bool zWrite; // 新增
public Vector2 uvScale = Vector2.one;
public Vector2 uvOffset = Vector2.zero;
public TrackRendererSubmoduleAutoOrient_BM()
{
}
public TrackRendererSubmoduleAutoOrient_BM(GameElement attachedElement,
TrackRendererSubmoduleAutoOrient trackRendererSubmodule) : base(attachedElement)
{
materialThemeBundleName = trackRendererSubmodule.materialThemeBundleName;
materialName = trackRendererSubmodule.materialName;
enableEmission = trackRendererSubmodule.enableEmission;
emissionIntensity = trackRendererSubmodule.emissionIntensity;
zWrite = trackRendererSubmodule.zWrite; // 新增
uvScale = trackRendererSubmodule.uvScale;
uvOffset = trackRendererSubmodule.uvOffset;
}
public override void ExecuteBM()
{
attachedElement = GameElement_BM.GetElement(attachedElementGuid);
Track track = attachedElement as Track;
track.trackRendererSubmodule =
new TrackRendererSubmoduleAutoOrient(track, enableEmission, emissionIntensity, zWrite, uvScale, uvOffset);
if (materialName.Trim() != String.Empty)
{
track.trackRendererSubmodule.ApplyMaterial(materialThemeBundleName, materialName);
}
}
public override void DuplicateBM(GameElement attached)
{
Track track = attached as Track;
track.trackRendererSubmodule =
new TrackRendererSubmoduleAutoOrient(track, enableEmission, emissionIntensity, zWrite, uvScale, uvOffset);
if (materialName.Trim() != String.Empty)
{
track.trackRendererSubmodule.ApplyMaterial(materialThemeBundleName, materialName);
}
}
}
}
#endregion
#region PathGenerator
public class TrackRendererSubmodulePathGenerator : TrackRendererSubmodule
{
public PathGenerator pathGenerator;
public TrackRendererSubmodulePathGenerator(Track track, bool enableEmission, float emissionIntensity, bool zWrite,
Vector2 uvScale, Vector2 uvOffset, Material material = null) :
base(track, enableEmission, emissionIntensity, zWrite, uvScale, uvOffset)
{
this.pathGenerator = track.AddComponent<PathGenerator>();
this.meshRenderer = pathGenerator.GetComponent<MeshRenderer>();
this.meshGenerator = pathGenerator;
this.renderMaterial = material == null ? EditorManager.instance.basePrefabs.defaultTrackMaterial : material;
this.pathGenerator.spline = track.trackPathSubmodule.path;
this.pathGenerator.doubleSided = true;
this.pathGenerator.clipFrom = 0;
this.pathGenerator.clipTo = 1;
this.pathGenerator.updateMethod = SplineUser.UpdateMethod.Update;
this.meshRenderer.material = renderMaterial;
this.pathGenerator.color = Color.white;
this.pathGenerator.uvRotation = 90;
this.pathGenerator.uvMode = MeshGenerator.UVMode.UniformClip;
this.submoduleNameIndex = 1; // Path Generator is the second submodule
}
public override void SaveBM()
{
matchedBM = new TrackRendererSubmodulePathGenerator_BM(attachedGameElement, this);
}
}
namespace Beatmap
{
public class TrackRendererSubmodulePathGenerator_BM : Submodule_BM
{
public string materialThemeBundleName;
public string materialName;
public bool enableEmission;
public float emissionIntensity;
public bool zWrite; // 新增
public Vector2 uvScale = Vector2.one;
public Vector2 uvOffset = Vector2.zero;
public TrackRendererSubmodulePathGenerator_BM()
{
}
public TrackRendererSubmodulePathGenerator_BM(GameElement attachedElement,
TrackRendererSubmodulePathGenerator trackRendererSubmodule) : base(attachedElement)
{
materialThemeBundleName = trackRendererSubmodule.materialThemeBundleName;
materialName = trackRendererSubmodule.materialName;
enableEmission = trackRendererSubmodule.enableEmission;
emissionIntensity = trackRendererSubmodule.emissionIntensity;
zWrite = trackRendererSubmodule.zWrite; // 新增
uvScale = trackRendererSubmodule.uvScale;
uvOffset = trackRendererSubmodule.uvOffset;
}
public override void ExecuteBM()
{
attachedElement = GameElement_BM.GetElement(attachedElementGuid);
Track track = attachedElement as Track;
track.trackRendererSubmodule =
new TrackRendererSubmodulePathGenerator(track, enableEmission, emissionIntensity, zWrite, uvScale, uvOffset);
if (materialName.Trim() != String.Empty)
{
track.trackRendererSubmodule.ApplyMaterial(materialThemeBundleName, materialName);
}
}
public override void DuplicateBM(GameElement attached)
{
Track track = attached as Track;
track.trackRendererSubmodule =
new TrackRendererSubmodulePathGenerator(track, enableEmission, emissionIntensity, zWrite, uvScale, uvOffset);
if (materialName.Trim() != String.Empty)
{
track.trackRendererSubmodule.ApplyMaterial(materialThemeBundleName, materialName);
}
}
}
}
#endregion
#region TubeGenerator
public class TrackRendererSubmoduleTubeGenerator : TrackRendererSubmodule
{
public TubeGenerator tubeGenerator;
public int sideCount;
public TrackRendererSubmoduleTubeGenerator(Track track, bool enableEmission, float emissionIntensity, bool zWrite,
int sideCount, Vector2 uvScale, Vector2 uvOffset, Material material = null) :
base(track, enableEmission, emissionIntensity, zWrite, uvScale, uvOffset)
{
this.sideCount = sideCount;
this.tubeGenerator = track.AddComponent<TubeGenerator>();
this.meshRenderer = tubeGenerator.GetComponent<MeshRenderer>();
this.meshGenerator = tubeGenerator;
this.renderMaterial = material == null ? EditorManager.instance.basePrefabs.defaultTrackMaterial : material;
this.tubeGenerator.spline = track.trackPathSubmodule.path;
this.tubeGenerator.doubleSided = true;
this.tubeGenerator.clipFrom = 0;
this.tubeGenerator.clipTo = 1;
this.tubeGenerator.updateMethod = SplineUser.UpdateMethod.Update;
this.meshRenderer.material = renderMaterial;
this.tubeGenerator.color = Color.white;
this.tubeGenerator.uvRotation = 90;
this.tubeGenerator.sides = sideCount;
this.tubeGenerator.uvMode = MeshGenerator.UVMode.UniformClip;
this.submoduleNameIndex = 2; // Tube Generator is the third submodule
}
public override void SaveBM()
{
matchedBM = new TrackRendererSubmoduleTubeGenerator_BM(attachedGameElement, this);
}
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Tube Settings");
var tubeSettings = container.GenerateSubcontainer(3);
var sideCountInputField =
inspector.GenerateInputField(this, tubeSettings, "Side Count", nameof(sideCount))
.AddListenerFunction(() => { tubeGenerator.sides = sideCount; });
base.SetUpInspector();
}
}
namespace Beatmap
{
public class TrackRendererSubmoduleTubeGenerator_BM : Submodule_BM
{
public string materialThemeBundleName;
public string materialName;
public bool enableEmission;
public float emissionIntensity;
public bool zWrite; // 新增
public int sideCount;
public Vector2 uvScale = Vector2.one;
public Vector2 uvOffset = Vector2.zero;
public TrackRendererSubmoduleTubeGenerator_BM()
{
}
public TrackRendererSubmoduleTubeGenerator_BM(GameElement attachedElement,
TrackRendererSubmoduleTubeGenerator trackRendererSubmodule) : base(attachedElement)
{
materialThemeBundleName = trackRendererSubmodule.materialThemeBundleName;
materialName = trackRendererSubmodule.materialName;
enableEmission = trackRendererSubmodule.enableEmission;
emissionIntensity = trackRendererSubmodule.emissionIntensity;
zWrite = trackRendererSubmodule.zWrite; // 新增
sideCount = trackRendererSubmodule.sideCount;
uvScale = trackRendererSubmodule.uvScale;
uvOffset = trackRendererSubmodule.uvOffset;
}
public override void ExecuteBM()
{
attachedElement = GameElement_BM.GetElement(attachedElementGuid);
Track track = attachedElement as Track;
track.trackRendererSubmodule =
new TrackRendererSubmoduleTubeGenerator(track, enableEmission, emissionIntensity, zWrite, sideCount, uvScale, uvOffset);
if (materialName.Trim() != String.Empty)
{
track.trackRendererSubmodule.ApplyMaterial(materialThemeBundleName, materialName);
}
}
public override void DuplicateBM(GameElement attached)
{
Track track = attached as Track;
track.trackRendererSubmodule =
new TrackRendererSubmoduleTubeGenerator(track, enableEmission, emissionIntensity, zWrite, sideCount, uvScale, uvOffset);
if (materialName.Trim() != String.Empty)
{
track.trackRendererSubmodule.ApplyMaterial(materialThemeBundleName, materialName);
}
}
}
}
#endregion
#region Surface
public class TrackRendererSubmoduleSurface : TrackRendererSubmodule
{
public SurfaceGenerator surface;
public TrackRendererSubmoduleSurface(Track track, bool enableEmission, float emissionIntensity, bool zWrite,
Vector2 uvScale, Vector2 uvOffset, Material material = null) :
base(track, enableEmission, emissionIntensity, zWrite, uvScale, uvOffset)
{
this.surface = track.AddComponent<SurfaceGenerator>();
this.meshRenderer = surface.GetComponent<MeshRenderer>();
this.meshGenerator = surface;
this.renderMaterial = material == null ? EditorManager.instance.basePrefabs.defaultTrackMaterial : material;
this.surface.spline = track.trackPathSubmodule.path;
this.surface.doubleSided = true;
this.surface.clipFrom = 0;
this.surface.clipTo = 1;
this.surface.updateMethod = SplineUser.UpdateMethod.Update;
this.meshRenderer.material = renderMaterial;
this.surface.color = Color.white;
this.surface.uvRotation = 90;
this.surface.uvMode = MeshGenerator.UVMode.UniformClip;
this.submoduleNameIndex = 3; // Surface is the fourth submodule
}
public override void SaveBM()
{
matchedBM = new TrackRendererSubmoduleSurface_BM(attachedGameElement, this);
}
}
namespace Beatmap
{
public class TrackRendererSubmoduleSurface_BM : Submodule_BM
{
public string materialThemeBundleName;
public string materialName;
public bool enableEmission;
public float emissionIntensity;
public bool zWrite; // 新增
public Vector2 uvScale = Vector2.one;
public Vector2 uvOffset = Vector2.zero;
public TrackRendererSubmoduleSurface_BM()
{
}
public TrackRendererSubmoduleSurface_BM(GameElement attachedElement,
TrackRendererSubmoduleSurface trackRendererSubmodule) : base(attachedElement)
{
materialThemeBundleName = trackRendererSubmodule.materialThemeBundleName;
materialName = trackRendererSubmodule.materialName;
enableEmission = trackRendererSubmodule.enableEmission;
emissionIntensity = trackRendererSubmodule.emissionIntensity;
zWrite = trackRendererSubmodule.zWrite; // 新增
uvScale = trackRendererSubmodule.uvScale;
uvOffset = trackRendererSubmodule.uvOffset;
}
public override void ExecuteBM()
{
attachedElement = GameElement_BM.GetElement(attachedElementGuid);
Track track = attachedElement as Track;
track.trackRendererSubmodule =
new TrackRendererSubmoduleSurface(track, enableEmission, emissionIntensity, zWrite, uvScale, uvOffset);
if (materialName.Trim() != String.Empty)
{
track.trackRendererSubmodule.ApplyMaterial(materialThemeBundleName, materialName);
}
}
public override void DuplicateBM(GameElement attached)
{
Track track = attached as Track;
track.trackRendererSubmodule =
new TrackRendererSubmoduleSurface(track, enableEmission, emissionIntensity, zWrite, uvScale, uvOffset);
if (materialName.Trim() != String.Empty)
{
track.trackRendererSubmodule.ApplyMaterial(materialThemeBundleName, materialName);
}
}
}
}
#endregion
}

View File

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

View File

@@ -1,299 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using Ichni.Editor;
using UnityEngine;
namespace Ichni.RhythmGame
{
public class TrackTimeSubmodule : TrackSubmodule
{
public float headPercent, tailPercent;
public TrackTimeSubmodule(Track track) : base(track)
{
if (!HaveSameSubmodule)
{
this.track.trackTimeSubmodule = this;
}
}
public override void SaveBM()
{
throw new System.NotImplementedException();
}
}
#region Movable
public class TrackTimeSubmoduleMovable : TrackTimeSubmodule
{
public float trackStartTime;
public float trackEndTime;
public float trackTotalTime;
public float visibleTrackTimeLength;
public AnimationCurveType animationCurveType;
//public bool isGoWithZ = false;
public TrackTimeSubmoduleMovable(Track track, float trackStartTime, float trackEndTime,
float visibleTrackTimeLength, AnimationCurveType animationCurveType) : base(track)
{
this.trackStartTime = trackStartTime;
this.trackEndTime = trackEndTime;
this.trackTotalTime = trackEndTime - trackStartTime;
this.visibleTrackTimeLength = visibleTrackTimeLength;
this.animationCurveType = animationCurveType;
//timeDurationSubmodule 根据下辖Note的时间来设置
}
public void UpdateTrackPart()
{
float songTime = EditorManager.instance.songInformation.songTime;
headPercent = GetTrackPercent(songTime);
tailPercent = GetTrackPercent(songTime - visibleTrackTimeLength);
if (track.trackRendererSubmodule != null)
{
track.trackRendererSubmodule.meshGenerator.clipFrom = tailPercent;
track.trackRendererSubmodule.meshGenerator.clipTo = headPercent;
}
}
public float GetTrackPercent(float songTimeInTime)
{
float per = AnimationCurveEvaluator.Evaluate(animationCurveType, (songTimeInTime - trackStartTime) / trackTotalTime);
// return isGoWithZ ? GetSplineZPercent(Mathf.Clamp01(per)) : Mathf.Clamp01(per);
return Mathf.Clamp01(per);
}
public float GetTrackPercentRaw(float songTimeInTime)
{
float per = AnimationCurveEvaluator.Evaluate(animationCurveType, (songTimeInTime - trackStartTime) / trackTotalTime);
// return isGoWithZ ? GetSplineZPercent(Mathf.Clamp01(per)) : Mathf.Clamp01(per);
return per;
}
// private float GetSplineZPercent(float percent)
// {
// var nodeList = track.trackPathSubmodule.pathNodeList;
// int count = nodeList.Count;
// if (count <= 2) return percent;
// float startZ = nodeList[0].transformSubmodule.currentPosition.z;
// float endZ = nodeList[count - 1].transformSubmodule.currentPosition.z;
// float needZ = Mathf.Lerp(startZ, endZ, percent);
// float outpercent = 0f;
// float percentBetween = 1f / (count - 1);
// for (int i = 0; i < count - 1; i++)
// {
// float z0 = nodeList[i].transformSubmodule.currentPosition.z;
// float z1 = nodeList[i + 1].transformSubmodule.currentPosition.z;
// // 如果 needZ 在当前区间内,做插值
// if ((z0 <= needZ && needZ <= z1) || (z1 <= needZ && needZ <= z0))
// {
// float zDelta = z1 - z0;
// if (Mathf.Approximately(zDelta, 0f)) return outpercent;
// float t = (needZ - z0) / zDelta;
// outpercent += percentBetween * Mathf.Clamp01(t);
// return outpercent;
// }
// else
// {
// outpercent += percentBetween;
// }
// }
// // 如果没找到区间,返回 1f已遍历所有节点
// return 1f;
// }
public override void Refresh()
{
trackTotalTime = trackEndTime - trackStartTime;
UpdateTrackPart();
track.childElementList.ForEach(child =>
{
if (child is NoteBase note)
{
note.UpdateNoteInTrack();
}
});
}
public override void SaveBM()
{
matchedBM = new Beatmap.TrackTimeSubmoduleMovable_BM(attachedGameElement, this);
}
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Track Time Movable");
var trackTimeSubmoduleSettings = container.GenerateSubcontainer(3);
var startTimeInputField =
inspector.GenerateInputField(this, trackTimeSubmoduleSettings, "Start Time", nameof(trackStartTime))
.AddListenerFunction(RefreshChildren);
var endTimeInputField = inspector.GenerateInputField(this, trackTimeSubmoduleSettings, "End Time", nameof(trackEndTime))
.AddListenerFunction(RefreshChildren);
var visibleTimeInputField =
inspector.GenerateInputField(this, trackTimeSubmoduleSettings, "Visible Time Length", nameof(visibleTrackTimeLength));
var animationCurveDropdown =
inspector.GenerateDropdown(this, trackTimeSubmoduleSettings, "Animation Curve", typeof(AnimationCurveType), nameof(animationCurveType))
.AddListenerFunction(RefreshChildren);
// var isGoWithZToggle =
// inspector.GenerateToggle(this, trackTimeSubmoduleSettings, "Go With Z", nameof(isGoWithZ));
var deleteButton = inspector.GenerateButton(this, trackTimeSubmoduleSettings, "Delete", () =>
{
Delete();
track.trackTimeSubmodule = null;
inspectorMain.SetInspector(track);
track.Refresh();
});
}
private void RefreshChildren()
{
track.childElementList.ForEach(child =>
{
if (child is NoteBase note)
{
note.UpdateNoteInTrack();
}
});
}
}
namespace Beatmap
{
public class TrackTimeSubmoduleMovable_BM : Submodule_BM
{
public float trackStartTime;
public float trackEndTime;
public float visibleTrackTimeLength;
public AnimationCurveType animationCurveType;
public TrackTimeSubmoduleMovable_BM()
{
}
public TrackTimeSubmoduleMovable_BM(GameElement attachedElement, TrackTimeSubmoduleMovable trackTimeSubmoduleMovable) : base(attachedElement)
{
trackStartTime = trackTimeSubmoduleMovable.trackStartTime;
trackEndTime = trackTimeSubmoduleMovable.trackEndTime;
visibleTrackTimeLength = trackTimeSubmoduleMovable.visibleTrackTimeLength;
animationCurveType = trackTimeSubmoduleMovable.animationCurveType;
}
public override void ExecuteBM()
{
attachedElement = GameElement_BM.GetElement(attachedElementGuid);
Track track = attachedElement as Track;
track.trackTimeSubmodule = new TrackTimeSubmoduleMovable(track, trackStartTime, trackEndTime, visibleTrackTimeLength, animationCurveType);
}
public override void DuplicateBM(GameElement attached)
{
Track track = attached as Track;
track.trackTimeSubmodule = new TrackTimeSubmoduleMovable(track, trackStartTime, trackEndTime, visibleTrackTimeLength, animationCurveType);
}
}
}
#endregion
#region Static
public class TrackTimeSubmoduleStatic : TrackTimeSubmodule
{
public float trackTotalTime;
public AnimationCurveType animationCurveType;
public TrackTimeSubmoduleStatic(Track track, float trackTotalTime, AnimationCurveType animationCurveType) :
base(track)
{
this.trackTotalTime = trackTotalTime;
this.animationCurveType = animationCurveType;
this.headPercent = 0;
this.tailPercent = 1;
//timeDurationSubmodule 根据下辖Note的时间来设置
}
public override void Refresh()
{
if (track.trackRendererSubmodule != null)
{
track.trackRendererSubmodule.meshGenerator.clipFrom = tailPercent;
track.trackRendererSubmodule.meshGenerator.clipTo = headPercent;
}
track.childElementList.ForEach(child =>
{
if (child is NoteBase note)
{
note.UpdateNoteInTrack();
}
});
}
public override void SaveBM()
{
matchedBM = new Beatmap.TrackTimeSubmoduleStatic_BM(attachedGameElement, this);
}
public override void SetUpInspector()
{
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Track Time Static");
var trackTimeSubmoduleSettings = container.GenerateSubcontainer(3);
var totalTimeInputField =
inspector.GenerateInputField(this, trackTimeSubmoduleSettings, "Total Time", nameof(trackTotalTime));
var animationCurveDropdown =
inspector.GenerateDropdown(this, trackTimeSubmoduleSettings, "Animation Curve", typeof(AnimationCurveType), nameof(animationCurveType));
var deleteButton = inspector.GenerateButton(this, trackTimeSubmoduleSettings, "Delete", () =>
{
Delete();
track.trackTimeSubmodule = null;
inspectorMain.SetInspector(track);
track.Refresh();
});
}
}
namespace Beatmap
{
public class TrackTimeSubmoduleStatic_BM : Submodule_BM
{
public float trackTotalTime;
public AnimationCurveType animationCurveType;
public TrackTimeSubmoduleStatic_BM()
{
}
public TrackTimeSubmoduleStatic_BM(GameElement attachedElement, TrackTimeSubmoduleStatic trackTimeSubmoduleStatic) : base(attachedElement)
{
trackTotalTime = trackTimeSubmoduleStatic.trackTotalTime;
animationCurveType = trackTimeSubmoduleStatic.animationCurveType;
}
public override void ExecuteBM()
{
attachedElement = GameElement_BM.GetElement(attachedElementGuid);
Track track = attachedElement as Track;
track.trackTimeSubmodule = new TrackTimeSubmoduleStatic(track, trackTotalTime, animationCurveType);
}
public override void DuplicateBM(GameElement attached)
{
Track track = attached as Track;
track.trackTimeSubmodule = new TrackTimeSubmoduleStatic(track, trackTotalTime, animationCurveType);
}
}
}
#endregion
}

View File

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

View File

@@ -1,285 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Dreamteck.Splines;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
namespace Ichni.RhythmGame
{
public partial class ObjectTracker : GameElement
{
public Track track;
public ObjectController objectController;
public GameObject objectPrefab;
private List<string> themeBundleList;
private List<string> objectNameList;
public string themeBundleName;
public string objectName;
public float playTime;
public float stopTime;
public int spawnCount;
public Vector2 positionOffsetMin = Vector2.zero;
public Vector2 positionOffsetMax = Vector2.zero;
public string customPositionRuleName;
public bool applyRotationOffset = false;
public Vector3 rotationOffsetMin = Vector3.zero;
public Vector3 rotationOffsetMax = Vector3.zero;
public string customRotationRuleName;
public bool applyScaleOffset = false;
public Vector3 scaleOffsetMin = Vector3.one;
public Vector3 scaleOffsetMax = Vector3.one;
public string customScaleRuleName;
public static ObjectTracker GenerateElement(string elementName, Guid id, List<string> tags,
bool isFirstGenerated, Track track, string themeBundleName, string objectName, int spawnCount,
Vector2 positionOffsetMin, Vector2 positionOffsetMax, string customPositionRuleName,
bool applyRotationOffset, Vector3 rotationOffsetMin, Vector3 rotationOffsetMax, string customRotationRuleName,
bool applyScaleOffset, Vector3 scaleOffsetMin, Vector3 scaleOffsetMax, string customScaleRuleName)
{
ObjectTracker objectTracker = Instantiate(EditorManager.instance.basePrefabs.objectTracker, track.transform).GetComponent<ObjectTracker>();
objectTracker.objectPrefab = ThemeBundleManager.instance.GetObject<GameObject>(themeBundleName, objectName);
objectTracker.objectController.objects = new[] { objectTracker.objectPrefab };
objectTracker.Initialize(elementName, id, tags, isFirstGenerated, track);
objectTracker.track = track;
objectTracker.objectController.spline = track.trackPathSubmodule.path;
objectTracker.themeBundleList = ThemeBundleManager.instance.loadedThemeBundleList.ConvertAll(x => x.themeBundleName);
objectTracker.objectNameList = new List<string>();
objectTracker.themeBundleName = themeBundleName;
objectTracker.objectName = objectName;
objectTracker.SetSpawnSettings(spawnCount,
positionOffsetMin, positionOffsetMax, customPositionRuleName,
applyRotationOffset, rotationOffsetMin, rotationOffsetMax, customRotationRuleName,
applyScaleOffset, scaleOffsetMin, scaleOffsetMax, customScaleRuleName);
return objectTracker;
}
private void Update()
{
float songTime = EditorManager.instance.songInformation.songTime;
if (playTime > songTime || stopTime < songTime)
{
if (objectController.enabled)
{
objectController.enabled = false;
}
}
else
{
if (!objectController.enabled)
{
objectController.enabled = true;
objectController.Spawn();
}
}
}
public override void SetUpInspector()
{
base.SetUpInspector();
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Object Tracker");
var generate = container.GenerateSubcontainer(3);
var themeBundleDropdown =
inspector.GenerateDropdown(this, generate, "Theme Bundle", themeBundleList, nameof(themeBundleName))
.AddListenerFunction(() => inspectorMain.SetInspector(this));
if (themeBundleName != String.Empty && ThemeBundleManager.instance.TryGetThemeBundle(themeBundleName, out ThemeBundle themeBundle))
{
objectNameList = themeBundle.assetList_GameObject.ConvertAll(x => x.name);
var objectNameDropdown =
inspector.GenerateDropdown(this, generate, "Object Name", objectNameList, nameof(objectName))
.AddListenerFunction(() => inspectorMain.SetInspector(this));
}
else
{
var objectNameDropdown =
inspector.GenerateDropdown(this, generate, "Object Name", new List<string>(), nameof(objectName));
objectNameDropdown.dropdown.interactable = false;
} // 如果没有选择主题包,则物体名称下拉框不可用
var setButton = inspector.GenerateButton(this, generate, "Generate", () =>
{
objectController.Clear();
this.objectPrefab = ThemeBundleManager.instance.GetObject<GameObject>(themeBundleName, objectName);
this.objectController.objects = new[] { this.objectPrefab };
this.objectController.Spawn();
});
if (themeBundleName == String.Empty || objectName == String.Empty)
{
setButton.button.interactable = false;
}
var spawnSettings = container.GenerateSubcontainer(3);
inspector.GenerateInputField(this, spawnSettings, "Spawn Count", nameof(spawnCount))
.AddListenerFunction(() => objectController.spawnCount = spawnCount);
inspector.GenerateInputField(this, spawnSettings, "Play Time", nameof(playTime));
inspector.GenerateInputField(this, spawnSettings, "Stop Time", nameof(stopTime));
var posSettings = container.GenerateSubcontainer(1);
inspector.GenerateVector2InputField(this, posSettings, "Position Offset Min", nameof(positionOffsetMin))
.AddListenerFunction(() => objectController.minOffset = positionOffsetMin);
inspector.GenerateVector2InputField(this, posSettings, "Position Offset Max", nameof(positionOffsetMax))
.AddListenerFunction(() => objectController.maxOffset = positionOffsetMax);
//inspector.GenerateInputField(this, posSettings, "Custom Position Rule Name", nameof(customPositionRuleName));
var rotSettings = container.GenerateSubcontainer(1);
inspector.GenerateToggle(this, rotSettings, "Apply Rotation Offset", nameof(applyRotationOffset))
.AddListenerFunction(() => objectController.applyRotation = applyRotationOffset);
inspector.GenerateVector3InputField(this, rotSettings, "Rotation Offset Min", nameof(rotationOffsetMin))
.AddListenerFunction(() => objectController.minRotation = rotationOffsetMin);
inspector.GenerateVector3InputField(this, rotSettings, "Rotation Offset Max", nameof(rotationOffsetMax))
.AddListenerFunction(() => objectController.maxRotation = rotationOffsetMax);
//inspector.GenerateInputField(this, rotSettings, "Custom Rotation Rule Name", nameof(customRotationRuleName));
var scaleSettings = container.GenerateSubcontainer(1);
inspector.GenerateToggle(this, scaleSettings, "Apply Scale Offset", nameof(applyScaleOffset))
.AddListenerFunction(() => objectController.applyScale = applyScaleOffset);
inspector.GenerateVector3InputField(this, scaleSettings, "Scale Offset Min", nameof(scaleOffsetMin))
.AddListenerFunction(() => objectController.minScaleMultiplier = scaleOffsetMin);
inspector.GenerateVector3InputField(this, scaleSettings, "Scale Offset Max", nameof(scaleOffsetMax))
.AddListenerFunction(() => objectController.maxScaleMultiplier = scaleOffsetMax);
//inspector.GenerateInputField(this, scaleSettings, "Custom Scale Rule Name", nameof(customScaleRuleName));
}
public override void SaveBM()
{
matchedBM = new Beatmap.ObjectTracker_BM(elementName, elementGuid, tags,
parentElement.matchedBM as GameElement_BM,
themeBundleName, objectName,
playTime, stopTime,
spawnCount,
positionOffsetMin, positionOffsetMax, customPositionRuleName,
applyRotationOffset, rotationOffsetMin, rotationOffsetMax, customRotationRuleName,
applyScaleOffset, scaleOffsetMin, scaleOffsetMax, customScaleRuleName);
}
}
public partial class ObjectTracker
{
public void SetSpawnSettings(int spawnCount,
Vector2 positionOffsetMin, Vector2 positionOffsetMax, string customPositionRuleName,
bool applyRotationOffset, Vector3 rotationOffsetMin, Vector3 rotationOffsetMax, string customRotationRuleName,
bool applyScaleOffset, Vector3 scaleOffsetMin, Vector3 scaleOffsetMax, string customScaleRuleName)
{
this.spawnCount = spawnCount;
this.positionOffsetMin = positionOffsetMin;
this.positionOffsetMax = positionOffsetMax;
this.customPositionRuleName = customPositionRuleName;
this.applyRotationOffset = applyRotationOffset;
this.rotationOffsetMin = rotationOffsetMin;
this.rotationOffsetMax = rotationOffsetMax;
this.customRotationRuleName = customRotationRuleName;
this.applyScaleOffset = applyScaleOffset;
this.scaleOffsetMin = scaleOffsetMin;
this.scaleOffsetMax = scaleOffsetMax;
this.customScaleRuleName = customScaleRuleName;
objectController.spawnCount = spawnCount;
objectController.minOffset = positionOffsetMin;
objectController.maxOffset = positionOffsetMax;
objectController.applyRotation = applyRotationOffset;
objectController.minRotation = rotationOffsetMin;
objectController.maxRotation = rotationOffsetMax;
objectController.applyScale = applyScaleOffset;
objectController.minScaleMultiplier = scaleOffsetMin;
objectController.maxScaleMultiplier = scaleOffsetMax;
objectController.Spawn();
}
}
namespace Beatmap
{
public class ObjectTracker_BM : GameElement_BM
{
public string themeBundleName;
public string objectName;
public float playTime;
public float stopTime;
public int spawnCount;
public Vector2 positionOffsetMin;
public Vector2 positionOffsetMax;
public string customPositionRuleName;
public bool applyRotationOffset;
public Vector3 rotationOffsetMin;
public Vector3 rotationOffsetMax;
public string customRotationRuleName;
public bool applyScaleOffset;
public Vector3 scaleOffsetMin;
public Vector3 scaleOffsetMax;
public string customScaleRuleName;
public ObjectTracker_BM()
{
}
public ObjectTracker_BM(string elementName, Guid elementGuid, List<string> tags, GameElement_BM attachedElement,
string themeBundleName, string objectName,
float playTime, float stopTime,
int spawnCount,
Vector2 positionOffsetMin, Vector2 positionOffsetMax, string customPositionRuleName,
bool applyRotationOffset, Vector3 rotationOffsetMin, Vector3 rotationOffsetMax, string customRotationRuleName,
bool applyScaleOffset, Vector3 scaleOffsetMin, Vector3 scaleOffsetMax, string customScaleRuleName)
: base(elementName, elementGuid, tags, attachedElement)
{
this.themeBundleName = themeBundleName;
this.objectName = objectName;
this.playTime = playTime;
this.stopTime = stopTime;
this.spawnCount = spawnCount;
this.positionOffsetMin = positionOffsetMin;
this.positionOffsetMax = positionOffsetMax;
this.customPositionRuleName = customPositionRuleName;
this.applyRotationOffset = applyRotationOffset;
this.rotationOffsetMin = rotationOffsetMin;
this.rotationOffsetMax = rotationOffsetMax;
this.customRotationRuleName = customRotationRuleName;
this.applyScaleOffset = applyScaleOffset;
this.scaleOffsetMin = scaleOffsetMin;
this.scaleOffsetMax = scaleOffsetMax;
this.customScaleRuleName = customScaleRuleName;
}
public override void ExecuteBM()
{
matchedElement = ObjectTracker.GenerateElement(
elementName, elementGuid, tags, false,
GetElement(attachedElementGuid) as Track,
themeBundleName, objectName,
spawnCount,
positionOffsetMin, positionOffsetMax, customPositionRuleName,
applyRotationOffset, rotationOffsetMin, rotationOffsetMax, customRotationRuleName,
applyScaleOffset, scaleOffsetMin, scaleOffsetMax, customScaleRuleName);
}
public override GameElement DuplicateBM(GameElement attached)
{
return ObjectTracker.GenerateElement(
elementName, Guid.NewGuid(), new List<string>(tags), false,
attached as Track,
themeBundleName, objectName,
spawnCount,
positionOffsetMin, positionOffsetMax, customPositionRuleName,
applyRotationOffset, rotationOffsetMin, rotationOffsetMax, customRotationRuleName,
applyScaleOffset, scaleOffsetMin, scaleOffsetMax, customScaleRuleName);
}
}
}
}

View File

@@ -1,290 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Dreamteck.Splines;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
using UnityEngine.Serialization;
namespace Ichni.RhythmGame
{
public partial class ParticleTracker : GameElement, IHaveParticles, IHaveColorSubmodule
{
public Track track;
public ParticleController particleController;
private IHaveParticles particlesContainer => this;
public ParticleSystem particle { get; set; }
public ColorSubmodule colorSubmodule { get; set; }
public bool haveBaseColor => true;
public bool haveEmissionColor => true;
private List<string> themeBundleList;
private List<string> materialNameList;
public string themeBundleName;
public string materialName;
public bool prewarm;
public float playTime;
public float stopTime;
public bool is3D;
public float width;
public Vector3 extendDirection;
public float density;
public float lifeTime;
public bool isAutoOrient;
public Vector3 particleRotation;
public static ParticleTracker GenerateElement(string elementName, Guid id, List<string> tags,
bool isFirstGenerated, Track track, string themeBundleName, string materialName,
bool prewarm, float playTime, float stopTime,
bool is3D, float width, Vector3 extendDirection,
float density, float lifeTime,
bool isAutoOrient, Vector3 particleRotation)
{
ParticleTracker particleTracker = Instantiate(EditorManager.instance.basePrefabs.particleTracker, track.transform)
.GetComponent<ParticleTracker>();
particleTracker.particle = particleTracker.GetComponentInChildren<ParticleSystem>();
particleTracker.Initialize(elementName, id, tags, isFirstGenerated, track);
particleTracker.track = track;
particleTracker.particleController.spline = track.trackPathSubmodule.path;
particleTracker.playTime = playTime;
particleTracker.stopTime = stopTime;
particleTracker.themeBundleList = ThemeBundleManager.instance.loadedThemeBundleList.ConvertAll(x => x.themeBundleName);
particleTracker.materialNameList = new List<string>();
particleTracker.themeBundleName = themeBundleName;
particleTracker.materialName = materialName;
particleTracker.particlesContainer.SetParticleMaterial(themeBundleName, materialName);
particleTracker.SetParticleSettings(prewarm, is3D, width, extendDirection, density, lifeTime, isAutoOrient, particleRotation);
return particleTracker;
}
public override void SetDefaultSubmodules()
{
colorSubmodule = new ColorSubmodule(this, Color.white, true, Color.white, 0);
}
public void SetParticleSettings(bool prewarm, bool is3D, float width, Vector3 extendDirection,
float density, float lifeTime, bool isAutoOrient, Vector3 particleRotation)
{
this.prewarm = prewarm;
this.is3D = is3D;
this.width = width;
this.extendDirection = extendDirection;
this.density = density;
this.lifeTime = lifeTime;
this.prewarm = prewarm;
this.isAutoOrient = isAutoOrient;
this.particleRotation = particleRotation;
particlesContainer.SetParticleSettings(prewarm, ParticleSystemSimulationSpace.Local, density,
lifeTime, 0, 1, isAutoOrient, particleRotation);
SetShape();
}
}
public partial class ParticleTracker
{
private void Update()
{
float songTime = EditorManager.instance.songInformation.songTime;
if (playTime > songTime || stopTime < songTime)
{
if (particle.isPlaying || particle.isPaused)
{
particle.Stop();
if (songTime < playTime) { particle.Clear(); }
}
}
else
{
if (!EditorManager.instance.musicPlayer.isPlaying)
{
particle.Pause();
}
else if (!particle.isPlaying)
{
particle.Play();
}
}
}
public override void SaveBM()
{
matchedBM = new ParticleTracker_BM(elementName, elementGuid, tags,
parentElement.matchedBM as GameElement_BM,
prewarm, playTime, stopTime, is3D, width, extendDirection, density, lifeTime, isAutoOrient, particleRotation,
themeBundleName, materialName);
}
public override void SetUpInspector()
{
base.SetUpInspector();
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Particle Tracker");
// 确保 themeBundleList 初始化
if (themeBundleList == null)
themeBundleList = ThemeBundleManager.instance.loadedThemeBundleList.ConvertAll(x => x.themeBundleName);
DynamicUISubcontainer particleSettings0 = container.GenerateSubcontainer(3);
inspector.GenerateToggle(this, particleSettings0, "Prewarm", nameof(prewarm))
.AddListenerFunction(() => particlesContainer.SetPrewarm(prewarm));
inspector.GenerateInputField(this, particleSettings0, "Play Time", nameof(playTime));
inspector.GenerateInputField(this, particleSettings0, "Stop Time", nameof(stopTime));
DynamicUISubcontainer particleSettings1_0 = container.GenerateSubcontainer(3);
inspector.GenerateToggle(this, particleSettings1_0, "Is 3D", nameof(is3D))
.AddListenerFunction(SetShape);
inspector.GenerateInputField(this, particleSettings1_0, "Width", nameof(width))
.AddListenerFunction(SetShape);
DynamicUISubcontainer particleSettings1_1 = container.GenerateSubcontainer(1);
inspector.GenerateVector3InputField(this, particleSettings1_1, "Extend Direction", nameof(extendDirection))
.AddListenerFunction(SetShape);
DynamicUISubcontainer particleSettings2 = container.GenerateSubcontainer(3);
inspector.GenerateInputField(this, particleSettings2, "Density", nameof(density))
.AddListenerFunction(()=>particlesContainer.SetDensity(density));
inspector.GenerateInputField(this, particleSettings2, "Life Time", nameof(lifeTime))
.AddListenerFunction(()=>particlesContainer.SetLifeTime(lifeTime));
DynamicUISubcontainer particleSettings3_0 = container.GenerateSubcontainer(3);
inspector.GenerateToggle(this, particleSettings3_0, "Is Auto Orient", nameof(isAutoOrient))
.AddListenerFunction(()=>particlesContainer.SetAlignment(isAutoOrient, particleRotation));
DynamicUISubcontainer particleSettings3_1 = container.GenerateSubcontainer(1);
inspector.GenerateVector3InputField(this, particleSettings3_1, "Particle Rotation", nameof(particleRotation))
.AddListenerFunction(()=>particlesContainer.SetParticleRotation(particleRotation));
DynamicUISubcontainer materialSettings = container.GenerateSubcontainer(3);
var themeBundleDropdown =
inspector.GenerateDropdown(this, materialSettings, "Theme Bundle", themeBundleList, nameof(themeBundleName))
.AddListenerFunction(() => inspectorMain.SetInspector(this));
if (themeBundleName != String.Empty && ThemeBundleManager.instance.TryGetThemeBundle(themeBundleName, out ThemeBundle themeBundle))
{
materialNameList = themeBundle.assetList_Material.ConvertAll(x => x.name);
var objectNameDropdown =
inspector.GenerateDropdown(this, materialSettings, "Material Name", materialNameList, nameof(materialName))
.AddListenerFunction(() => inspectorMain.SetInspector(this));
}
else
{
materialNameList = new List<string>(); // 防止为null
var objectNameDropdown =
inspector.GenerateDropdown(this, materialSettings, "Material Name", materialNameList, nameof(materialName));
objectNameDropdown.dropdown.interactable = false;
} // 如果没有选择主题包,则材质名称下拉框不可用
var setMaterialButton = inspector.GenerateButton(this, materialSettings, "Set Material", () =>
{
particlesContainer.SetParticleMaterial(themeBundleName, materialName);
});
if (themeBundleName == String.Empty || materialName == String.Empty)
{
setMaterialButton.button.interactable = false;
}
}
}
public partial class ParticleTracker
{
private void SetShape()
{
particleController.is3D = is3D;
particleController.width = width;
particleController.extendDirection = extendDirection;
particleController.Rebuild();
}
public override void Refresh()
{
base.Refresh();
ParticleSystemRenderer particleSystemRenderer = particle.GetComponent<ParticleSystemRenderer>();
particleSystemRenderer.material.SetColor("_BaseColor", colorSubmodule.currentBaseColor);
if (colorSubmodule.emissionEnabled)
{
particleSystemRenderer.material.EnableKeyword("_EMISSION_ON");
particleSystemRenderer.material.SetColor("_EmissionColor", colorSubmodule.GetCurrentEmissionColor());
}
else
{
particleSystemRenderer.material.DisableKeyword("_EMISSION_ON");
}
}
}
namespace Beatmap
{
public class ParticleTracker_BM : GameElement_BM
{
public bool prewarm = false;
public float playTime = 0f;
public float stopTime = 1f;
public bool is3D = false;
public float width = 10f;
public Vector3 extendDirection = Vector3.right;
public float density = 10;
public float lifeTime = 5;
public bool isAutoOrient = true;
public Vector3 particleRotation = Vector3.zero;
public string materialThemeBundleName = string.Empty;
public string materialName = string.Empty;
public ParticleTracker_BM()
{
}
public ParticleTracker_BM(string elementName, Guid elementGuid, List<string> tags, GameElement_BM attachedElement,
bool prewarm, float playTime, float stopTime,
bool is3D, float width, Vector3 extendDirection,
float density, float lifeTime,
bool isAutoOrient, Vector3 particleRotation,
string materialThemeBundleName, string materialName) : base(elementName, elementGuid, tags, attachedElement)
{
this.prewarm = prewarm;
this.playTime = playTime;
this.stopTime = stopTime;
this.width = width;
this.density = density;
this.is3D = is3D;
this.extendDirection = extendDirection;
this.lifeTime = lifeTime;
this.isAutoOrient = isAutoOrient;
this.particleRotation = particleRotation;
this.materialThemeBundleName = materialThemeBundleName;
this.materialName = materialName;
}
public override void ExecuteBM()
{
matchedElement = ParticleTracker.GenerateElement(
elementName, elementGuid, tags, false,
GetElement(attachedElementGuid) as Track, materialThemeBundleName, materialName,
prewarm, playTime, stopTime, is3D, width, extendDirection, density, lifeTime, isAutoOrient, particleRotation);
}
public override GameElement DuplicateBM(GameElement attached)
{
return ParticleTracker.GenerateElement(
elementName, Guid.NewGuid(), tags, false,
attached as Track, materialThemeBundleName, materialName,
prewarm, playTime, stopTime, is3D, width, extendDirection, density, lifeTime, isAutoOrient, particleRotation);
}
}
}
}

View File

@@ -1,291 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
namespace Ichni.RhythmGame
{
public partial class Trail : GameElement, IHaveTransformSubmodule, IHaveTrail
{
public TrailRenderer trailRenderer { get; set; }
public Material renderMaterial;
// Add these fields for material selection in inspector
public string materialThemeBundleName;
public string materialName;
public float visibleTimeLength;
public bool isAutoOrient;
public float widthMultiplier;
public AnimationCurve widthCurve;
public Gradient gradient;
public TransformSubmodule transformSubmodule { get; set; }
float IHaveTrail.visibleTimeLength
{
get => visibleTimeLength;
set => visibleTimeLength = value;
}
public bool emissionEnabled = false;
// public float emissionIntensity = 1f; // 发光强度
public static Trail GenerateElement(string name, Guid id, List<string> tags, bool isFirstGenerated,
GameElement parentElement, float visibleTimeLength, bool isAutoOrient, float widthMultiplier,
AnimationCurve widthCurve, Gradient gradient, string materialThemeBundleName, string materialName, Material material = null)
{
gradient ??= ColorExtensions.DefaultGradient();
Trail trail = Instantiate(EditorManager.instance.basePrefabs.trail, parentElement.transform).GetComponent<Trail>();
trail.trailRenderer = trail.GetComponent<TrailRenderer>();
trail.Initialize(name, id, tags, isFirstGenerated, parentElement);
trail.renderMaterial = material == null ? EditorManager.instance.basePrefabs.defaultTrailMaterial : material;
trail.visibleTimeLength = visibleTimeLength;
trail.isAutoOrient = isAutoOrient;
trail.widthMultiplier = widthMultiplier;
trail.widthCurve = widthCurve;
trail.gradient = gradient;
trail.materialThemeBundleName = materialThemeBundleName;
trail.materialName = materialName;
trail.trailRenderer.material = trail.renderMaterial;
trail.trailRenderer.time = visibleTimeLength;
trail.trailRenderer.alignment = isAutoOrient ? LineAlignment.View : LineAlignment.TransformZ;
trail.trailRenderer.widthMultiplier = widthMultiplier;
trail.trailRenderer.widthCurve = widthCurve;
trail.trailRenderer.colorGradient = gradient;
return trail;
}
public override void SetDefaultSubmodules()
{
transformSubmodule = new TransformSubmodule(this);
}
// 新增:通过主题包名和材质名获取材质的方法
public Material GetMaterialFromThemeBundle()
{
if (!string.IsNullOrEmpty(materialThemeBundleName) && !string.IsNullOrEmpty(materialName))
{
var mat = ThemeBundleManager.instance.GetObject<Material>(materialThemeBundleName, materialName);
if (mat != null)
return mat;
}
return EditorManager.instance.basePrefabs.defaultTrailMaterial;
}
}
public partial class Trail
{
public override void SaveBM()
{
matchedBM = new Trail_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM,
visibleTimeLength, isAutoOrient, widthMultiplier, widthCurve, materialThemeBundleName, materialName, gradient);
}
public override void SetUpInspector()
{
base.SetUpInspector();
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
StandardInspectionElement.GenerateForTransform(this); //关于有Transform的元素
var container = inspector.GenerateContainer("Trail");
var trailSettings = container.GenerateSubcontainer(3);
var visibleTimeLengthInputField =
inspector.GenerateInputField(this, trailSettings, "Visible Time Length", nameof(visibleTimeLength))
.AddListenerFunction(() => trailRenderer.time = visibleTimeLength);
var isAutoOrientToggle =
inspector.GenerateToggle(this, trailSettings, "Is Auto Orient", nameof(isAutoOrient))
.AddListenerFunction(() => trailRenderer.alignment = isAutoOrient ? LineAlignment.View : LineAlignment.TransformZ);
var widthMultiplierInputField =
inspector.GenerateInputField(this, trailSettings, "Width Multiplier", nameof(widthMultiplier))
.AddListenerFunction(() => trailRenderer.widthMultiplier = widthMultiplier);
var widthCurveButton = inspector.GenerateButton(this, trailSettings, "Width Curve", () =>
{
var widthCurveWindow = inspector.GenerateCompositeParameterWindow(this, "Width Curve", nameof(widthCurve));
widthCurveWindow.SetAsCustomCurve();
widthCurveWindow.closeButton.onClick.AddListener(() => trailRenderer.widthCurve = widthCurve);
});
// ----------- 新增:材质设置 -----------
var materialSettings = container.GenerateSubcontainer(3);
// 主题包下拉框
if (ThemeBundleManager.instance != null)
{
var themeBundleDropdown = inspector
.GenerateDropdown(this, materialSettings, "Theme Bundle", ThemeBundleManager.instance.selectedThemeBundleList, nameof(materialThemeBundleName))
.AddListenerFunction(() => inspectorMain.SetInspector(this));
// 材质名下拉框
if (!string.IsNullOrEmpty(materialThemeBundleName) && ThemeBundleManager.instance.TryGetThemeBundle(materialThemeBundleName, out ThemeBundle themeBundle))
{
List<string> materialNameList = themeBundle.assetList_Material.ConvertAll(x => x.name);
var objectNameDropdown = inspector.GenerateDropdown(this, materialSettings, "Material Name", materialNameList, nameof(materialName))
.AddListenerFunction(() => inspectorMain.SetInspector(this));
}
else
{
var objectNameDropdown = inspector.GenerateDropdown(this, materialSettings, "Material Name", new List<string>(), nameof(materialName));
objectNameDropdown.dropdown.interactable = false;
}
// 应用材质按钮
var applyMaterialButton = inspector.GenerateButton(this, materialSettings, "Apply Material", () =>
{
if (!string.IsNullOrEmpty(materialThemeBundleName) && !string.IsNullOrEmpty(materialName))
{
Material mat = ThemeBundleManager.instance.GetObject<Material>(materialThemeBundleName, materialName);
if (mat != null)
{
renderMaterial = mat;
if (trailRenderer != null)
trailRenderer.material = renderMaterial;
}
}
});
}
// ----------- 材质设置结束 -----------
var colorSettings = container.GenerateSubcontainer(3);
var gradientColorKeysButton = inspector.GenerateButton(this, colorSettings, "Gradient Color Keys", () =>
{
var gradientWindow = inspector.GenerateCompositeParameterWindow(this, "Gradient Color Keys", nameof(gradient));
gradientWindow.SetAsGradientColorKeys();
gradientWindow.closeButton.onClick.AddListener(() => trailRenderer.colorGradient = gradient);
});
var gradientAlphaKeysButton = inspector.GenerateButton(this, colorSettings, "Gradient Alpha Keys", () =>
{
var gradientWindow = inspector.GenerateCompositeParameterWindow(this, "Gradient Alpha Keys", nameof(gradient));
gradientWindow.SetAsGradientAlphaKeys();
gradientWindow.closeButton.onClick.AddListener(() => trailRenderer.colorGradient = gradient);
});
}
}
public partial class Trail
{
public static void SetAllTrails(bool emitting, bool willClear)
{
foreach (GameElement x in EditorManager.instance.beatmapContainer.gameElementList)
{
if (x is IHaveTrail t && t.trailRenderer != null)
{
t.trailRenderer.emitting = emitting;
t.trailRenderer.enabled = emitting;
if (willClear) t.trailRenderer.Clear();
}
}
}
public static void FreezeAllTrails(bool freeze)
{
foreach (GameElement x in EditorManager.instance.beatmapContainer.gameElementList)
{
if (x is IHaveTrail t && t != null)
{
FreezeTrail(freeze, t);
}
}
}
public static void FreezeTrail(bool freeze, IHaveTrail trail)
{
if (!freeze)
{
UnfreezeTrail(trail);
return;
}
trail.trailRenderer.time = Mathf.Infinity; // 使现有轨迹永不消失
trail.trailRenderer.emitting = false; // 停止生成新轨迹点
}
// 解冻尾迹(恢复动态更新)
public static void UnfreezeTrail(IHaveTrail trail)
{
trail.trailRenderer.Clear(); // 清除当前冻结的轨迹
trail.trailRenderer.time = trail.visibleTimeLength; // 恢复原始持续时间
trail.trailRenderer.emitting = true; // 重新开始发射轨迹点
}
}
public interface IHaveTrail
{
TrailRenderer trailRenderer { get; set; }
float visibleTimeLength { get; set; }
}
namespace Beatmap
{
public class Trail_BM : GameElement_BM
{
public float visibleTimeLength;
public string renderMaterialName;
public string materialThemeBundleName; // 新增
public string materialName; // 新增
public bool isAutoOrient;
public float widthMultiplier;
public AnimationCurve widthCurve;
public Gradient gradient;
public Trail_BM()
{
}
public Trail_BM(string elementName, Guid elementGuid, List<string> tags, GameElement_BM attachedElement,
float visibleTimeLength, bool isAutoOrient, float widthMultiplier,
AnimationCurve widthCurve, string materialThemeBundleName, string materialName, Gradient gradient) : base(elementName, elementGuid, tags,
attachedElement)
{
this.visibleTimeLength = visibleTimeLength;
// 新增:保存主题包名和材质名
this.materialThemeBundleName = materialThemeBundleName;
this.materialName = materialName;
this.isAutoOrient = isAutoOrient;
this.widthMultiplier = widthMultiplier;
this.widthCurve = widthCurve;
this.gradient = gradient;
}
public override void ExecuteBM()
{
// 新增根据bm里的主题包名和材质名获取材质
Material mat = null;
if (!string.IsNullOrEmpty(materialThemeBundleName) && !string.IsNullOrEmpty(materialName))
{
mat = ThemeBundleManager.instance.GetObject<Material>(materialThemeBundleName, materialName);
}
matchedElement = Trail.GenerateElement(elementName, elementGuid, tags,
false, GetElement(attachedElementGuid),
visibleTimeLength, isAutoOrient, widthMultiplier, widthCurve, gradient, materialThemeBundleName, materialName, mat);
}
public override GameElement DuplicateBM(GameElement parent)
{
// 新增根据bm里的主题包名和材质名获取材质
Material mat = null;
if (!string.IsNullOrEmpty(materialThemeBundleName) && !string.IsNullOrEmpty(materialName))
{
mat = ThemeBundleManager.instance.GetObject<Material>(materialThemeBundleName, materialName);
}
return Trail.GenerateElement(elementName, Guid.NewGuid(), tags,
false, parent, visibleTimeLength,
isAutoOrient, widthMultiplier, widthCurve, gradient, materialThemeBundleName, materialName, mat);
}
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 7bf117e642611451c8562357254c1e83
guid: e5c81960366f31346aada41fa3847d97
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 5f5c439efd47f46888026603e35d5a4e
guid: 0465fbef9411d134cb49c9da5db347a9
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 5f85e090ad2708745a8fd3b9c254ad3a
guid: 92c40b847213a5e41a3ebe8a47bc7daf
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
namespace Ichni.RhythmGame.Beatmap
{
public abstract class AnimationBase_BM : GameElement_BM
{
public AnimationBase_BM()
{
}
public AnimationBase_BM(string elementName, Guid elementGuid, List<string> tags,
GameElement_BM attachedElement) : base(elementName, elementGuid, tags, attachedElement)
{
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 62f7f20bc287dba439ab78c3adc20013

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 6944ee6ee5d024c15a16862148361df3
guid: afaa9a1f53951cc4293cdf042a085792
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
namespace Ichni.RhythmGame.Beatmap
{
public partial class CameraFieldOfView_BM : AnimationBase_BM
{
public FlexibleFloat_BM fieldOfView;
public CameraFieldOfView_BM()
{
}
public CameraFieldOfView_BM(string elementName, Guid elementGuid, List<string> tags,
GameElement_BM attachedElement, FlexibleFloat_BM fieldOfView)
: base(elementName, elementGuid, tags, attachedElement)
{
this.fieldOfView = fieldOfView;
}
public override void ExecuteBM()
{
matchedElement = CameraFieldOfView.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid) as GameCamera, fieldOfView.ConvertToGameType());
}
public override GameElement DuplicateBM(GameElement parent)
{
return CameraFieldOfView.GenerateElement(elementName, Guid.NewGuid(), tags, false,
parent as GameCamera, fieldOfView.ConvertToGameType());
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 4237b95b10903c04da3914fb0d9ebd0e

View File

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

View File

@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
namespace Ichni.RhythmGame.Beatmap
{
public class BaseColorChange_BM : AnimationBase_BM
{
public FlexibleFloat_BM colorR, colorG, colorB, colorA;
public BaseColorChange_BM()
{
}
public BaseColorChange_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 = BaseColorChange.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid), colorR.ConvertToGameType(),
colorG.ConvertToGameType(), colorB.ConvertToGameType(), colorA.ConvertToGameType());
}
public override GameElement DuplicateBM(GameElement parent)
{
return BaseColorChange.GenerateElement(elementName, Guid.NewGuid(), tags, false,
parent, colorR.ConvertToGameType(), colorG.ConvertToGameType(),
colorB.ConvertToGameType(), colorA.ConvertToGameType());
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 54072515035e86e4490c1d5d6412e834

View File

@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
namespace Ichni.RhythmGame.Beatmap
{
public class EmissionColorChange_BM : AnimationBase_BM
{
public FlexibleFloat_BM colorR, colorG, colorB, colorI;
public EmissionColorChange_BM()
{
}
public EmissionColorChange_BM(string elementName, Guid elementGuid, List<string> tags, GameElement_BM parentElement,
FlexibleFloat_BM colorR, FlexibleFloat_BM colorG, FlexibleFloat_BM colorB, FlexibleFloat_BM colorI) :
base(elementName, elementGuid, tags, parentElement)
{
this.colorR = colorR;
this.colorG = colorG;
this.colorB = colorB;
this.colorI = colorI;
}
public override void ExecuteBM()
{
matchedElement = EmissionColorChange.GenerateElement(elementName, elementGuid, tags, false, GetElement(attachedElementGuid),
colorR.ConvertToGameType(), colorG.ConvertToGameType(), colorB.ConvertToGameType(), colorI.ConvertToGameType());
}
public override GameElement DuplicateBM(GameElement parent)
{
return EmissionColorChange.GenerateElement(elementName, Guid.NewGuid(), tags, false, parent,
colorR.ConvertToGameType(), colorG.ConvertToGameType(), colorB.ConvertToGameType(), colorI.ConvertToGameType());
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 41c413de18a45884cb5a212200f3193b

View File

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

View File

@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
namespace Ichni.RhythmGame.Beatmap
{
public class DisplacementTracker_BM : AnimationBase_BM, ICanNotInExport
{
public Guid targetDisplacementGuid;
public float timeOffset;
public DisplacementTracker_BM() { }
public DisplacementTracker_BM(string elementName, System.Guid elementGuid, List<string> tags,
GameElement_BM attachedElement, Guid targetDisplacementGuid, float timeOffset)
: base(elementName, elementGuid, tags, attachedElement)
{
this.targetDisplacementGuid = targetDisplacementGuid;
this.timeOffset = timeOffset;
}
public override void ExecuteBM()
{
matchedElement = DisplacementTracker.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid), GetElement(targetDisplacementGuid) as Displacement, timeOffset);
matchedElement.matchedBM = this;
}
public override GameElement DuplicateBM(GameElement parent)
{
return DisplacementTracker.GenerateElement(elementName, System.Guid.NewGuid(), tags, false, parent,
GetElement(targetDisplacementGuid) as Displacement, timeOffset);
}
public override void AfterExecute()
{
(matchedElement as DisplacementTracker).targetDisplacement = GetElement(targetDisplacementGuid) as ICanBeTrackedDisplacement;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a854f837f01d15f45bd486d81ff35259

View File

@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
namespace Ichni.RhythmGame.Beatmap
{
public class ScaleTracker_BM : AnimationBase_BM, ICanNotInExport
{
public Guid targetScaleGuid;
public float timeOffset;
public ScaleTracker_BM() { }
public ScaleTracker_BM(string elementName, Guid elementGuid, List<string> tags,
GameElement_BM attachedElement, Guid targetScaleGuid, float timeOffset)
: base(elementName, elementGuid, tags, attachedElement)
{
this.targetScaleGuid = targetScaleGuid;
this.timeOffset = timeOffset;
}
public override void ExecuteBM()
{
matchedElement = ScaleTracker.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid), GetElement(targetScaleGuid) as ICanBeTrackedScale, timeOffset);
matchedElement.matchedBM = this;
}
public override GameElement DuplicateBM(GameElement parent)
{
return ScaleTracker.GenerateElement(elementName, Guid.NewGuid(), tags, false, parent,
GetElement(targetScaleGuid) as ICanBeTrackedScale, timeOffset);
}
public override void AfterExecute()
{
(matchedElement as ScaleTracker).targetScale = GetElement(targetScaleGuid) as ICanBeTrackedScale;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 4fd8d93fbaacc9e4693a14658c303fa9

View File

@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
namespace Ichni.RhythmGame.Beatmap
{
public class SwirlTracker_BM : AnimationBase_BM, ICanNotInExport
{
public Guid targetSwirlGuid;
public float timeOffset;
public SwirlTracker_BM() { }
public SwirlTracker_BM(string elementName, Guid elementGuid, List<string> tags,
GameElement_BM attachedElement, Guid targetSwirlGuid, float timeOffset)
: base(elementName, elementGuid, tags, attachedElement)
{
this.targetSwirlGuid = targetSwirlGuid;
this.timeOffset = timeOffset;
}
public override void ExecuteBM()
{
matchedElement = SwirlTracker.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid), GetElement(targetSwirlGuid) as Swirl, timeOffset);
matchedElement.matchedBM = this;
}
public override GameElement DuplicateBM(GameElement parent)
{
return SwirlTracker.GenerateElement(elementName, Guid.NewGuid(), tags, false, parent,
GetElement(targetSwirlGuid) as Swirl, timeOffset);
}
public override void AfterExecute()
{
(matchedElement as SwirlTracker).targetSwirl = GetElement(targetSwirlGuid) as ICanBeTrackedSwirl;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 49c51b81352f0444a9348e594a8364d6

View File

@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Ichni.RhythmGame.Beatmap
{
public class Vector3Interferometer_BM : AnimationBase_BM, ICanNotInExport
{
public Vector3 InterferomValueVector3;
public InterferomType InterferomType;
public Vector3Interferometer_BM() { }
public Vector3Interferometer_BM(string elementName, Guid elementGuid, List<string> tags,
GameElement_BM attachedElement, InterferomType interferomType, Vector3 interferomValue)
: base(elementName, elementGuid, tags, attachedElement)
{
this.InterferomType = interferomType;
this.InterferomValueVector3 = interferomValue;
}
public override void ExecuteBM()
{
matchedElement = Vector3Interferometer.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid) as AnimationBase, InterferomType, InterferomValueVector3);
}
public override GameElement DuplicateBM(GameElement parent)
{
return Vector3Interferometer.GenerateElement(elementName, Guid.NewGuid(), tags, false,
parent as AnimationBase, InterferomType, InterferomValueVector3);
}
}
public interface ICanNotInExport { }
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 523d5a711ebc2d84797488b5fee2b08c

View File

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

View File

@@ -0,0 +1,37 @@
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 GameElement DuplicateBM(GameElement attached)
{
return TrackGlobalColorChange.GenerateElement(elementName, Guid.NewGuid(), tags, true, attached,
colorR.ConvertToGameType(), colorG.ConvertToGameType(), colorB.ConvertToGameType(), colorA.ConvertToGameType());
}
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: 4a6e3c456031ba64dbb66efb488a2cff

View File

@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
namespace Ichni.RhythmGame.Beatmap
{
public class TrackTotalTimeChange_BM : AnimationBase_BM
{
public FlexibleFloat_BM totalTime;
public TrackTotalTimeChange_BM()
{
}
public TrackTotalTimeChange_BM(string elementName, Guid elementGuid, List<string> tags,
GameElement_BM attachedElement, FlexibleFloat_BM totalTime) :
base(elementName, elementGuid, tags, attachedElement)
{
this.totalTime = totalTime;
}
public override void ExecuteBM()
{
matchedElement = TrackTotalTimeChange.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid) as Track, totalTime.ConvertToGameType());
}
public override GameElement DuplicateBM(GameElement parent)
{
return TrackTotalTimeChange.GenerateElement(elementName, Guid.NewGuid(), tags, false,
parent as Track, totalTime.ConvertToGameType());
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 095a199d040efa14c8505df1752c832f

View File

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

View File

@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
namespace Ichni.RhythmGame.Beatmap
{
public class Displacement_BM : AnimationBase_BM
{
public FlexibleFloat_BM positionX, positionY, positionZ;
public Displacement_BM()
{
}
public Displacement_BM(string elementName, Guid elementGuid, List<string> tags,
GameElement_BM attachedElement, FlexibleFloat_BM positionX, FlexibleFloat_BM positionY, FlexibleFloat_BM positionZ)
: base(elementName, elementGuid, tags, attachedElement)
{
this.positionX = positionX;
this.positionY = positionY;
this.positionZ = positionZ;
}
public override void ExecuteBM()
{
matchedElement = Displacement.GenerateElement(elementName, elementGuid, tags, false, GetElement(attachedElementGuid),
positionX.ConvertToGameType(), positionY.ConvertToGameType(), positionZ.ConvertToGameType());
}
public override GameElement DuplicateBM(GameElement parent)
{
return Displacement.GenerateElement(elementName, Guid.NewGuid(), tags, false, parent,
positionX.ConvertToGameType(), positionY.ConvertToGameType(), positionZ.ConvertToGameType());
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: ee1155566a762724bbf8486c2f0ed48b

View File

@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
namespace Ichni.RhythmGame.Beatmap
{
public class LookAt_BM : GameElement_BM
{
public FlexibleBool_BM enabling;
public Guid lookAtObjectGuid;
public LookAt_BM()
{
}
public LookAt_BM(string elementName, Guid elementGuid, List<string> tags,
GameElement_BM attachedElement, FlexibleBool_BM enabling, Guid lookAtObjectGuid)
: base(elementName, elementGuid, tags, attachedElement)
{
this.enabling = enabling;
this.lookAtObjectGuid = lookAtObjectGuid;
}
public override void ExecuteBM()
{
matchedElement = LookAt.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid), GetElement(lookAtObjectGuid), enabling.ConvertToGameType());
matchedElement.matchedBM = this;
}
public override GameElement DuplicateBM(GameElement parent)
{
return LookAt.GenerateElement(elementName, Guid.NewGuid(), tags, false, parent,
GetElement(lookAtObjectGuid), enabling.ConvertToGameType());
}
public override void AfterExecute()
{
(matchedElement as LookAt).lookAtObject = GetElement(lookAtObjectGuid);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: fc1bafbf1d46274459a8339c37f65a70

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