Signed-off-by: TRAfoer <lhf190@outlook.com>
This commit is contained in:
2025-09-21 13:34:59 +08:00
parent 7f7324bdb8
commit 4966ba353a
29 changed files with 1528 additions and 1981 deletions

View File

@@ -178,6 +178,10 @@ namespace Ichni.Editor
}
private string TransformCommand(string input)
{
string getFloatorInt(string a)
{
return a.Contains(".") ? $"float.Parse({a})" : a;
}
// 处理命令格式,适配 DynamicExpresso
string trimmed = input.Trim();
@@ -212,9 +216,9 @@ namespace Ichni.Editor
string content = a.Substring(1, a.Length - 2).Trim();
var nums = content.Split(',').Select(s => s.Trim()).ToArray();
if (nums.Length == 2)
processedArgs.Add($"new Vector2({nums[0]},{nums[1]})");
processedArgs.Add($"new Vector2({getFloatorInt(nums[0])},{getFloatorInt(nums[1])})");
else if (nums.Length == 3)
processedArgs.Add($"new Vector3({nums[0]},{nums[1]},{nums[2]})");
processedArgs.Add($"new Vector3({getFloatorInt(nums[0])},{getFloatorInt(nums[1])},{getFloatorInt(nums[2])})");
else
processedArgs.Add(a); // 不是2或3维原样返回
}
@@ -226,7 +230,7 @@ namespace Ichni.Editor
// 数字
else if (Regex.IsMatch(a, @"^-?\d+(\.\d+)?([eE][+-]?\d+)?$"))
{
processedArgs.Add(a);
processedArgs.Add(getFloatorInt(a));
}
// 变量名(字母开头,允许字母数字下划线)
else if (Regex.IsMatch(a, @"^[a-zA-Z_]\w*$"))

View File

@@ -108,8 +108,15 @@ namespace Ichni.RhythmGame
{
EffectBase newEffect = factory.Invoke(); // 创建新实例
newEffect.attachedGameElement = attachedGameElement;
effectCollection[effect.Key].Add(newEffect);
newEffect.AccommodatingList = effectCollection[effect.Key];
var list = effectCollection[effect.Key];
// 自动继承上一个Effect的参数
if (list.Count > 0)
{
var last = list[list.Count - 1];
newEffect.CopyParametersFrom(last);
}
list.Add(newEffect);
newEffect.AccommodatingList = list;
inspectorMain.SetInspector(attachedGameElement);
}
else
@@ -373,6 +380,10 @@ namespace Ichni.RhythmGame
});
}
public virtual void CopyParametersFrom(EffectBase other)
{
// 默认实现什么都不做,子类重写
}
}
namespace Beatmap

View File

@@ -56,6 +56,17 @@ namespace Ichni.RhythmGame
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

View File

