Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / Grid.cs

using System;
using System.Collections.Generic;
using Godot;

/// <summary>
/// 网格数据结构, 通过 x 和 y 存储数据
/// </summary>
public class Grid<T>
{
    /// <summary>
    /// 遍历网格数据回调
    /// </summary>
    public delegate void EachGridCallback(int x, int y, T data);
    
    private readonly Dictionary<int, Dictionary<int, T>> _map = new Dictionary<int, Dictionary<int, T>>();

    /// <summary>
    /// 返回指定xy位置是否存在数据
    /// </summary>
    public bool Contains(int x, int y)
    {
        if (_map.TryGetValue(x, out var value))
        {
            return value.ContainsKey(y);
        }

        return false;
    }

    /// <summary>
    /// 设置指定xy位置的数据
    /// </summary>
    public void Set(int x, int y, T data)
    {
        if (_map.TryGetValue(x, out var value))
        {
            value[y] = data;
        }
        else
        {
            value = new Dictionary<int, T>();
            value.Add(y, data);
            _map.Add(x, value);
        }
    }

    /// <summary>
    /// 获取指定xy位置的数据
    /// </summary>
    public T Get(int x, int y)
    {
        if (_map.TryGetValue(x, out var value))
        {
            return value[y];
        }

        return default;
    }
    
    /// <summary>
    /// 往一个区域中填充指定的数据
    /// </summary>
    /// <param name="pos">起点位置</param>
    /// <param name="size">区域大小</param>
    /// <param name="data">数据</param>
    public void AddRect(Vector2 pos, Vector2 size, T data)
    {
        var x = (int)pos.X;
        var y = (int)pos.Y;
        for (var i = 0; i < size.X; i++)
        {
            for (var j = 0; j < size.Y; j++)
            {
                if (_map.TryGetValue(x + i, out var value))
                {
                    value[y + j] = data;
                }
                else
                {
                    value = new Dictionary<int, T>();
                    value.Add(y + j, data);
                    _map.Add(x + i, value);
                }
            }
        }
    }

    /// <summary>
    /// 移除指定区域数据
    /// </summary>
    /// <param name="pos">起点位置</param>
    /// <param name="size">区域大小</param>
    public void RemoveRect(Vector2 pos, Vector2 size)
    {
        var x = (int)pos.X;
        var y = (int)pos.Y;
        for (var i = 0; i < size.X; i++)
        {
            for (var j = 0; j < size.Y; j++)
            {
                if (_map.TryGetValue(x + i, out var value))
                {
                    value.Remove(y + j);
                    if (value.Count == 0)
                    {
                        _map.Remove(x + i);
                    }
                }
            }
        }
    }

    /// <summary>
    /// 清除所有数据
    /// </summary>
    public void Clear()
    {
        _map.Clear();
    }
    
    /// <summary>
    /// 检测矩形区域内是否与其他数据有碰撞
    /// </summary>
    /// <param name="pos">起点位置</param>
    /// <param name="size">区域大小</param>
    public bool RectCollision(Vector2 pos, Vector2 size)
    {
        var x = (int)pos.X;
        var y = (int)pos.Y;
        var w = (int)size.X;
        var h = (int)size.Y;
        //先判断四个角
        if (Contains(x, y) || Contains(x + w - 1, y) || Contains(x, y + h - 1) || Contains(x + w - 1, y + h - 1))
        {
            return true;
        }

        //逐个点判断
        for (int i = 1; i < w; i++)
        {
            for (int j = 0; j < h; j++)
            {
                if (Contains(x + i, y + j))
                {
                    return true;
                }
            }
        }

        return false;
    }

    /// <summary>
    /// 遍历网格数据
    /// </summary>
    public void ForEach(EachGridCallback cb)
    {
        foreach (var pair1 in _map)
        {
            foreach (var pair2 in pair1.Value)
            {
                cb(pair1.Key, pair2.Key, pair2.Value);
            }
        }
    }
}