riversong code showcase
This commit is contained in:
65
Source/Riversong/Game/Collections/NativeGrid.cs
Normal file
65
Source/Riversong/Game/Collections/NativeGrid.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class NativeGrid<T> : IDisposable where T : struct
|
||||
{
|
||||
private NativeArray<T> _data;
|
||||
|
||||
public NativeGrid(int2 size, Allocator allocator)
|
||||
{
|
||||
Size = size;
|
||||
_data = new NativeArray<T>(Size.x * Size.y, allocator);
|
||||
}
|
||||
|
||||
public int2 Size { get; }
|
||||
|
||||
protected int GetIndex(int2 point)
|
||||
{
|
||||
return math.mad(point.y, Size.x, point.x);
|
||||
}
|
||||
|
||||
public T GetValue(int index)
|
||||
{
|
||||
return _data[index];
|
||||
}
|
||||
|
||||
public T GetValue(int2 point)
|
||||
{
|
||||
return GetValue(GetIndex(point));
|
||||
}
|
||||
|
||||
public unsafe ref T GetValueRW(int index)
|
||||
{
|
||||
return ref UnsafeUtility.ArrayElementAsRef<T>(_data.GetUnsafePtr(), index);
|
||||
}
|
||||
|
||||
public ref T GetValueRW(int2 point)
|
||||
{
|
||||
return ref GetValueRW(GetIndex(point));
|
||||
}
|
||||
|
||||
public void SetValue(int index, T value)
|
||||
{
|
||||
_data[index] = value;
|
||||
}
|
||||
|
||||
public void SetValue(int2 point, T value)
|
||||
{
|
||||
SetValue(GetIndex(point), value);
|
||||
}
|
||||
|
||||
public NativeArray<T> GetNativeArray()
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_data.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
147
Source/Riversong/Game/Collections/SpatialLookup.cs
Normal file
147
Source/Riversong/Game/Collections/SpatialLookup.cs
Normal file
@@ -0,0 +1,147 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine.Pool;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class SpatialLookup<T>
|
||||
{
|
||||
private static readonly Predicate<T> NoopFilter = _ => true;
|
||||
|
||||
private int _cellSize;
|
||||
|
||||
private ListMultiDictionary<int2, Item> _lookup = new();
|
||||
|
||||
public SpatialLookup(int cellSize)
|
||||
{
|
||||
_cellSize = cellSize;
|
||||
}
|
||||
|
||||
public void Add(T obj, TileRect rect, int key)
|
||||
{
|
||||
foreach (var cell in CellRange(rect)) _lookup.Add(cell, new Item(obj, rect, key));
|
||||
}
|
||||
|
||||
public void Remove(TileRect rect, int key)
|
||||
{
|
||||
foreach (var cell in CellRange(rect)) _lookup.Remove(cell, new Item(key));
|
||||
}
|
||||
|
||||
private TileRange CellRange(TileRect rect)
|
||||
{
|
||||
return TileRange.From(rect.Min / _cellSize, rect.Max / _cellSize);
|
||||
}
|
||||
|
||||
public void RemoveAll(TileRect rect, Predicate<T> filter = null, List<T> result = null)
|
||||
{
|
||||
filter ??= NoopFilter;
|
||||
|
||||
using var closedScope = HashSetPool<int>.Get(out var closed);
|
||||
using var toRemoveScope = ListPool<(int2, Item)>.Get(out var toRemove);
|
||||
|
||||
var cellMin = rect.Min / _cellSize;
|
||||
var cellMax = rect.Max / _cellSize;
|
||||
|
||||
int2 cell;
|
||||
for (cell.x = cellMin.x; cell.x <= cellMax.x; cell.x++)
|
||||
for (cell.y = cellMin.y; cell.y <= cellMax.y; cell.y++)
|
||||
{
|
||||
if (!_lookup.TryGetValues(cell, out var list)) continue;
|
||||
|
||||
if (cell.x == cellMin.x || cell.x == cellMax.x || cell.y == cellMin.y || cell.y == cellMax.y)
|
||||
{
|
||||
foreach (var item in list)
|
||||
{
|
||||
if (!closed.Add(item.EqualityKey) || !rect.Intersects(item.Rect) || !filter.Invoke(item.Obj)) continue;
|
||||
toRemove.Add((cell, item));
|
||||
result?.Add(item.Obj);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result != null)
|
||||
foreach (var item in list)
|
||||
if (closed.Add(item.EqualityKey) || !filter.Invoke(item.Obj))
|
||||
result.Add(item.Obj);
|
||||
_lookup.Clear(cell);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var (key, value) in toRemove) _lookup.Remove(key, value);
|
||||
}
|
||||
|
||||
public void Find(TileRect rect, List<T> result)
|
||||
{
|
||||
using var closedScope = HashSetPool<int>.Get(out var closed);
|
||||
|
||||
var cellMin = rect.Min / _cellSize;
|
||||
var cellMax = rect.Max / _cellSize;
|
||||
|
||||
int2 cell;
|
||||
for (cell.x = cellMin.x; cell.x <= cellMax.x; cell.x++)
|
||||
for (cell.y = cellMin.y; cell.y <= cellMax.y; cell.y++)
|
||||
{
|
||||
if (!_lookup.TryGetValues(cell, out var list)) continue;
|
||||
|
||||
if (cell.x == cellMin.x || cell.x == cellMax.x || cell.y == cellMin.y || cell.y == cellMax.y)
|
||||
foreach (var item in list)
|
||||
{
|
||||
if (!rect.Intersects(item.Rect) || !closed.Add(item.EqualityKey)) continue;
|
||||
result.Add(item.Obj);
|
||||
}
|
||||
else
|
||||
foreach (var item in list)
|
||||
if (closed.Add(item.EqualityKey))
|
||||
result.Add(item.Obj);
|
||||
}
|
||||
}
|
||||
|
||||
public bool FindMax(TileRect rect, Func<T, int> scoreFunc, out T max)
|
||||
{
|
||||
using var resultScope = ListPool<T>.Get(out var result);
|
||||
|
||||
Find(rect, result);
|
||||
|
||||
max = default;
|
||||
var maxScore = int.MinValue;
|
||||
|
||||
foreach (var item in result)
|
||||
{
|
||||
var score = scoreFunc.Invoke(item);
|
||||
if (score > maxScore)
|
||||
{
|
||||
maxScore = score;
|
||||
max = item;
|
||||
}
|
||||
}
|
||||
|
||||
return maxScore > int.MinValue;
|
||||
}
|
||||
|
||||
private struct Item : IEquatable<Item>
|
||||
{
|
||||
public T Obj;
|
||||
|
||||
public TileRect Rect;
|
||||
|
||||
public int EqualityKey;
|
||||
|
||||
public Item(T obj, TileRect rect, int equalityKey)
|
||||
{
|
||||
Obj = obj;
|
||||
Rect = rect;
|
||||
EqualityKey = equalityKey;
|
||||
}
|
||||
|
||||
public Item(int equalityKey) : this(default, default, equalityKey)
|
||||
{
|
||||
}
|
||||
|
||||
public bool Equals(Item other)
|
||||
{
|
||||
return EqualityKey == other.EqualityKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user