public bool NoContactCertainty(IConvex2D shape) { float minA = 0; float maxA = 0; float minB = 0; float maxB = 0; // Only check up & right normals for an AABB since down & left are the same axes shape.Project(Vector2.up, ref minA, ref maxA); this.Project(Vector2.up, ref minB, ref maxB); // Check if the polygon projections are currentlty NOT intersecting if (Utility.IntervalDistance(minA, maxA, minB, maxB) > 0) { return(true); } shape.Project(Vector2.right, ref minA, ref maxA); this.Project(Vector2.right, ref minB, ref maxB); // Check if the polygon projections are currentlty NOT intersecting if (Utility.IntervalDistance(minA, maxA, minB, maxB) > 0) { return(true); } return(false); }
/// <summary> /// Adds a unit. /// </summary> public void Add(T unit, IConvex2D shape) { foreach (var cell in _getOrCreateSupercover(shape)) { cell.Add(new UnitWrapper(unit, shape)); } Count++; }
/// <summary> /// Enumerates all cells that are in the supercover of shape and creates a new cell if that cell was null /// </summary> protected IEnumerable <TCell> _getOrCreateSupercover(IConvex2D shape) { foreach (var location in shape.Supercover(this)) { if (_cells[location.x, location.y] == null) { _cells[location.x, location.y] = _createNewCell(location); } yield return(_cells[location.x, location.y]); } }
/// <summary> /// Adds a unit. /// </summary> public void Add(TKey key, T unit, IConvex2D shape) { UnitWrapper wrapper = new UnitWrapper(unit, shape); foreach (var cell in _getOrCreateSupercover(shape)) { cell.Add(key, wrapper); } wrappers.Add(key, wrapper); Count++; }
/// <summary> /// Enumarates all objects that overlap with shape /// </summary> public IEnumerable <T> Contact(IConvex2D shape) { // Increment our query number to prevent yielding a unit multiple times if it spans more than one cell _queryNumber++; foreach (Vector2Int cellIndex in shape.Supercover(this)) { if (_cells[cellIndex.x, cellIndex.y] != null) { foreach (var wrapper in _cells[cellIndex.x, cellIndex.y].Contact(shape, (u) => true, _queryNumber)) { yield return(wrapper.Unit); } } } }
/// <summary> /// Returns the first object found that contacts shape for which a predicate evaluates to true. It might speak an alien language to us humans. /// </summary> public T FirstContactWhich(IConvex2D shape, Predicate <T> predicate) { _queryNumber++; foreach (Vector2Int cellIndex in shape.Supercover(this)) { if (_cells[cellIndex.x, cellIndex.y] != null) { foreach (var wrapper in _cells[cellIndex.x, cellIndex.y].Contact(shape, predicate, _queryNumber)) { return(wrapper.Unit); } } } return(default(T)); }
/// <summary> /// Updates a unit's position / shape /// </summary> public void Update(TKey key, IConvex2D newShape) { UnitWrapper wrapper = wrappers[key]; foreach (var cell in _getOrCreateSupercover(wrapper.Shape)) { cell.Remove(key); } var newWrapper = new UnitWrapper(wrapper.Unit, newShape); foreach (var cell in _getOrCreateSupercover(newShape)) { cell.Add(key, newWrapper); } wrappers[key] = newWrapper; }
/// <summary> /// Returns all units in this cell that contact shape /// </summary> public IEnumerable <UnitWrapper> Contact(IConvex2D shape, Predicate <T> predicate, int queryNumber) { foreach (var wrapper in _unitWrappers) { // Make sure to check each unit only once. Certain shapes might span multiple cells. if (!wrapper.Once(queryNumber)) { continue; } if (!shape.NoContactCertainty(wrapper.Shape) && !wrapper.Shape.NoContactCertainty(shape) && predicate(wrapper.Unit)) { yield return(wrapper); } } }
public bool NoContactCertainty(IConvex2D shape) { float minA = 0; float maxA = 0; float minB = 0; float maxB = 0; Vector2 normal = new Vector2(-(w.y - v.y), w.x - v.x).normalized; shape.Project(normal, ref minA, ref maxA); this.Project(normal, ref minB, ref maxB); // Check if the polygon projections are currentlty NOT intersecting if (Utility.IntervalDistance(minA, maxA, minB, maxB) > 0) { return(true); } return(false); }
/// <summary> /// Returns the first object found that contacts shape. It might speak an alien language to us humans. /// </summary> public T FirstContact(IConvex2D shape) { _queryNumber++; int cellsSearched = 0; foreach (Vector2Int cellIndex in shape.Supercover(this)) { cellsSearched++; if (_cells[cellIndex.x, cellIndex.y] != null) { foreach (var wrapper in _cells[cellIndex.x, cellIndex.y].Contact(shape, (u) => true, _queryNumber)) { return(wrapper.Unit); } } } AverageCellsSearched = Mathf.Lerp(AverageCellsSearched, cellsSearched, 0.5f); return(default(T)); }
/// <summary> /// Enumarates all objects that overlap with a convex shape and for which a predicate evaluates to true /// </summary> public IEnumerable <T> ContactWhich(IConvex2D shape, Predicate <T> predicate) { // Increment our query number to prevent yielding a unit multiple times if it spans more than one cell _queryNumber++; int cellsSearched = 0; int unitsAcc = 0; foreach (Vector2Int cellIndex in shape.Supercover(this)) { cellsSearched++; if (_cells[cellIndex.x, cellIndex.y] != null) { unitsAcc += _cells[cellIndex.x, cellIndex.y].Count; foreach (var wrapper in _cells[cellIndex.x, cellIndex.y].Contact(shape, predicate, _queryNumber)) { yield return(wrapper.Unit); } } } AverageCellsSearched = Mathf.Lerp(AverageCellsSearched, cellsSearched, 0.5f); AverageUnitsPerCell = (float)unitsAcc / cellsSearched; }
public bool NoContactCertainty(IConvex2D shape) { return(this.shape.NoContactCertainty(shape)); }
public bool NoContactCertainty(IConvex2D shape) { return(shape.DistanceSquared(new Vector2(x, y)) > 0); }
public void UpdateShape(int key, IConvex2D shape) { _grid.Update(key, shape); }
private int _lastQueryNumber; // Keeps track of the last query number that has been made to prevent duplicate results public UnitWrapper(T unit, IConvex2D shape) { Shape = shape; Unit = unit; }
public CachedShape(IGridDimensions2D grid, IConvex2D shape) { this.shape = shape; this.supercover = shape.Supercover(grid).ToArray(); }
/// <summary> /// No SAT here /// A shape doesn't touch a circle when it's closest distance to the circle's center is greater than the circle's radius /// </summary> public bool NoContactCertainty(IConvex2D shape) { return(shape.DistanceSquared(center) > radius * radius); }