public override void Calculate(FOWFieldData field, FOWMap map) { Vector3 worldPosition = field.position; int rx = (int)(field.radius / map.deltaX); int rz = (int)(field.radius / map.deltaZ); float rs = rx * rx; int x = Mathf.FloorToInt((worldPosition.x - map.beginPosition.x) / map.deltaX); int z = Mathf.FloorToInt((worldPosition.z - map.beginPosition.z) / map.deltaZ); int beginx = Mathf.Max(0, x - rx); int beginy = Mathf.Max(0, z - rz); int endx = Mathf.Min(map.texWidth, x + rx); int endy = Mathf.Min(map.texHeight, z + rz); for (int i = beginx; i < endx; i++) { for (int j = beginy; j < endy; j++) { int dx = i - x; int dy = j - z; float rads = dx * dx + dy * dy; if (rads <= rs) { map.maskTexture.SetAsVisible(i, j); } } } }
private bool IsPositionInvisible(FOWMap map, int x, int y) { float angle = Mathf.Atan2((y * map.deltaZ), (x * map.deltaX)) * Mathf.Rad2Deg; //if (angle < 0) angle += 360; bool isEnd = (m_SortAngle[0] - m_SortAngle[3]) >= 180; float minAngle = isEnd ? m_SortAngle[1] : m_SortAngle[3]; float maxAngle = isEnd ? m_SortAngle[2] : m_SortAngle[0]; if (isEnd) { if (angle >= minAngle && angle <= 180) { return(true); } if (angle <= maxAngle && angle >= -180) { return(true); } return(false); } if (angle >= minAngle && angle <= maxAngle) { return(true); } return(false); }
private void RaycastLine(FOWMap map, FOWMapPos pos, int centX, int centZ, float px, float pz, FOWFieldData field) { Vector2 dir = new Vector2(px, pz) * 10; int x = centX + (int)dir.x; int y = centZ + (int)dir.y; SetInvisibleLine(map, pos.x, pos.y, x, y, centX, centZ, field.radiusSquare); }
protected override void RayCast(FOWMap map, FOWMapPos pos, int centX, int centZ, FOWFieldData field) { float radiusSq = field.radiusSquare; int x = pos.x - centX; int z = pos.y - centZ; m_SortAngle[0] = Mathf.Atan2((z * map.deltaZ + map.deltaZ / 2), (x * map.deltaX - map.deltaX / 2)) * Mathf.Rad2Deg; m_SortAngle[1] = Mathf.Atan2((z * map.deltaZ - map.deltaZ / 2), (x * map.deltaX - map.deltaX / 2)) * Mathf.Rad2Deg; m_SortAngle[2] = Mathf.Atan2((z * map.deltaZ + map.deltaZ / 2), (x * map.deltaX + map.deltaX / 2)) * Mathf.Rad2Deg; m_SortAngle[3] = Mathf.Atan2((z * map.deltaZ - map.deltaZ / 2), (x * map.deltaX + map.deltaX / 2)) * Mathf.Rad2Deg; float curAngle = Mathf.Atan2((z * map.deltaZ), (x * map.deltaX)) * Mathf.Rad2Deg; SortAngle(); m_RayCastQueue.Clear(); m_RayCastQueue.Enqueue(pos); int index = pos.y * map.texWidth + pos.x; m_Arrives.Add(index); while (m_RayCastQueue.Count > 0) { FOWMapPos root = m_RayCastQueue.Dequeue(); if (root.x - 1 >= 0 && (curAngle >= 90 || curAngle < -90)) { SetInvisibleAtPosition(map, root.x - 1, root.y, centX, centZ, radiusSq); } if (root.x - 1 >= 0 && root.y - 1 >= 0 && curAngle <= -90 && curAngle >= -180) { SetInvisibleAtPosition(map, root.x - 1, root.y - 1, centX, centZ, radiusSq); } if (root.y - 1 >= 0 && curAngle <= 0 && curAngle >= -180) { SetInvisibleAtPosition(map, root.x, root.y - 1, centX, centZ, radiusSq); } if (root.x + 1 < map.texWidth && root.y - 1 >= 0 && curAngle <= 0 && curAngle >= -90) { SetInvisibleAtPosition(map, root.x + 1, root.y - 1, centX, centZ, radiusSq); } if (root.x + 1 < map.texWidth && curAngle >= -90 && curAngle <= 90) { SetInvisibleAtPosition(map, root.x + 1, root.y, centX, centZ, radiusSq); } if (root.x + 1 < map.texWidth && root.y + 1 < map.texHeight && curAngle >= 0 && curAngle <= 90) { SetInvisibleAtPosition(map, root.x + 1, root.y + 1, centX, centZ, radiusSq); } if (root.y + 1 < map.texHeight && curAngle >= 0 && curAngle <= 180) { SetInvisibleAtPosition(map, root.x, root.y + 1, centX, centZ, radiusSq); } if (root.x - 1 >= 0 && root.y + 1 < map.texHeight && curAngle >= 90 && curAngle <= 180) { SetInvisibleAtPosition(map, root.x - 1, root.y + 1, centX, centZ, radiusSq); } } }
private void SetInvisibleAtPosition(FOWMap map, int x, int z) { int index = z * map.texWidth + x; if (m_Arrives.Contains(index) == false) { m_Arrives.Add(index); } }
private bool IsInRange(FOWMap map, int x, int z, int centX, int centZ, float radiusSq) { float r = (x - centX) * (x - centX) * map.deltaX * map.deltaX + (z - centZ) * (z - centZ) * map.deltaZ * map.deltaZ; if (r > radiusSq) { return(false); } return(true); }
protected override void RayCast(FOWMap map, FOWMapPos pos, int centX, int centZ, FOWFieldData field) { int x = pos.x - centX; int z = pos.y - centZ; float corner1x, corner1z, corner2x, corner2z; GetCornersPos(x, z, out corner1x, out corner1z, out corner2x, out corner2z); RaycastLine(map, pos, centX, centZ, corner1x, corner1z, field); RaycastLine(map, pos, centX, centZ, corner2x, corner2z, field); }
public void Calculate(FOWFieldData field, FOWMap map) { if (map.mapData.isPregeneration) { UsePregenerationDataCalculate(field, map); } else { RealtimeCalculate(field, map); } }
private bool IsVisible(FOWMap map, int x, int y) { if (x < 0 || x >= map.texWidth) { return(false); } if (y < 0 || y >= map.texHeight) { return(false); } return(map.mapData[x, y] == 0); }
public sealed override void Calculate(FOWFieldData field, FOWMap map) { Vector3 worldPosition = field.position; float radiusSq = field.radiusSquare; int x = Mathf.FloorToInt((worldPosition.x - map.beginPosition.x) / map.deltaX); int z = Mathf.FloorToInt((worldPosition.z - map.beginPosition.z) / map.deltaZ); if (x < 0 || x >= map.texWidth) { return; } if (z < 0 || z >= map.texHeight) { return; } if (map.mapData[x, z] != 0) { return; } m_Queue.Clear(); m_Arrives.Clear(); m_Queue.Enqueue(new FOWMapPos(x, z)); m_Arrives.Add(z * map.texWidth + x); map.maskTexture.SetAsVisible(x, z); while (m_Queue.Count > 0) { var root = m_Queue.Dequeue(); if (map.mapData[root.x, root.y] != 0) { if (PreRayCast(map, root, x, z)) { int index = root.y * map.texWidth + root.x; if (!m_Arrives.Contains(index)) { m_Arrives.Add(index); } map.maskTexture.SetAsVisible(root.x, root.y); } else { RayCast(map, root, x, z, field); } continue; } SetVisibleAtPosition(map, root.x - 1, root.y, x, z, radiusSq); SetVisibleAtPosition(map, root.x, root.y - 1, x, z, radiusSq); SetVisibleAtPosition(map, root.x + 1, root.y, x, z, radiusSq); SetVisibleAtPosition(map, root.x, root.y + 1, x, z, radiusSq); } }
protected override void RayCast(FOWMap map, FOWMapPos pos, int centX, int centZ, FOWFieldData field) { float r = field.radius * map.invDeltaX; Vector2 dir = new Vector2(pos.x - centX, pos.y - centZ); float l = dir.magnitude; if (r - l <= 0) { return; } dir = dir.normalized * (r - l); int x = pos.x + (int)dir.x; int y = pos.y + (int)dir.y; SetInvisibleLine(map, pos.x, pos.y, x, y, centX, centZ, field.radiusSquare); }
private void SetInvisibleAtPosition(FOWMap map, int x, int z, int centX, int centZ, float radiusSq) { int index = z * map.texWidth + x; float r = (x - centX) * (x - centX) * map.deltaX * map.deltaX + (z - centZ) * (z - centZ) * map.deltaZ * map.deltaZ; if (r > radiusSq) { return; } if (m_Arrives.Contains(index) == false) { if (IsPositionInvisible(map, x - centX, z - centZ)) { m_RayCastQueue.Enqueue(new FOWMapPos(x, z)); m_Arrives.Add(index); } } }
private void SetVisibleAtPosition(FOWMap map, int x, int z, int centX, int centZ, float radiusSq) { if (x < 0 || z < 0 || x >= map.texWidth || z >= map.texHeight) { return; } if (!IsInRange(map, x, z, centX, centZ, radiusSq)) { return; } int index = z * map.texWidth + x; if (m_Arrives.Contains(index)) { return; } m_Arrives.Add(index); m_Queue.Enqueue(new FOWMapPos(x, z)); map.maskTexture.SetAsVisible(x, z); }
private bool PreRayCast(FOWMap map, FOWMapPos pos, int centX, int centZ) { float k = ((float)(pos.y - centZ)) / (pos.x - centX); if (k < -0.414f && k >= -2.414f) { return(!IsVisible(map, pos.x + 1, pos.y + 1) && !IsVisible(map, pos.x - 1, pos.y - 1)); } else if (k < -2.414f || k >= 2.414f) { return(!IsVisible(map, pos.x + 1, pos.y) && !IsVisible(map, pos.x - 1, pos.y)); } else if (k < 2.414f && k >= 0.414f) { return(!IsVisible(map, pos.x + 1, pos.y - 1) && !IsVisible(map, pos.x - 1, pos.y + 1)); } else { return(!IsVisible(map, pos.x, pos.y + 1) && !IsVisible(map, pos.x, pos.y - 1)); } }
private void SetVisibleAtPosition(FOWMap map, int x, int z, int centX, int centZ, float radiusSq) { if (x < 0 || z < 0 || x >= map.texWidth || z >= map.texHeight) { return; } float r = (x - centX) * (x - centX) * map.deltaX * map.deltaX + (z - centZ) * (z - centZ) * map.deltaZ * map.deltaZ; if (r > radiusSq) { return; } int index = z * map.texWidth + x; if (m_Arrives.Contains(index)) { return; } m_Arrives.Add(index); m_Queue.Enqueue(new FOWMapPos(x, z)); map.maskTexture.SetAsVisible(x, z); }
/// <summary> /// 实时计算 /// </summary> /// <param name="field"></param> /// <param name="map"></param> protected abstract void RealtimeCalculate(FOWFieldData field, FOWMap map);
protected abstract void RayCast(FOWMap map, FOWMapPos pos, int centX, int centZ, FOWFieldData field);
protected void SetInvisibleLine(FOWMap map, int beginx, int beginy, int endx, int endy, int centX, int centZ, float rsq) { int dx = Mathf.Abs(endx - beginx); int dy = Mathf.Abs(endy - beginy); //int x, y; int step = ((endy < beginy && endx >= beginx) || (endy >= beginy && endx < beginx)) ? -1 : 1; int p, twod, twodm; int pv1, pv2, to; int x, y; if (dy < dx) { p = 2 * dy - dx; twod = 2 * dy; twodm = 2 * (dy - dx); if (beginx > endx) { pv1 = endx; pv2 = endy; endx = beginx; } else { pv1 = beginx; pv2 = beginy; } to = endx; } else { p = 2 * dx - dy; twod = 2 * dx; twodm = 2 * (dx - dy); if (beginy > endy) { pv2 = endx; pv1 = endy; endy = beginy; } else { pv2 = beginx; pv1 = beginy; } to = endy; } if (dy < dx) { x = pv1; y = pv2; } else { x = pv2; y = pv1; } SetInvisibleAtPosition(map, x, y); while (pv1 < to) { pv1++; if (p < 0) { p += twod; } else { pv2 += step; p += twodm; } if (dy < dx) { x = pv1; y = pv2; } else { x = pv2; y = pv1; } if (!IsInRange(map, x, y, centX, centZ, rsq)) { return; } SetInvisibleAtPosition(map, x, y); } }
/// <summary> /// TODO:使用预生成FOV数据计算(暂未实现) /// </summary> /// <param name="field"></param> /// <param name="map"></param> private void UsePregenerationDataCalculate(FOWFieldData field, FOWMap map) { }
public abstract void Calculate(FOWFieldData field, FOWMap map);
private void SetInvisibleLine(FOWMap map, int beginx, int beginy, int endx, int endy) { int dx = Mathf.Abs(endx - beginx); int dy = Mathf.Abs(endy - beginy); //int x, y; int step = ((endy < beginy && endx >= beginx) || (endy >= beginy && endx < beginx)) ? -1 : 1; int p, twod, twodm; int pv1, pv2, to; if (dy < dx) { p = 2 * dy - dx; twod = 2 * dy; twodm = 2 * (dy - dx); if (beginx > endx) { pv1 = endx; pv2 = endy; endx = beginx; } else { pv1 = beginx; pv2 = beginy; } to = endx; } else { p = 2 * dx - dy; twod = 2 * dx; twodm = 2 * (dx - dy); if (beginy > endy) { pv2 = endx; pv1 = endy; endy = beginy; } else { pv2 = beginx; pv1 = beginy; } to = endy; } if (dy < dx) { SetInvisibleAtPosition(map, pv1, pv2); } else { SetInvisibleAtPosition(map, pv2, pv1); } while (pv1 < to) { pv1++; if (p < 0) { p += twod; } else { pv2 += step; p += twodm; } if (dy < dx) { SetInvisibleAtPosition(map, pv1, pv2); } else { SetInvisibleAtPosition(map, pv2, pv1); } } }