using System; using System.Collections; using System.Collections.Generic; using AibisDream.Framework; using DG.Tweening; using UnityEngine; namespace AibisDream.FixSystem { [RequireComponent(typeof(Collider2D), typeof(Rigidbody2D))] public class CoolingBottle : MonoBehaviour, IMoveable { private const float RotateTime = 0.3f; private const float SnapMoveTime = 0.3f; private static readonly Vector3 ClockwiseAngle = new(0, 0, 0); private static readonly Vector3 ClockWiseScale = new(1, 1, 1); private static readonly Vector3 AnticlockwiseAngle = new(0, 0, 90); private static readonly Vector3 AnticlockwiseScale = new(1.45f, 1.45f, 1); public CoolingBottleData data; #region 引用 private Sprite _verticalSprite; private Sprite _horizontalSprite; public BottleSlot curSnapSlot; public readonly HashSet targetSnapSlotSet = new(); private Rigidbody2D _rb; private SpriteRenderer _renderer; #endregion private void Awake() { InitRefs(); } private void InitRefs() { _rb = GetComponent(); _renderer = GetComponent(); } #region 移动逻辑 public bool IsBlock { get; set; } public void StartMove() { _rb.isKinematic = false; gameObject.layer = LayerMask.NameToLayer("Clinic"); // 开始移动时就切换成横版 Rotate(false); } public void Rotate(bool isVertical) { StartCoroutine(RotateAsync(isVertical)); } /// /// 旋转瓶子 /// /// 是否竖直 /// private IEnumerator RotateAsync(bool isVertical) { var angle = isVertical ? ClockwiseAngle : AnticlockwiseAngle; var scale = isVertical ? ClockWiseScale : AnticlockwiseScale; // 动画序列 var sq = DOTween.Sequence(); Tween rotate = transform.DORotate(angle, RotateTime, RotateMode.FastBeyond360); sq.Join(rotate); Tween scaleTw = transform.DOScale(scale, RotateTime); sq.Join(scaleTw); yield return sq.WaitForCompletion(); } public void Move(Vector2 mousePos) { _rb.MovePosition(mousePos); } public void StopMove() { if (TryFindClosestSlot(out var targetSlot)) { // 从原有Slot移出 curSnapSlot.RemoveBottle(); // 更新到新的Slot curSnapSlot = targetSlot; curSnapSlot.ChangeSlot(this); } targetSnapSlotSet.Clear(); // 吸附到目标位置 _rb.isKinematic = true; gameObject.layer = LayerMask.NameToLayer("Default"); curSnapSlot.InsertSlot(this); transform.DOMove(curSnapSlot.transform.position, SnapMoveTime); // TODO 停止描边 } public bool TryFindClosestSlot(out BottleSlot targetSlot) { // 没有目标Slot,返回 if (targetSnapSlotSet.Count == 0) { targetSlot = null; return false; } // 寻找最近的Slot var shortestDistance = float.MaxValue; BottleSlot closestSlot = null; foreach (var slot in targetSnapSlotSet) { var distance = Vector3.Distance(slot.transform.position, transform.position); if (distance < shortestDistance) { shortestDistance = distance; closestSlot = slot; } } targetSlot = closestSlot; return true; } #endregion public void Load(CoolingBottleData targetData) { data = targetData; _verticalSprite = ResourceKit.LoadSpriteFromPsd($"Art/Fix/Cooling/冷却系统/{data.verticalSprite}"); _renderer.sprite = _verticalSprite; } } [Serializable] public struct CoolingBottleData { public string name; public string description; public string verticalSprite; public string horizontalSprite; } }