320 lines
12 KiB
C#
320 lines
12 KiB
C#
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;
|
||
}
|
||
}
|
||
}
|