@@ -25,7 +25,15 @@ namespace Ichni.RhythmGame
this.offsetValue = offsetValue;
this.offsetCurve = offsetCurve;
}
public override void CopyParametersFrom(EffectBase other)
{
if (other is CameraOffsetEffect otherEffect)
{
this.duration = otherEffect.duration;
this.offsetValue = otherEffect.offsetValue;
this.offsetCurve = otherEffect.offsetCurve != null ? new AnimationCurve(otherEffect.offsetCurve.keys) : null;
}
}
public override void Recover()
{
if (!EditorManager.instance.cameraManager.haveGameCamera)

View File

@@ -26,6 +26,17 @@ namespace Ichni.RhythmGame
this.amplitudeY = amplitudeY;
this.amplitudeZ = amplitudeZ;
}
public override void CopyParametersFrom(EffectBase other)
{
if (other is CameraShakeEffect otherEffect)
{
this.duration = otherEffect.duration;
this.frequency = otherEffect.frequency;
this.amplitudeX = otherEffect.amplitudeX;
this.amplitudeY = otherEffect.amplitudeY;
this.amplitudeZ = otherEffect.amplitudeZ;
}
}
public override void Adjust()
{

View File

@@ -26,6 +26,15 @@ namespace Ichni.RhythmGame
this.tiltValue = tiltValue;
this.tiltCurve = tiltCurve;
}
public override void CopyParametersFrom(EffectBase other)
{
if (other is CameraTiltEffect otherEffect)
{
this.duration = otherEffect.duration;
this.tiltValue = otherEffect.tiltValue;
this.tiltCurve = otherEffect.tiltCurve != null ? new AnimationCurve(otherEffect.tiltCurve.keys) : null;
}
}
public override void Recover()
{

View File

@@ -23,6 +23,15 @@ namespace Ichni.RhythmGame
this.relativeZoom = relativeZoom;
this.zoomCurve = zoomCurve;
}
public override void CopyParametersFrom(EffectBase other)
{
if (other is CameraZoomEffect otherEffect)
{
this.duration = otherEffect.duration;
this.relativeZoom = otherEffect.relativeZoom;
this.zoomCurve = otherEffect.zoomCurve != null ? new AnimationCurve(otherEffect.zoomCurve.keys) : null;
}
}
public override void Adjust()
{

View File

@@ -22,6 +22,16 @@ namespace Ichni.RhythmGame
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()
{

View File

@@ -27,6 +27,17 @@ namespace Ichni.RhythmGame
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()
{

View File

@@ -22,6 +22,16 @@ namespace Ichni.RhythmGame
this.peak = peak;
this.intensityCurve = intensityCurve;
}
public override void CopyParametersFrom(EffectBase other)
{
if (other is HighPassFilterEffect otherEffect)
{
this.duration = otherEffect.duration;
this.peak = otherEffect.peak;
this.intensityCurve = otherEffect.intensityCurve != null ? new AnimationCurve(otherEffect.intensityCurve.keys) : null;
}
}
public override void Adjust()
{

View File

@@ -22,6 +22,16 @@ namespace Ichni.RhythmGame
this.bottom = bottom;
this.intensityCurve = intensityCurve;
}
public override void CopyParametersFrom(EffectBase other)
{
if (other is LowPassFilterEffect otherEffect)
{
this.duration = otherEffect.duration;
this.bottom = otherEffect.bottom;
this.intensityCurve = otherEffect.intensityCurve != null ? new AnimationCurve(otherEffect.intensityCurve.keys) : null;
}
}
public override void Adjust()
{

View File

@@ -21,6 +21,16 @@ namespace Ichni.RhythmGame
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()
{

View File

@@ -8,15 +8,15 @@ namespace Ichni.RhythmGame
{
public class RadialBlurEffect : EffectBase
{
private readonly NBPostProcessingController nbController;
private readonly NBPostProcessingController 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;
@@ -28,7 +28,19 @@ namespace Ichni.RhythmGame
this.intensityCurve = intensityCurve;
this.nbController = EditorManager.instance.postProcessingManager.nbController;
}
public override void CopyParametersFrom(EffectBase other)
{
if (other is RadialBlurEffect otherEffect)
{
this.duration = otherEffect.duration;
this.sampleLevel = otherEffect.sampleLevel;
this.position = otherEffect.position;
this.fadeRange = otherEffect.fadeRange;
this.peakIntensity = otherEffect.peakIntensity;
this.intensityCurve = otherEffect.intensityCurve != null ? new AnimationCurve(otherEffect.intensityCurve.keys) : null;
}
}
public override void Recover()
{
nbController.radialBlurToggle = false;
@@ -52,7 +64,7 @@ namespace Ichni.RhythmGame
float intensity = Mathf.Lerp(0, peakIntensity, intensityCurve.Evaluate(effectProgressPercent));
nbController.radialBlurIntensity = intensity;
}
public override void Adjust()
{
nbController.radialBlurToggle = false;
@@ -104,7 +116,7 @@ namespace Ichni.RhythmGame
this.peakIntensity = peakIntensity;
this.intensityCurve = intensityCurve;
}
public override EffectBase ConvertToGameType(GameElement attachedGameElement)
{
return new RadialBlurEffect(duration, sampleLevel, position, fadeRange, peakIntensity, intensityCurve)

View File

@@ -26,6 +26,17 @@ namespace Ichni.RhythmGame
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()
{

View File

@@ -92,8 +92,9 @@ namespace Ichni.RhythmGame
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 = blendSpeedList[currentSkyboxIndex - 1];
if (currentSkyboxIndex != 0) skyboxBlender.blendSpeed = isSmaller ? 9999f : blendSpeedList[currentSkyboxIndex - 1];
skyboxBlender.Blend(currentSkyboxIndex, false);
DynamicGI.UpdateEnvironment();
}

View File

@@ -124,11 +124,8 @@ namespace Ichni.RhythmGame
holdingTimeInputField.AddListenerFunction(() =>
{
holdEndTime = float.Parse(holdingTimeInputField.inputField.text) + exactJudgeTime;
noteVisual?.effectSubmodule.effectCollection["Holding"].ForEach(effect =>
{
effect.effectTime = holdingTime;
});
holdEndTimeInputField.inputField.text = holdEndTime.ToString();
holdEndTimeInputField.inputField.onEndEdit.Invoke(holdEndTimeInputField.inputField.text);
});
inspector.MarkedElements["ExactJudgeTime"].AddListenerFunction(() =>
{

View File

@@ -11,7 +11,7 @@ using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;
public class EventPoint : MonoBehaviour
public partial class EventPoint : MonoBehaviour
{
public AnimatedFloat animatedFloat;
public EventPoint LastEventPoint;
@@ -65,144 +65,7 @@ public class EventPoint : MonoBehaviour
UpdateValue();
ReDraw(value);
}
public IEnumerator GenerateTextureCoroutine(int width, int height, float value)
{
Task<Color[]> task = Task.Run(() => GenerateTextureColors(width, height, value));
while (!task.IsCompleted)
{
yield return null; // 等待下一帧
}
Color[] textureColors = task.Result;
Texture2D Texture = new Texture2D(width, height);
Texture.SetPixels(textureColors);
Texture.Apply();
CurveCanvas.texture = Texture;
// CurveCanvas.color = new Color(1, 1, 1, 0);
// CurveCanvas.DOColor(new Color(1, 1, 1, 1), 0.2f).SetEase(Ease.InOutSine);
}
public Color[] GenerateTextureColors(int width, int height, float value)
{
Color[] pixels = new Color[width * height];
// 初始化所有像素为透明
for (int i = 0; i < pixels.Length; i++)
{
pixels[i] = new Color(0, 0, 0, 0);
}
int LastEventPointY = 0;
for (int i = 0; i < width; i++)
{
float t = (float)i / width;
int f = (int)(
(height / 2) + (animatedFloat.startValue * value + ((animatedFloat.endValue - animatedFloat.startValue)
* AnimationCurveEvaluator.Evaluate(animatedFloat.animationCurveType, t) * value))
);
// 绘制垂直线段 - 保留超出边界的红色标记
if (LastEventPointY < f)
{
for (int j = LastEventPointY; j < f; j++)
{
// 检查是否超出边界
bool isOutOfBounds = j < 0 || j >= height;
// 计算实际坐标(循环调整)
int actualY = j;
while (actualY < 0) actualY += height;
while (actualY >= height) actualY -= height;
int index = actualY * width + i;
if (index >= 0 && index < pixels.Length)
{
// 根据是否超出边界设置颜色
pixels[index] = isOutOfBounds ? Color.red : Color.green;
}
}
}
else
{
for (int j = LastEventPointY; j > f; j--)
{
// 检查是否超出边界
bool isOutOfBounds = j < 0 || j >= height;
// 计算实际坐标(循环调整)
int actualY = j;
while (actualY < 0) actualY += height;
while (actualY >= height) actualY -= height;
int index = actualY * width + i;
if (index >= 0 && index < pixels.Length)
{
// 根据是否超出边界设置颜色
pixels[index] = isOutOfBounds ? Color.red : Color.green;
}
}
}
// 绘制当前点 - 保留超出边界的红色标记
bool isFOutOfBounds = f < 0 || f >= height;
int actualF = f;
while (actualF < 0) actualF += height;
while (actualF >= height) actualF -= height;
int currentIndex = actualF * width + i;
if (currentIndex >= 0 && currentIndex < pixels.Length)
{
// 根据是否超出边界设置颜色
pixels[currentIndex] = isFOutOfBounds ? Color.red : Color.green;
}
LastEventPointY = f;
}
return pixels;
}
public void ReDraw(float value)
{
int width = (int)CurveCanvas.rectTransform.sizeDelta.x / 5;
int height = (int)CurveCanvas.rectTransform.sizeDelta.y / 5;
// 获取颜色数组(可在多线程环境中调用)
// 在主线程中创建和设置纹理Unity对象操作必须在主线程
StartCoroutine(GenerateTextureCoroutine(width, height, value));
// 其余的非纹理相关代码保持不变
if (NextEventPoint != null)
{
OvDrawimage.transform.localPosition = new Vector3(RightSide.transform.localPosition.x,
animatedFloat.endValue * value * 5, 0);
OvDrawimage.rectTransform.sizeDelta = new Vector2((NextEventPoint.animatedFloat.startTime - animatedFloat.endTime) / EditorManager.instance.uiManager.timeline.timePerBeat * FatherTab.BeatDeviver,
OvDrawimage.rectTransform.sizeDelta.y);
OvDrawimage.color = new Color(0, 1, 0, 1);
while (OvDrawimage.transform.localPosition.y > 100)
{
OvDrawimage.color = new Color(1, 0, 0, 0.3f);
OvDrawimage.transform.localPosition = new Vector3(OvDrawimage.transform.localPosition.x, OvDrawimage.transform.localPosition.y - 200, OvDrawimage.transform.localPosition.z);
}
while (OvDrawimage.transform.localPosition.y < -100)
{
OvDrawimage.color = new Color(1, 0, 0, 0.3f);
OvDrawimage.transform.localPosition = new Vector3(OvDrawimage.transform.localPosition.x, OvDrawimage.transform.localPosition.y + 200, OvDrawimage.transform.localPosition.z);
}
}
else
{
OvDrawimage.rectTransform.sizeDelta = new Vector2(0, OvDrawimage.rectTransform.sizeDelta.y);
}
selectButton.transform.localPosition = EvDrawimage.transform.localPosition;
selectButton.GetComponent<RectTransform>().sizeDelta = EvDrawimage.rectTransform.sizeDelta;
ViewText.text = animatedFloat.startTime.ToString("0.00") + "s" + "\n" +
animatedFloat.startValue.ToString("0.0") + "\n" + animatedFloat.endValue.ToString("0.0") + "\n" + animatedFloat.endTime.ToString("0.00") + "s" + "\n" +
animatedFloat.animationCurveType.ToString();
ViewText.color = new Color(1, 1, 1, EvDrawimage.rectTransform.sizeDelta.x < 100 ? 0 : 1);
}
public void SelectButtonClick()//unity内当按钮按下时
@@ -359,3 +222,144 @@ public class EventPoint : MonoBehaviour
);
}
}
public partial class EventPoint//显示?
{
public IEnumerator GenerateTextureCoroutine(int width, int height, float value)
{
Task<Color[]> task = Task.Run(() => GenerateTextureColors(width, height, value));
while (!task.IsCompleted)
{
yield return null; // 等待下一帧
}
Color[] textureColors = task.Result;
Texture2D Texture = new Texture2D(width, height);
Texture.SetPixels(textureColors);
Texture.Apply();
CurveCanvas.texture = Texture;
// CurveCanvas.color = new Color(1, 1, 1, 0);
// CurveCanvas.DOColor(new Color(1, 1, 1, 1), 0.2f).SetEase(Ease.InOutSine);
}
public Color[] GenerateTextureColors(int width, int height, float value)
{
Color[] pixels = new Color[width * height];
// 初始化所有像素为透明
for (int i = 0; i < pixels.Length; i++)
{
pixels[i] = new Color(0, 0, 0, 0);
}
int LastEventPointY = 0;
for (int i = 0; i < width; i++)
{
float t = (float)i / width;
int f = (int)(
(height / 2) + (animatedFloat.startValue * value + ((animatedFloat.endValue - animatedFloat.startValue)
* AnimationCurveEvaluator.Evaluate(animatedFloat.animationCurveType, t) * value))
);
// 绘制垂直线段 - 保留超出边界的红色标记
if (LastEventPointY < f)
{
for (int j = LastEventPointY; j < f; j++)
{
// 检查是否超出边界
bool isOutOfBounds = j < 0 || j >= height;
// 计算实际坐标(循环调整)
int actualY = j;
while (actualY < 0) actualY += height;
while (actualY >= height) actualY -= height;
int index = actualY * width + i;
if (index >= 0 && index < pixels.Length)
{
// 根据是否超出边界设置颜色
pixels[index] = isOutOfBounds ? Color.red : Color.green;
}
}
}
else
{
for (int j = LastEventPointY; j > f; j--)
{
// 检查是否超出边界
bool isOutOfBounds = j < 0 || j >= height;
// 计算实际坐标(循环调整)
int actualY = j;
while (actualY < 0) actualY += height;
while (actualY >= height) actualY -= height;
int index = actualY * width + i;
if (index >= 0 && index < pixels.Length)
{
// 根据是否超出边界设置颜色
pixels[index] = isOutOfBounds ? Color.red : Color.green;
}
}
}
// 绘制当前点 - 保留超出边界的红色标记
bool isFOutOfBounds = f < 0 || f >= height;
int actualF = f;
while (actualF < 0) actualF += height;
while (actualF >= height) actualF -= height;
int currentIndex = actualF * width + i;
if (currentIndex >= 0 && currentIndex < pixels.Length)
{
// 根据是否超出边界设置颜色
pixels[currentIndex] = isFOutOfBounds ? Color.red : Color.green;
}
LastEventPointY = f;
}
return pixels;
}
public void ReDraw(float value)
{
int width = (int)CurveCanvas.rectTransform.sizeDelta.x / 5;
int height = (int)CurveCanvas.rectTransform.sizeDelta.y / 5;
// 获取颜色数组(可在多线程环境中调用)
// 在主线程中创建和设置纹理Unity对象操作必须在主线程
StartCoroutine(GenerateTextureCoroutine(width, height, value));
// 其余的非纹理相关代码保持不变
if (NextEventPoint != null)
{
OvDrawimage.transform.localPosition = new Vector3(RightSide.transform.localPosition.x,
animatedFloat.endValue * value * 5, 0);
OvDrawimage.rectTransform.sizeDelta = new Vector2((NextEventPoint.animatedFloat.startTime - animatedFloat.endTime) / EditorManager.instance.uiManager.timeline.timePerBeat * FatherTab.BeatDeviver,
OvDrawimage.rectTransform.sizeDelta.y);
OvDrawimage.color = new Color(0, 1, 0, 1);
while (OvDrawimage.transform.localPosition.y > 100)
{
OvDrawimage.color = new Color(1, 0, 0, 0.3f);
OvDrawimage.transform.localPosition = new Vector3(OvDrawimage.transform.localPosition.x, OvDrawimage.transform.localPosition.y - 200, OvDrawimage.transform.localPosition.z);
}
while (OvDrawimage.transform.localPosition.y < -100)
{
OvDrawimage.color = new Color(1, 0, 0, 0.3f);
OvDrawimage.transform.localPosition = new Vector3(OvDrawimage.transform.localPosition.x, OvDrawimage.transform.localPosition.y + 200, OvDrawimage.transform.localPosition.z);
}
}
else
{
OvDrawimage.rectTransform.sizeDelta = new Vector2(0, OvDrawimage.rectTransform.sizeDelta.y);
}
selectButton.transform.localPosition = EvDrawimage.transform.localPosition;
selectButton.GetComponent<RectTransform>().sizeDelta = EvDrawimage.rectTransform.sizeDelta;
ViewText.text = animatedFloat.startTime.ToString("0.00") + "s" + "\n" +
animatedFloat.startValue.ToString("0.0") + "\n" + animatedFloat.endValue.ToString("0.0") + "\n" + animatedFloat.endTime.ToString("0.00") + "s" + "\n" +
animatedFloat.animationCurveType.ToString();
ViewText.color = new Color(1, 1, 1, EvDrawimage.rectTransform.sizeDelta.x < 100 ? 0 : 1);
}
}