using asap.core; using cfg; using DG.Tweening; using GameCore; using System.Collections; using System.Collections.Generic; using System.Threading.Tasks; using TMPro; using UnityEngine; using UnityEngine.UI; public class DuelRandomMapPanel : MonoBehaviour { public Transform arrow1; public Transform arrow2; public float StartDelay = 0.5f; public float StartDuration = 0.35f; public float AccNum = 3; public float LoopDuration = 0.125f; public int[] ArrowRotationRand = new[] { 10, 15 }; public float[] SelectedMapNumRandUp = new[] { 2f, 5f }; public float[] SelectedMapNumRandDown = new[] { 4f, 7f }; int MapNum = 2; float BackRatio = 2f; FishingDuelManager FDM; RectTransform Content; GameObject img_map; int allCount = 5; float height; IUIService uIService; GameObject text_title; TMP_Text text_map; Tables _tables; List mapDatas; List newIDs; bool isClose; [System.NonSerialized] public bool IsStop; bool isUP; private void Awake() { _tables = GContext.container.Resolve(); uIService = GContext.container.Resolve(); FDM = GContext.container.Resolve(); Content = transform.Find("Viewport/Content").GetComponent(); img_map = transform.Find("Viewport/Content/Item").gameObject; height = img_map.GetComponent().rect.height; img_map.SetActive(false); text_title = transform.Find("title").gameObject; text_map = transform.Find("title/text_map").GetComponent(); } public void StartMap() { isUP = Random.value < 0.5f; float t = Random.Range(0f, 1f); if (isUP) { BackRatio = SelectedMapNumRandUp[0] + (SelectedMapNumRandUp[1] - SelectedMapNumRandUp[0]) * t; } else { BackRatio = SelectedMapNumRandDown[0] + (SelectedMapNumRandDown[1] - SelectedMapNumRandDown[0]) * t; } MapNum = Mathf.CeilToInt(BackRatio); IsStop = false; text_title.SetActive(false); isClose = false; _tables = GContext.container.Resolve(); var lastMapID = GContext.container.Resolve().lastMapId; mapDatas = _tables.TbMapData.DataList; List indexs = new List { 0,1 }; for (int i = 2; i < mapDatas.Count; i++) { if (mapDatas[i].ID <= lastMapID) { indexs.Insert(Random.Range(0, indexs.Count), i); } else { break; } } while (indexs.Count < allCount + MapNum) { indexs.AddRange(indexs); } newIDs = indexs; for (int i = 0; i < allCount; i++) { SetMapBg(mapDatas[newIDs[i]].Bg); } SetMapBg(mapDatas[newIDs[0]].Bg); for (int i = 0; i < MapNum - 1; i++) { SetMapBg(mapDatas[newIDs[allCount + i]].Bg); } StartCoroutine(Play()); } public void SetClose() { int mapId = FDM.MapId; var mapData = _tables.TbMapData.DataMap[mapId]; SetMapBg(mapData.Bg); SetMapBg(mapDatas[newIDs[0]].Bg); text_map.text = LocalizationMgr.GetText(mapData.Name_l10n_key); isClose = true; } void SetMapBg(string bg) { GameObject go = Instantiate(img_map, Content); Image image = go.transform.GetChild(0).GetComponent(); go.SetActive(true); uIService.SetImageSprite(image, bg); } public void Stop() { StopAllCoroutines(); Content.DOKill(); } IEnumerator PlayArrow() { int cur = 1; float acc = (StartDuration - LoopDuration) / AccNum; float time = StartDuration; float arrowTime = time / 4; yield return new WaitForSeconds(time); int ArrowRotation = Random.Range(ArrowRotationRand[0], ArrowRotationRand[1]); arrow1.DOLocalRotate(new Vector3(0, 0, ArrowRotation), arrowTime); arrow2.DOLocalRotate(new Vector3(0, 0, -ArrowRotation), arrowTime); yield return new WaitForSeconds(arrowTime); arrowTime = time / 4; while (cur < AccNum) { cur++; time -= acc; arrowTime = arrowTime + time / 4; ArrowRotation = Random.Range(ArrowRotationRand[0], ArrowRotationRand[1]); arrow1.DOLocalRotate(new Vector3(0, 0, -ArrowRotation), arrowTime); arrow2.DOLocalRotate(new Vector3(0, 0, ArrowRotation), arrowTime); yield return new WaitForSeconds(arrowTime); arrowTime = time / 2; ArrowRotation = Random.Range(ArrowRotationRand[0], ArrowRotationRand[1]); arrow1.DOLocalRotate(new Vector3(0, 0, ArrowRotation), arrowTime); arrow2.DOLocalRotate(new Vector3(0, 0, -ArrowRotation), arrowTime); yield return new WaitForSeconds(arrowTime); arrowTime = time / 4; } while (!isClose) { arrowTime = LoopDuration / 2; ArrowRotation = Random.Range(ArrowRotationRand[0], ArrowRotationRand[1]); arrow1.DOLocalRotate(new Vector3(0, 0, -ArrowRotation), arrowTime); arrow2.DOLocalRotate(new Vector3(0, 0, ArrowRotation), arrowTime); yield return new WaitForSeconds(arrowTime); arrowTime = LoopDuration / 2; ArrowRotation = Random.Range(ArrowRotationRand[0], ArrowRotationRand[1]); arrow1.DOLocalRotate(new Vector3(0, 0, ArrowRotation), arrowTime); arrow2.DOLocalRotate(new Vector3(0, 0, -ArrowRotation), arrowTime); yield return new WaitForSeconds(arrowTime); } } Coroutine playArrow; IEnumerator Play() { Content.anchoredPosition = Vector2.zero; yield return new WaitForSeconds(StartDelay); playArrow = StartCoroutine(PlayArrow()); float subHeight = height * AccNum; float time = 2 * AccNum / (1 / StartDuration + 1 / LoopDuration); Content.DOAnchorPosY(subHeight, time).SetEase(Ease.InQuad); yield return new WaitForSeconds(time); time = LoopDuration * (allCount - AccNum); Content.DOAnchorPosY(allCount * height, time).SetEase(Ease.Linear); yield return new WaitForSeconds(time); time = LoopDuration * allCount; while (!isClose) { Content.anchoredPosition = Vector2.zero; Content.DOAnchorPosY(allCount * height, time).SetEase(Ease.Linear); yield return new WaitForSeconds(time); } float ratio = MapNum - BackRatio; if (ratio > 0.01) { time = LoopDuration * ratio; Content.DOAnchorPosY((allCount + ratio) * height, time).SetEase(Ease.Linear); yield return new WaitForSeconds(time); } StartCoroutine(Close()); } IEnumerator Close() { float time2 = 0.4f; StopCoroutine(playArrow); arrow1.DOKill(); arrow2.DOKill(); arrow1.DOLocalRotate(new Vector3(0, 0, 0), time2); arrow2.DOLocalRotate(new Vector3(0, 0, 0), time2); yield return SharkAni().AsIEnumerator(); //yield return new WaitForSeconds(time2); IsStop = true; GContext.Publish(new VibrationData(HapticTypes.HeavyImpact)); text_title.SetActive(true); } [Header("物理参数")] [SerializeField, Min(1), Tooltip("弹簧刚度 k (N·m/rad)")] private float springStiffness = 20f; [SerializeField, Min(1), Tooltip("阻尼系数 (N·m·s/rad)")] private float dampingRatio = 5f; [SerializeField, Min(0.1f), Tooltip("动摩擦 (N·m) T_k")] private float dynamicFriction = 3f; [SerializeField, Min(0.1f), Tooltip("转动惯量 (kg·m²)")] private float momentOfInertia = 1.0f; //匀速进入减速的角度,是相对于第一次减速阶段稳定角的角度,正数(减)在奖励顺时针方向,负数(加)在目标点逆时针方向 private float valueOffset2 = 200f; [Header("减速阶段")] [SerializeField, Tooltip("停留左侧时,匀速进入减速的角度,是相对于第一次减速阶段稳定角的角度")] private float[] valueOffsetToTmpStableUp = new float[2] { 0.2f, 0.4f }; [SerializeField, Tooltip("停留右侧时,匀速进入减速的角度")] private float[] valueOffsetToTmpStableDown = new float[2] { -0.2f, -0.4f }; [Header("停止条件")] [SerializeField, Min(10f), Tooltip("第一阶段减速的速度停止条件")] private float velocityStop = 10f; [SerializeField, Min(10f), Tooltip("第二阶段减速的速度停止条件,!!!必须小于 velocityStop !!! ")] private float velocityStopFinal = 10f; [SerializeField, Tooltip("第一阶段减速的角度停止条件")] private float valueStopRatio = 1f; [SerializeField, Tooltip("第二阶段减速的角度停止条件")] private float valueStopFinalRatio = 0.1f; private float currentValue = 0f; private float currentVelocity = 0f; private float targetValue = 0f; bool revertTargetValue = false; bool effectTask; private void DecelerationgAni(float deltaTime) { float valueError = currentValue - targetValue; int direction = valueError > 0 ? 1 : -1; float springTorque = springStiffness * Mathf.Abs(valueError) * direction; float dampingTorque = -dampingRatio * currentVelocity; float frictionTorque = CalculateFrictionTorque(); float totalTorque = springTorque + dampingTorque + frictionTorque; float angularAcceleration = totalTorque / momentOfInertia; currentVelocity += angularAcceleration * deltaTime; CheckStopCondition(); } private float CalculateFrictionTorque() { return -dynamicFriction * Mathf.Sign(currentVelocity); } private void CheckStopCondition() { float valueError = Mathf.Abs(currentValue - targetValue); bool inPosition = valueError < Mathf.Abs(valueStopRatio); bool slowEnough = Mathf.Abs(currentVelocity) < velocityStop; bool inPositionFinal = valueError < Mathf.Abs(valueStopFinalRatio); bool slowEnoughFinal = Mathf.Abs(currentVelocity) < velocityStopFinal; if (inPosition && slowEnough && !revertTargetValue) { targetValue -= valueOffset2; revertTargetValue = true; } else if (inPositionFinal && slowEnoughFinal) { currentVelocity = 0f; currentValue = targetValue; revertTargetValue = false; effectTask = false; } } public async Task SharkAni() { float tmpValue2; if (isUP) { tmpValue2 = UnityEngine.Random.Range(valueOffsetToTmpStableUp[0], valueOffsetToTmpStableUp[1]); } else { tmpValue2 = UnityEngine.Random.Range(valueOffsetToTmpStableDown[0], valueOffsetToTmpStableDown[1]); } valueOffset2 = tmpValue2 * height; revertTargetValue = false; targetValue = (allCount + MapNum) * height; targetValue += valueOffset2; currentValue = allCount * height; currentVelocity = -height / LoopDuration; effectTask = true; while (effectTask) { DecelerationgAni(Time.deltaTime); currentValue -= currentVelocity * Time.deltaTime; Content.anchoredPosition = new Vector2(0, currentValue); await Awaiters.NextFrame; } } }