Files
ft/Client/Assets/Scripts/Duel/UI/DuelRandomMapPanel.cs
2026-06-29 21:18:33 +08:00

320 lines
12 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<MapData> mapDatas;
List<int> newIDs;
bool isClose;
[System.NonSerialized]
public bool IsStop;
bool isUP;
private void Awake()
{
_tables = GContext.container.Resolve<Tables>();
uIService = GContext.container.Resolve<IUIService>();
FDM = GContext.container.Resolve<FishingDuelManager>();
Content = transform.Find("Viewport/Content").GetComponent<RectTransform>();
img_map = transform.Find("Viewport/Content/Item").gameObject;
height = img_map.GetComponent<RectTransform>().rect.height;
img_map.SetActive(false);
text_title = transform.Find("title").gameObject;
text_map = transform.Find("title/text_map").GetComponent<TMP_Text>();
}
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<Tables>();
var lastMapID = GContext.container.Resolve<PlayerData>().lastMapId;
mapDatas = _tables.TbMapData.DataList;
List<int> indexs = new List<int>
{
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<Image>();
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;
}
}
}