using System; using System.Collections; using System.Collections.Generic; using Ichni.RhythmGame.Beatmap; using UnityEngine; namespace Ichni.RhythmGame { public partial class Scale : AnimationBase { #region [暴露属性字段与关联] Exposed Fields & References public TransformSubmodule targetTransformSubmodule; public FlexibleFloat scaleX, scaleY, scaleZ; // 静态跟踪全局激活的Scale组件,为了方便同物体的跨动画状态感应 public static HashSet ActiveScales = new HashSet(); #endregion protected void OnEnable() { ActiveScales.Add(this); } protected void OnDisable() { ActiveScales.Remove(this); } #region [生命周期与工厂] Lifecycle & Factory public static Scale GenerateElement(string elementName, Guid id, List tags, bool isFirstGenerated, GameElement animatedObject, FlexibleFloat scaleX, FlexibleFloat scaleY, FlexibleFloat scaleZ) { Scale scale = Instantiate(GameManager.Instance.basePrefabs.emptyObject).AddComponent(); scale.Initialize(elementName, id, tags, isFirstGenerated, animatedObject); scale.animatedObject = animatedObject; scale.scaleX = scaleX; scale.scaleY = scaleY; scale.scaleZ = scaleZ; scale.animationReturnType = FlexibleReturnType.Before; scale.targetTransformSubmodule = (animatedObject as IHaveTransformSubmodule).transformSubmodule; //scale.timeDurationSubmodule.SetDuration(scaleX, scaleY, scaleZ); return scale; } public override void SetDefaultSubmodules() { timeDurationSubmodule = new TimeDurationSubmodule(this); } #endregion #region [核心动画逻辑] Core Animation Logic protected override void UpdateAnimation(float songTime, bool forceUpdate) { scaleX.UpdateFlexibleFloat(songTime); scaleY.UpdateFlexibleFloat(songTime); scaleZ.UpdateFlexibleFloat(songTime); bool isMiddleExecuting = scaleX.returnType is FlexibleReturnType.MiddleExecuting || scaleY.returnType is FlexibleReturnType.MiddleExecuting || scaleZ.returnType is FlexibleReturnType.MiddleExecuting; bool isSwitching = scaleX.isSwitchingReturnType || scaleY.isSwitchingReturnType || scaleZ.isSwitchingReturnType; if (forceUpdate || isMiddleExecuting) { if(!forceUpdate) animationReturnType = FlexibleReturnType.MiddleExecuting; // 检查是否是刚开始的第一帧,且有其它同类动画正在收尾(避免两帧叠加导致 ScaleX2) bool shouldSkipFirstFrame = false; if (!forceUpdate && isSwitching) { foreach (var s in ActiveScales) { if (s != this && s.targetTransformSubmodule == this.targetTransformSubmodule) { if (s.scaleX.isSwitchingReturnType || s.scaleY.isSwitchingReturnType || s.scaleZ.isSwitchingReturnType) { shouldSkipFirstFrame = true; break; } } } } if (!shouldSkipFirstFrame) { Vector3 currentScale = new Vector3(scaleX.value, scaleY.value, scaleZ.value); targetTransformSubmodule.scaleOffset += currentScale; targetTransformSubmodule.scaleDirtyMark = true; } } else if (isSwitching) { // 【收尾保护】如果这个动画是附着物体的“最后的动画”的结束,额外更新彻底将其设为终定值 bool isAnyOtherExecuting = false; foreach (var s in ActiveScales) { if (s != this && s.targetTransformSubmodule == this.targetTransformSubmodule) { if (s.scaleX.returnType is FlexibleReturnType.MiddleExecuting || s.scaleY.returnType is FlexibleReturnType.MiddleExecuting || s.scaleZ.returnType is FlexibleReturnType.MiddleExecuting) { isAnyOtherExecuting = true; break; } } } if (!isAnyOtherExecuting) { animationReturnType = FlexibleReturnType.MiddleExecuting; // 使系统认为有有效活动 Vector3 currentScale = new Vector3(scaleX.value, scaleY.value, scaleZ.value); targetTransformSubmodule.scaleOffset += currentScale; targetTransformSubmodule.scaleDirtyMark = true; } } else { animationReturnType = FlexibleReturnType.MiddleInterval; } } public override void ApplyTimeOffset(float offset) { base.ApplyTimeOffset(offset); scaleX.animations.ForEach(anim => anim.ApplyTimeOffset(offset)); scaleY.animations.ForEach(anim => anim.ApplyTimeOffset(offset)); scaleZ.animations.ForEach(anim => anim.ApplyTimeOffset(offset)); } #endregion } }