using Thousandto.Core.Base; using System; using System.Collections.Generic; using System.Text; using UnityEngine; using PathEditor.Proxy.Plugin; namespace Thousandto.Plugins.PathGrid { public enum DyBlockType { None = 0, Circle, AABB, OBB, } public abstract class DynamicBlock { internal struct BlockInfo { public int cellIndex; public bool block; public BlockInfo(int _cellIndex, bool _block) { cellIndex = _cellIndex; block = _block; } } public abstract List GetConverCells(PathGirdData grid); protected DyBlockType m_type = DyBlockType.None; } public class Circle : DynamicBlock { Vector2 m_center; float m_radius; public Circle(Vector2 center, float radius) { m_center = center; m_radius = radius; m_type = DyBlockType.Circle; } public override List GetConverCells(PathGirdData grid) { var ret = new List(); var _center = m_center - MathLib.ToVector2_XOZ(ref grid.Position); var _startY = _center.y - m_radius; var _endY = _center.y + m_radius; var _startX = _center.x - m_radius; var _endX = _center.x + m_radius; var radSq = m_radius * m_radius; var cellSize = grid.CellSize; var halfCellSize = Vector2.one * cellSize * 0.5f; var startY = (int)(_startY * grid.RecipCellSize) - 1; var endY = (int)(_endY * grid.RecipCellSize) + 1; var startX = (int)(_startX * grid.RecipCellSize) - 1; var endX = (int)(_endX * grid.RecipCellSize) + 1; var curPos = Vector2.zero; for (var j = startY; j <= endY; ++j) { curPos.y = halfCellSize.y + j * cellSize; for (var i = startX; i <= endX; ++i) { curPos.x = halfCellSize.x + i * cellSize; var id = grid.GetCellID(i, j); if (id != -1) { // valid check if (MathLib.GetDistanceSq(ref curPos, ref _center) <= radSq) { ret.Add(id); } } } } return ret; } } public class AABB : DynamicBlock { Vector2 m_center; Vector2 m_halfSize; public AABB(Vector2 center, Vector2 size) { m_center = center; m_halfSize = size * 0.5f; m_type = DyBlockType.AABB; } public override List GetConverCells(PathGirdData grid) { var ret = new List(); var _center = m_center - MathLib.ToVector2_XOZ(ref grid.Position); var _startY = _center.y - m_halfSize.y; var _endY = _center.y + m_halfSize.y; var _startX = _center.x - m_halfSize.x; var _endX = _center.x + m_halfSize.x; var cellSize = grid.CellSize; var halfCellSize = Vector2.one * cellSize * 0.5f; var startY = (int)(_startY * grid.RecipCellSize) - 1; var endY = (int)(_endY * grid.RecipCellSize) + 1; var startX = (int)(_startX * grid.RecipCellSize) - 1; var endX = (int)(_endX * grid.RecipCellSize) + 1; var curPos = Vector2.zero; var diff = Vector2.zero; for (var j = startY; j <= endY; ++j) { curPos.y = halfCellSize.y + j * cellSize; for (var i = startX; i <= endX; ++i) { curPos.x = halfCellSize.x + i * cellSize; var id = grid.GetCellID(i, j); if (id != -1) { diff = curPos - _center; if (MathLib.FastAbs(diff.x) <= m_halfSize.x && MathLib.FastAbs(diff.y) <= m_halfSize.y) { ret.Add(id); } } } } return ret; } } public class OBB : DynamicBlock { Vector2 m_center; Vector2 m_direction; Vector2 m_halfSize; public OBB(Vector2 center, Vector2 size, Vector2 dir) { m_center = center; m_halfSize = size * 0.5f; m_type = DyBlockType.OBB; m_direction = dir; } public override List GetConverCells(PathGirdData grid) { var ret = new List(); var _center = m_center - MathLib.ToVector2_XOZ(ref grid.Position); var normal = new Vector2(m_direction.y, -m_direction.x); var h = m_direction * m_halfSize.x; var v = normal * m_halfSize.y; var a = _center + h + v; var b = _center + h - v; var c = _center - h + v; var d = _center - h - v; var maxx = Math.Max(Math.Max(a.x, b.x), Math.Max(c.x, d.x)); var maxy = Math.Max(Math.Max(a.y, b.y), Math.Max(c.y, d.y)); var minx = Math.Min(Math.Min(a.x, b.x), Math.Min(c.x, d.x)); var miny = Math.Min(Math.Min(a.y, b.y), Math.Min(c.y, d.y)); var cellSize = grid.CellSize; var halfCellSize = Vector2.one * cellSize * 0.5f; var startY = (int)(miny * grid.RecipCellSize) - 1; var endY = (int)(maxy * grid.RecipCellSize) + 1; var startX = (int)(minx * grid.RecipCellSize) - 1; var endX = (int)(maxx * grid.RecipCellSize) + 1; var curPos = Vector2.zero; var diff = Vector2.zero; var transPos = Vector2.zero; for (var j = startY; j <= endY; ++j) { curPos.y = halfCellSize.y + j * cellSize; for (var i = startX; i <= endX; ++i) { curPos.x = halfCellSize.x + i * cellSize; var id = grid.GetCellID(i, j); if (id != -1) { diff = curPos - _center; transPos.x = MathLib.VectorDot(ref diff, ref m_direction); transPos.y = MathLib.VectorDot(ref diff, ref normal); if (MathLib.FastAbs(transPos.x) <= m_halfSize.x && MathLib.FastAbs(transPos.y) <= m_halfSize.y) { ret.Add(id); } } } } return ret; } } public class PathBlocker { enum State { Inactive, Enabled, Disabled, } public struct CellInfo { public int column; public int row; public PathGridType ori_type; // save the original block info for reverting public CellInfo(int c, int r, PathGridType type) { column = c; row = r; ori_type = type; } } int m_instId = 0; PathGirdData m_grid = null; DynamicBlock m_blockShape = null; State m_state = State.Inactive; List m_fillInfo = null; public static PathBlocker CreateAABB(PathGirdData grid, ref Vector2 center, ref Vector2 size, int instId = 0) { return new PathBlocker(grid, new AABB(center, size), instId); } public static PathBlocker CreateCircle(PathGirdData grid, ref Vector2 center, float radius, int instId = 0) { return new PathBlocker(grid, new Circle(center, radius), instId); } public static PathBlocker CreateOBB(PathGirdData grid, ref Vector2 center, ref Vector2 size, ref Vector2 dir, int instId = 0) { var _dir = dir; _dir.Normalize(); return new PathBlocker(grid, new OBB(center, size, _dir), instId); } static int InstIDGen = 0; static int GenId() { return ++InstIDGen; } PathBlocker(PathGirdData grid, DynamicBlock shape, int instId = 0) { if (m_instId >= 0) { m_instId = GenId(); } m_grid = grid; m_blockShape = shape; var ids = m_blockShape.GetConverCells(grid); m_fillInfo = new List(ids.Count); if (instId > 0) { for (int i = 0; i < ids.Count; ++i) { int c, r; if (grid.GetCellCoord(ids[i], out c, out r)) { m_fillInfo.Add(new CellInfo(c, r, grid.GetCellType(c, r))); } } } else { for (int i = 0; i < ids.Count; ++i) { int c, r; if (grid.GetCellCoord(ids[i], out c, out r)) { m_fillInfo.Add(new CellInfo(c, r, PathGridType.None)); } } } } public int instId { get { return m_instId; } } public List GetFillCells() { var ids = m_blockShape.GetConverCells(m_grid); var fillInfo = new List(ids.Count); for (int i = 0; i < ids.Count; ++i) { int c, r; if (m_grid.GetCellCoord(ids[i], out c, out r)) { fillInfo.Add(new CellInfo(c, r, PathGridType.None)); } } return fillInfo; } public bool Enable() { if (m_state != State.Enabled) { m_state = State.Enabled; for (int i = 0; i < m_fillInfo.Count; ++i) { var info = m_fillInfo[i]; m_grid.SetBlock(info.column, info.row, PathGridType.UserBlock); } return true; } return false; } public bool Disable() { if (m_state == State.Enabled) { m_state = State.Disabled; for (int i = 0; i < m_fillInfo.Count; ++i) { var info = m_fillInfo[i]; m_grid.SetBlock(info.column, info.row, info.ori_type); } return true; } return false; } } }