// 渲染游戏板
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using asap.core;
using asap.core.common;
using DG.Tweening;
using EventBlocks.UI;
using EventCubeMelt.Data;
using EventCubeMelt.UI;
using EventCubeMelt.Utils;
using Game;
using UnityEngine;
using UnityEngine.Serialization;
using UnityEngine.UI;
using Debug = UnityEngine.Debug;
using Quaternion = UnityEngine.Quaternion;
using Vector2 = UnityEngine.Vector2;
using Vector3 = UnityEngine.Vector3;
namespace EventCubeMelt
{
///
/// 新手引导「落子判定」在棋盘上的 Ghost 格(行/列与 一致)。
///
[Serializable]
public struct NewGuideGhostCheckCell
{
public int row;
public int col;
}
public class BoardRenderer : MonoBehaviour
{
#region 组件引用
[Header("预制体")] [SerializeField] private GameObject _cellPrefab;
[SerializeField] private GameObject _ghostCellPrefab;
[SerializeField] private GameObject _emptyCellPrefab;
//-
[SerializeField] private RectTransform bgTransform;
[SerializeField] private float boardPadding = 35f;
// [SerializeField] private float cellSpacing = 0.1f;
[SerializeField] private Transform _boardContainer;
[SerializeField] private Transform _ghostContainer;
[SerializeField] private PieceRenderer[] cellPiece; // 当前的Piece
[SerializeField]
private float putBeforeDisappearDuration = 0.2f;
//- 消除特效
[SerializeField] private Transform fxUIEventCubemeltEliminatable;
// 整行消除特效
[SerializeField] private Transform fxUIEventCubeMeltDisappear;
[SerializeField] private Transform fxUIEventCubeMeltColDisappear;
[SerializeField] private Transform fxUIEventCubeMeltDisappear6;
[SerializeField] private Transform fxUIEventCubeMeltColDisappear6;
[SerializeField] private Transform fxUIEventCubeMeltDisappear7;
[SerializeField] private Transform fxUIEventCubeMeltColDisappear7;
[Header("三行和三列消除特效")]
[SerializeField] private Transform fxUIEventCubemeltDisappearColorful;
[SerializeField] private Transform fxUIEventCubemeltDisappearColorfulVertical;
[SerializeField] private Transform fxUIEventCubemeltDisappearColorful6;
[SerializeField] private Transform fxUIEventCubemeltDisappearColorfulVertical6;
[SerializeField] private Transform fxUIEventCubemeltDisappearColorful7;
[SerializeField] private Transform fxUIEventCubemeltDisappearColorfulVertical7;
[Header("跳字特效")]
[SerializeField] private Transform fxInfoPiercing;
// 飞行的对象Controller
[Header("飞行特效")]
[SerializeField]
private RewardFlyBatchController _rewardFlyBatchCtrl;
//
[SerializeField]
private BatchedRewardFly _rewardFly;
[Header("延时")]
[SerializeField]
private float bombStartDelay = 0.2f;
[SerializeField]
private float bombFlyDelay = 0.2f;
// [SerializeField] private Transform fxUIEventCubemeltBroke;
[Header("新手引导")]
[Tooltip("NewGuide1:放手时需被 Ghost 覆盖的棋盘格;在 Inspector 中填写行/列,长度 0 则判定始终失败")]
[SerializeField]
private NewGuideGhostCheckCell[] _newGuide1GhostCheckCells =
{
new NewGuideGhostCheckCell { row = 0, col = 3 },
new NewGuideGhostCheckCell { row = 1, col = 3 },
new NewGuideGhostCheckCell { row = 1, col = 2 },
new NewGuideGhostCheckCell { row = 0, col = 2 },
};
#endregion
#region 私有成员
private TetrisBoardData _boardData;
private CellRenderer[,] _cellRenderers;
private GameObject[,] _emptyCellObjs;
private Dictionary _materialCache = new();
// 特效Trans
private Transform effectTrans;
// 对象池
//
// private readonly Queue _cellPool = new();
// 当前活跃的Cell
private readonly List _activeCells = new();
// 特效对象池
private IObjectPoolService _objectPoolService;
private IObjectPool _lineEffectPool;
// 特效消除池
private IObjectPool _disappearEffectRowPool;
private IObjectPool _disappearEffectColPool;
// 当前渲染隐藏
private readonly List _ghostCells = new();
private EventCubeMeltManager _thisEventManager;
private EventCubeMeltData _thisEventData;
public float TargetCellSize { get; set; } = 100;
// private Vector2 _cellSize;
// private Vector2 _cellSpace;
private float _contentWidth;
private float _contentHeight;
private Vector2 _contentZero;
// private float TargetCellSpace { get; set; } = 3f;
#endregion
#region 周期函数
private void Awake()
{
effectTrans = transform.Find("EffectPanel");
}
#endregion
#region 初始化
//
public void Initialize(int height, int width, List boardData)
{
ELog($"Initialize -> {height} {width}");
_objectPoolService = GContext.container.Resolve();
_lineEffectPool = _objectPoolService.CreatePool(fxUIEventCubemeltEliminatable, 0, 32);
_disappearEffectRowPool = _objectPoolService.CreatePool(fxUIEventCubeMeltDisappear, 0, 32);
_disappearEffectColPool = _objectPoolService.CreatePool(fxUIEventCubeMeltColDisappear, 0, 32);
_thisEventManager = GContext.container.Resolve();
_thisEventData = _thisEventManager.EventData;
_boardData = new TetrisBoardData(height, width);
_boardData.LoadData(boardData);
CreateGrid();
UpdateBgSize(height, width);
}
private void UpdateBgSize(int height, int width)
{
ELog("UpdateBgSize -> ");
var layoutGroup = _boardContainer.GetComponent();
var cellSize = layoutGroup.cellSize;
var spacing = layoutGroup.spacing;
// _cellSize = cellSize;
// _cellSpace = spacing;
// var topLeft = -(cellSize.x + spacing.x) * width * 0.5;
_contentWidth = cellSize.x * width + spacing.x * (width - 1);
_contentHeight = cellSize.y * height + spacing.y * (height - 1);
_contentZero = new Vector2(-_contentWidth * 0.5f, _contentHeight* 0.5f);
bgTransform.sizeDelta = new Vector2(width * (cellSize.x + spacing.x) + boardPadding * 2 , height * (cellSize.y + spacing.y) + boardPadding * 2);
}
private void CreateGrid()
{
ELog("CreateGrid -> ");
// 清空现有网格
foreach (Transform child in _boardContainer)
Destroy(child.gameObject);
foreach (Transform child in _ghostContainer)
Destroy(child.gameObject);
// 创建网格单元
_cellRenderers = new CellRenderer[_boardData.Height, _boardData.Width];
_emptyCellObjs = new GameObject[_boardData.Height, _boardData.Width];
for (var row = 0; row < _boardData.Height; row++)
{
for (var col = 0; col < _boardData.Width; col++)
{
var position = Vector3.zero;
CreateCell(row, col, position);
// 创建影子单元格
CreateEmptyCell(row, col, position);
}
}
}
private void CreateCell(int row, int col, Vector3 position)
{
// var parent = isGhost ? _ghostContainer : _boardContainer;
// var cellName = isGhost ? $"GhostCell_{row}_{col}" : $"Cell_{row}_{col}";
var parent = _boardContainer;
var cellName = $"Cell_{row}_{col}";
GameObject cellObj;
// if (_cellPool.Count > 0)
// {
// cellObj = _cellPool.Dequeue().gameObject;
// cellObj.name = cellName;
// cellObj.transform.position = position;
// cellObj.transform.parent = parent;
// cellObj.SetActive(true);
// }
// else
{
cellObj = Instantiate(_cellPrefab, position, Quaternion.identity, parent);
cellObj.name = cellName;
}
var cellRenderer = cellObj.GetComponent();
if (!cellRenderer)
cellRenderer = cellObj.AddComponent();
// 没什么用
// 初始化单元格大小
// cellRenderer.SetSize(_cellSize);
// if (isGhost)
// {
// _ghostRenderers[row, col] = cellRenderer;
// // cellRenderer.SetMaterial(_materialCache[CellType.Ghost]);
// }
// else
// {
// _cellRenderers[row, col] = cellRenderer;
// // cellRenderer.SetMaterial(_gridMaterial);
// // cellRenderer.SetColor(_gridColor);
// }
_cellRenderers[row, col] = cellRenderer;
cellRenderer.Row = row;
cellRenderer.Col = col;
// _activeCells.Add(cellRenderer);
}
private void CreateEmptyCell(int row, int col, Vector3 position)
{
var parent = _ghostContainer;
var cellName = $"Empty_{row}_{col}";
var cellObj = Instantiate(_emptyCellPrefab, position, Quaternion.identity, parent);
cellObj.name = cellName;
_emptyCellObjs[row, col] = cellObj;
}
#endregion
#region 更新渲染
public void UpdateBoard()
{
ELog("UpdateBoard-> ");
if (_boardData.ReSizeWithData(_thisEventData.BoardViewSize.y , _thisEventData.BoardViewSize.x , _thisEventData.BoardData))
{
RemakeBoard();
}
UpdateGridCells();
}
private void RemakeBoard()
{
ELog("ReMakeBoard-> ");
UpdateBgSize(_boardData.Height, _boardData.Width);
CreateGrid();
}
public void ClearBoard()
{
for (var row = 0; row < _boardData.Height; row++)
{
for (var col = 0; col < _boardData.Width; col++)
{
var cellRenderer = _cellRenderers[row, col];
cellRenderer.UpdateVisual(CellType.Empty);
}
}
}
//-
public void UpdateBoardWithAnim(Sequence sequence,float scaleDuration,float delayBetweenCells,out float delay)
{
ELog("UpdateBoardWithAnim");
UpdateBoard();
// _boardData.SetSize();
// _boardData.LoadData(_thisEventData?.BoardData);
// UpdateGridCells();
delay = 0;
var animationSequence = sequence;
var hasIndex = 0;
for (var row = 0; row < _boardData.Height; row++)
{
var has = false;
for (var col = 0; col < _boardData.Width; col++)
{
var cellType = _boardData[row, col];
var cell = _cellRenderers[row, col];
if (cellType != CellType.Empty)
{
cell.transform.localScale = Vector3.zero;
animationSequence.Insert(delay, cell.transform.DOScale(1.0f, scaleDuration)
.SetEase(Ease.OutBack)); // 使用弹性缓动效果,看起来更自然
has = true;
}
}
if (has)
{
hasIndex++;
delay = (hasIndex)* delayBetweenCells;
}
}
}
private void UpdateGridCells()
{
ELog("UpdateGridCells-> ");
// _activeCells.Clear();
for (var row = 0; row < _boardData.Height; row++)
{
for (var col = 0; col < _boardData.Width; col++)
{
var cellType = _boardData[row, col];
var cellRenderer = _cellRenderers[row, col];
cellRenderer.UpdateVisual(cellType,_boardData.GetGridValue(row,col-1),_boardData.GetGridValue(row +1,col - 1) ,_boardData.GetGridValue(row +1,col ));
}
}
}
//
[Header("清除特效时长")]
[SerializeField]
private float disappearTimeDuration = 1f;
private async Task DoGridClearAndAnims(List rows,
List cols,
List<(int row,int col,int value,int newRow,int newCol)> listBombs)
{
ELog("DoGridClearAndAnims-> ");
var list = new List();
var countClear = rows.Count + cols.Count;
foreach (var row in rows)
{
list.Add(DoRowDisappearEffect(row,countClear,listBombs));
}
//ClearCol
foreach (var col in cols)
{
list.Add(DoColDisappearEffect(col,countClear,listBombs));
}
if (rows.Count + cols.Count > 0)
{
GContext.Publish(new EventUISound("audio_ui_block_cube_clear"));
}
await Task.WhenAll(list);
RemoveDisappearEffect();
}
private async Task DoColDisappearEffect(int col,int count,List<(int row,int col,int value,int newRow,int newCol)> listBombs)
{
await Awaiters.NextFrame;
var list = new List();
list.Add(AddColDisappearEffect(col, count ));
var ls = listBombs.Select(item => (item.row, item.col)).ToList();
for (var i = 0; i< _boardData.Height; i++)
{
var cellRenderer = _cellRenderers[i,col];
// _ = cellRenderer.RunClearAnimation(_boardData.Height - i ,count >= 3);
if (!ls.Contains((i, col)))
{
// list.Add(cellRenderer.RunBombAnimation(_boardData.Height - i,true,2f));
// }
// else
// {
list.Add(cellRenderer.RunClearAnimation(_boardData.Height - i ,count >= 3));
}
}
await Task.WhenAll(list);
}
private async Task DoRowDisappearEffect(int row,int count,List<(int row,int col,int value,int newRow,int newCol)> listBombs)
{
await Awaiters.NextFrame;
var list = new List();
list.Add(AddRowDisappearEffect(row, count));
var ls = listBombs.Select(item => (item.row, item.col)).ToList();
for (var i = 0; i< _boardData.Width; i++)
{
var cellRenderer = _cellRenderers[row, i];
if (!ls.Contains((row, i)))
{
list.Add(cellRenderer.RunClearAnimation(i, count >= 3));
}
}
await Task.WhenAll(list);
}
private bool TryScreenToGrid(Vector2 screenPos, out Vector2Int grid)
{
var canvas = GetComponentInParent