using System.Collections.Generic; using Godot; /// <summary> /// RoomInfo 中用于存放静态Sprite的功能类 /// </summary> public partial class RoomStaticSprite : Node2D, IDestroy { public bool IsDestroyed { get; private set; } private readonly List<List<FreezeSprite>> _list = new List<List<FreezeSprite>>(); private readonly InfiniteGrid<List<FreezeSprite>> _grid = new InfiniteGrid<List<FreezeSprite>>(); private readonly RoomInfo _roomInfo; //网格划分的格子大小 private readonly Vector2I _step; //当前残骸数量 private int _count = 0; //最大残骸数量 private int _maxCount = 1000; //每个格子中最大残骸数量 private int _stepMaxCount = 30; private int _num = 0; public RoomStaticSprite(RoomInfo roomInfo) { _roomInfo = roomInfo; _step = new Vector2I(30, 30); } public void Destroy() { if (IsDestroyed) { return; } IsDestroyed = true; _grid.ForEach((x, y, data) => { foreach (var spriteData in data) { spriteData.Destroy(); } data.Clear(); return true; }); _grid.Clear(); QueueFree(); } /// <summary> /// 添加静态精灵 /// </summary> public void AddFreezeSprite(FreezeSprite freezeSprite) { var pos = ToGridPosition(freezeSprite.Position); var list = _grid.Get(pos); if (list == null) { list = new List<FreezeSprite>(); _grid.Set(pos, list); _list.Add(list); } list.Add(freezeSprite); _count++; if (list.Count > _stepMaxCount) //检测单个step中残骸是否超出最大数量 { var sprite = list[0]; list.RemoveAt(0); sprite.Destroy(); _count--; } else if (_count > _maxCount) //检测所有残骸是否超出最大数量 { if (_num <= 0 || _list[0].Count == 0) { _num = 5; _list.Sort((l1, l2) => l2.Count - l1.Count); } else { _num--; } var tempList = _list[0]; if (tempList.Count > 0) { var sprite = tempList[0]; tempList.RemoveAt(0); sprite.Destroy(); _count--; } } } /// <summary> /// 移除静态精灵 /// </summary> public void RemoveFreezeSprite(FreezeSprite freezeSprite) { var pos = ToGridPosition(freezeSprite.Position); var list = _grid.Get(pos); if (list != null) { if (list.Remove(freezeSprite)) { _count--; } } } /// <summary> /// 获取指定圆形范围内所有已经被冻结的物体 /// </summary> /// <param name="position">圆形中心点坐标</param> /// <param name="radius">圆形半径</param> /// <param name="unfreeze">是否解冻物体</param> public List<FreezeSprite> CollisionCircle(Vector2 position, float radius, bool unfreeze = false) { var len = radius * radius; var result = new List<FreezeSprite>(); var startPosition = ToGridPosition(new Vector2(position.X - radius, position.Y - radius)); var endPosition = ToGridPosition(new Vector2(position.X + radius, position.Y + radius)); for (var x = startPosition.X; x <= endPosition.X; x++) { for (var y = startPosition.Y; y <= endPosition.Y; y++) { var data = _grid.Get(x, y); if (data != null) { for (var i = 0; i < data.Count; i++) { var freezeSprite = data[i]; if (position.DistanceSquaredTo(freezeSprite.Position) < len) { result.Add(freezeSprite); if (unfreeze) { freezeSprite.HandlerUnfreezeSprite(); data.RemoveAt(i--); _count--; } } } } } } return result; } private Vector2I ToGridPosition(Vector2 position) { var x = Mathf.FloorToInt(position.X / _step.X); var y = Mathf.FloorToInt(position.Y / _step.Y); return new Vector2I(x * _step.X, y * _step.Y); } }