Files
ft/Client/Assets/Scripts/EventCubeMelt/PieceRenderer.cs
2026-06-29 21:18:33 +08:00

537 lines
18 KiB
C#

// 预览和拖动用的方块组
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using asap.core;
using DG.Tweening;
using EventCubeMelt.UI;
using EventCubeMelt.Utils;
using Game;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using Debug = UnityEngine.Debug;
namespace EventCubeMelt
{
public class PieceRenderer : MonoBehaviour,IPointerDownHandler,IPointerUpHandler, IBeginDragHandler, IDragHandler, IEndDragHandler
{
public int OffsetY { get; set; } = 320;
public int OffsetYWithDelta { get; set; } = 320;
public float ScaleFactor { get; set; } = 100F / 40;
// 棋盘目标大小
public float TargetSize { get; set; } = 100F;
public float DistanceFactor { get; set; } = 0.2f;
// 当前的RectTransform
[HideInInspector] public RectTransform rectTransform;
// 删除
public TetrominoData Data { get; set; }
public int Index { get; set; }
// 对应的数值
//
private Transform[,] _cellTransforms;
// 记录当前顶端坐标的位置
private Vector2Int _currentPosition;
// 数值
private EventCubeMeltManager _thisEventManager;
// 记录当前 picece 和 第一个顶点的 位置
public Vector2 OffsetXY { get; set; }
[SerializeField] private BoardRenderer boardRenderer;
//
private UIDragManager _dragManager;
//
private Canvas _canvas;
//- 可拖动
private PieceRenderer _dragPiece;
private bool _isDrag = false;
private Transform _childRoot;
private Transform _hotPlace;
#region
private void Awake()
{
rectTransform = GetComponent<RectTransform>();
// canvasGroup = GetComponent<CanvasGroup>();
_canvas = GetComponentInParent<Canvas>();
_hotPlace = transform.Find("hot_place");
_childRoot = transform.Find("ChildRoot");
}
private void Start()
{
_dragManager = UIDragManager.Instance;
}
private void OnEnable()
{
}
private void OnDisable()
{
}
private void OnDestroy()
{
}
#endregion
#region Log
private static void LogWarning(string message)
{
Debug.LogWarning($"<color=yellow>PieceRender => {message}</color>");
}
private static void ELog(string message)
{
#if UNITY_EDITOR
if (!EventCubeMeltLogPolicy.EnableELog) return;
Debug.Log($"<color=orange> PieceRender => {message} </color>");
#endif
}
#endregion
#region
public void Initialize(int height, int width)
{
ELog($"Initialize height={height} width={width} index={Index}");
_thisEventManager = GContext.container.Resolve<EventCubeMeltManager>();
var datas = _thisEventManager.GetMeltPieceData(Index);
Data = new TetrominoData(height, width);
ELog($"Initialize dataLoaded dataRef={Data} pieceDataCount={datas?.Count ?? 0}");
Data.LoadData(datas);
CreateGrid();
var layout = _childRoot.GetComponent<GridLayoutGroup>();
OffsetXY = new Vector2((layout.cellSize.x + layout.spacing.x) * 2, (layout.cellSize.y + layout.spacing.y) * 2) * -1;
// Log($"OffsetXY -> {OffsetXY}");
}
public void LoadDataToGrid(TetrominoData data)
{
Data = (TetrominoData)data.Clone();
CreateGrid();
UpdateGridVisual();
}
public void UpdatePiece()
{
ELog($"UpdatePiece {Index} ");
var datas = _thisEventManager.GetMeltPieceData(Index);
Data.LoadData(datas);
UpdateGridVisual();
}
private async void UpdateGridVisual()
{
for (var row = 0; row < Data.Height; ++row)
{
for (var col = 0; col < Data.Width; ++col)
{
var cellRenderer = _cellTransforms[row, col].GetComponent<CellRenderer>();
if (!cellRenderer)
cellRenderer = _cellTransforms[row, col].gameObject.AddComponent<CellRenderer>();
cellRenderer?.UpdatePieceVisual(Data[row,col], Data[row,col-1],Data[row +1,col - 1] ,Data[row +1,col ] );
}
}
}
public void CleanPiece()
{
for (var row = 0; row < Data.Height; ++row)
{
for (var col = 0; col < Data.Width; ++col)
{
var cellRenderer = _cellTransforms[row, col].GetComponent<CellRenderer>();
if (!cellRenderer)
cellRenderer = _cellTransforms[row, col].gameObject.AddComponent<CellRenderer>();
cellRenderer?.UpdatePieceVisual(CellType.Empty);
cellRenderer?.SetShadowAndDisplay(ShadowType.None);
}
}
}
public void UpdatePieceWithAnim(Sequence sequence,float scaleDuration, float delay)
{
UpdatePiece();
transform.localScale = Vector3.zero;
sequence.Insert(delay, transform.DOScale(1.0f, scaleDuration)
.SetEase(Ease.OutBack)); // 使用弹性缓动效果,看起来更自然
}
//-
// 返回最左上角的位置,然后进入检测
public Vector3 GetPiecePosition()
{
var diff = GetCenterPosition() - GetFirstPosition();
// ELog($"GetPiecePosition0 -> {diff}");
var rt = GetScreenPosition() - diff;
return rt;
}
public Vector3 GetFirstPosition()
{
var cb0 = _childRoot.Find("CubeMeltCube_01");
// return cb0.transform.position - new Vector3(TargetSize * 0.5f -45f,0);
return cb0.transform.position;
}
public Vector3 GetCenterPosition()
{
var cb = _childRoot.Find("CubeMeltCube_13");
return cb.transform.position;
}
public Vector3 GetScreenPosition()
{
var canvas = GetComponentInParent<Canvas>();
var screenPosition = RectTransformUtility.WorldToScreenPoint(canvas.worldCamera, transform.position);
return screenPosition;
}
public void CreateGrid()
{
_cellTransforms = new Transform[Data.Width,Data.Height];
var cellList = GetDirectChildrenArray();
// 添加组件
for (var row = 0; row < Data.Height; ++row)
{
for (var col = 0; col < Data.Width; ++col)
{
_cellTransforms[row, col] = cellList[row * Data.Width + col];
var cellRenderer = _cellTransforms[row, col].GetComponent<CellRenderer>();
if (!cellRenderer)
{
cellRenderer = _cellTransforms[row, col].gameObject.AddComponent<CellRenderer>();
}
// cellRenderer?.InitForPiece();
}
}
}
private Transform[] GetDirectChildrenArray()
{
_childRoot = transform.Find("ChildRoot");
if (!_childRoot)
_childRoot = transform;
var arr = new Transform[_childRoot.childCount];
for (var i = 0; i < arr.Length; i++)
arr[i] = _childRoot.GetChild(i);
return arr;
}
#endregion
public void BeginVisual()
{
// ELog($"BeginVisual-> {gameObject.name}");
}
public void SetBlocksRaycasts(bool b)
{
var canvasGroupArr = GetComponentsInChildren<CanvasGroup>();
foreach (var canvasGroup in canvasGroupArr)
{
canvasGroup.blocksRaycasts = b;
}
}
public void CopyData(PieceRenderer otherPiece)
{
OffsetXY = otherPiece.OffsetXY;
Data = otherPiece.Data;
OffsetY = otherPiece.OffsetY;
ScaleFactor = otherPiece.ScaleFactor;
TargetSize = otherPiece.TargetSize;
}
private async Task<bool> SpawnNewPieceData(int index, int clearCount)
{
if (!_isIgnoreChecked)
{
_isIgnoreChecked = true;
_sw = Stopwatch.StartNew();
await _thisEventManager.SpawnNewPiece(index,clearCount);
_sw.Stop();
long el = _sw.ElapsedMilliseconds;
_isIgnoreReqDelay = (el > 200);
}
else
{
await _thisEventManager.SpawnNewPiece(index,clearCount);
}
return _isIgnoreReqDelay;
}
// 生成新的Piece
public async Task SpawnNewPiece(int clearCount = 0)
{
await _thisEventManager.SpawnNewPiece(Index,clearCount);
RunSpawnNewPiece();
}
private void RunSpawnNewPiece()
{
{
UpdatePiece();
RestorePiece();
}
transform.localScale = Vector3.zero;
transform.DOScale(1.0f, 0.3f).SetEase(Ease.OutBack);
ELog("RunSpawnNewPieceFinished");
}
public void DestroyDragPiece()
{
Destroy(_dragPiece?.gameObject);
_dragPiece = null;
}
public void OnPointerDown(PointerEventData eventData)
{
ELog($"OnPointDown-> {gameObject.name}");
if (_thisEventManager == null)
return;
if (_thisEventManager.EventData == null)
return;
if (_thisEventManager.EventData.IsFinished)
return;
if (_thisEventManager.EventData.TicketCount <= 0)
{
GContext.Publish(new EventCubeMeltShowNeoNormalPack());
return;
}
if (_thisEventManager.IsInGuideAnim())
GContext.Publish(new EventCubeMeltGuideFingerHide());
GContext.Publish(new EventUISound("audio_ui_block_cube_up"));
CreateDragPiece(eventData);
SetPieceVisible(false);
}
public void OnPointerUp(PointerEventData eventData)
{
// throw new NotImplementedException();
ELog($"OnPointerUp -> {eventData} {gameObject.name}");
//
if (!_isDrag)
{
RestorePiece();
}
}
public void RestorePiece()
{
DestroyDragPiece();
SetPieceVisible(true);
}
private void SetPieceVisible(bool visible)
{
foreach (Transform trans in transform)
{
trans.gameObject.SetActive(visible);
}
}
public void OnBeginDrag(PointerEventData eventData)
{
ELog($"OnBeginDrag-> {gameObject.name} _dragPiece: {_dragPiece}");
if (_dragPiece)
{
_isDrag = true;
// _dragPiece.BeginVisual();
_dragPiece.SetBlocksRaycasts(false);
_vibrationDelta = true;
SaveOriginPos(eventData.position);
var diff = UpdateDragDistance(eventData);
UpdateDragPiecePos(eventData,diff);
}
}
private bool _vibrationDelta;
private void OnDragVibration()
{
if (_vibrationDelta)
{
GContext.Publish(new VibrationData(HapticTypes.SoftImpact));
_vibrationDelta = false;
}
}
public void OnDrag(PointerEventData eventData)
{
// ELog($"OnDrag-> {gameObject.name} _dragPiece: {_dragPiece}");
if (!_dragPiece)
return;
OnDragVibration();
var diff = UpdateDragDistance(eventData);
UpdateDragPiecePos(eventData,diff); // EventSystem 自动驱动
boardRenderer.UpdateVisual(_dragPiece,eventData.position);
}
private float UpdateDragDistance(PointerEventData eventData)
{
var diff = eventData.position.y - _originPos.y;
// ELog($"UpdateDragDistance -> {diff}");
if (diff < 0)
diff = 0;
return diff * DistanceFactor;
}
// ReSharper disable once AsyncVoidMethod
public void OnEndDrag(PointerEventData eventData)
{
ELog($"OnEndDrag-> {gameObject.name}");
if (_dragPiece)
{
CheckEndDrag(eventData);
}
_isDrag = false;
}
// private ProfileScope ps = new ProfileScope();
private Stopwatch _sw;
// 需要先测试一下是否需要高这个东西
private bool _isIgnoreReqDelay = false;
private bool _isIgnoreChecked = false;
public async void CheckEndDrag(PointerEventData eventData)
{
await Awaiters.NextFrame;
//- 处理最后
GContext.Publish(new EventUISound("audio_ui_block_cube_down"));
if (_thisEventManager.IsInGuideAnim())
{
if ( Index != _thisEventManager.GuideIndex || !boardRenderer.SatisfyNewGuide1(_dragPiece))
{
GContext.Publish(new VibrationData(HapticTypes.RigidImpact));
boardRenderer.ClearGhostGrid(true);
boardRenderer.RemoveLineEffect();
boardRenderer.RemoveDisappearEffect();
// DestroyDragPiece();
// SetPieceVisible(true);
PubBackPiece();
GContext.Publish(new EventNewGuideFingerStart());
return;
}
GContext.Publish(new EventNewGuideFingerFinish());
_thisEventManager?.SetIsInGuideAnim(false);
}
var ret = boardRenderer.TryPlaceDown(_dragPiece);
if (ret)
{
// ps.L_ProfileScope("TryPlaceDown");
_thisEventManager?.AddTicket(-1);
// ClearGridAndCollectItems( pieceId,out rows,out cols, out list,out listBomb);
boardRenderer.ClearGridAndCollectItems(Index, out var rows,out var cols, out var list,out var listBomb );
var clearCount = rows.Count + cols.Count;
// ps.L_ProfileScopeEnd();
// ps.L_ProfileScope("SpawnNewPiece");
// if (!_isIgnoreChecked)
// {
// _isIgnoreChecked = true;
// _sw = Stopwatch.StartNew();
// await SpawnNewPiece(clearCount);
// _sw.Stop();
// long el = _sw.ElapsedMilliseconds;
// _isIgnoreReqDelay = (el > 200);
// }
// else
// {
// await SpawnNewPiece(clearCount);
// }
// ps.L_ProfileScopeEnd();
// ps.L_ProfileScope("RestorePiece");
// ps.L_ProfileScopeEnd();
// ps.L_ProfileScope("OnGridAnimation");
ELog($"CheckEndDrag ignoreReqDelay={_isIgnoreReqDelay}");
DestroyDragPiece();
var task1 = SpawnNewPieceData(Index, clearCount);
var task2 = boardRenderer.OnGridAnimation(Index, rows, cols, list, listBomb, false);
await task1;
// var taskList = new List<Task>
// {
// SpawnNewPieceData(Index,clearCount),
// boardRenderer.OnGridAnimation(Index, rows, cols, list, listBomb,true)
// };
// await Task.WhenAll(taskList);
RunSpawnNewPiece();
await task2;
}
else
{
GContext.Publish(new VibrationData(HapticTypes.RigidImpact));
PubBackPiece();
}
}
private void PubBackPiece()
{
RestorePiece();
GContext.Publish(new EventUISound("audio_ui_block_cube_back_down"));
}
private void UpdateDragPiecePos(PointerEventData e,float diff = 0 )
{
var offset = _dragPiece.OffsetYWithDelta + diff;
var screenPosition = e.position;
var scrPos = new Vector2(screenPosition.x, screenPosition.y + offset);
RectTransformUtility.ScreenPointToWorldPointInRectangle( _dragManager.dragContainer, scrPos, _canvas.worldCamera, out var worldPos);
_dragPiece.rectTransform.position = worldPos;
}
private async void CreateDragPiece(PointerEventData eventData)
{
try
{
_dragPiece = _dragManager.CreateDragPiece(gameObject, eventData);
_dragPiece.gameObject.SetActive(false);
await Awaiters.NextFrame;
_dragPiece.gameObject.SetActive(true);
_dragPiece.BeginVisual();
}
catch (Exception e)
{
LogWarning($"CreateDragPieceFailed error={e.Message}");
}
}
//
private Vector3 _originPos = Vector3.zero;
public void SaveOriginPos(Vector3 position)
{
_originPos = position;
}
}
}