//#define DisplayRegions
#define DisplayFinalRegions
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
namespace CarFire
{
///
/// AI infomation to be used by monsters. The map is split into deferent regions,
/// each region is then linked to other regions that it can see.
///
public class AI
{
Game game;
int[,] regions;
List regionList;
int regionCnt;
public AI(Game _game)
{
game = _game;
regions = new int[game.State.Map.Width, game.State.Map.Height];
regionList = new List();
regionCnt = 0;
//set all square to -1 to show they have not been assigned to a region yet.
for (int y = 0; y < regions.GetLength(1); y++)
{
for (int x = 0; x < regions.GetLength(0); x++)
{
regions[x, y] = -1;
}
}
regionList.Add(new Region(0)); //region 0 will represent all walls and things like it.
#if DisplayRegions
printRegions();
#endif
setUpRegions();
foreach (Region r in regionList)
r.CalcCenter();
#if (DisplayRegions || DisplayFinalRegions)
printRegions();
#endif
linkRegions();
}
///
/// check to see if a spot on the map is visible from another spot
///
/// Current X position
/// Current Y position
/// X location to test
/// Y location to test
public bool spaceVisible(int curX, int curY, int testX, int testY)
{
return regionList[regions[curX, curY]].VisibleRegions.Contains(regions[testX, testY]);
}
//find regions in map. these regions will be large groups of connected grid squares.
public int setUpRegions()
{
//find open space that has not been assigned yet
for (int y = 0; y < regions.GetLength(1); y++)
{
for (int x = 0; x < regions.GetLength(0); x++)
{
if (regions[x, y] == -1 && spaceOpen(x, y))
{
regionCnt++;
regionList.Add(new Region(regionCnt));
createRegion(x, y);
}
else if (regions[x, y] == -1) //grid square is a wall
{
regions[x, y] = 0;
}
else //grid already assigned to region, do nothing
{
}
}
}
return regionList.Count;
}
#region Private Methods
private void createRegion(int x, int y)
{
regionList[regionCnt].Left = x;
regionList[regionCnt].Top = y;
for (int rY = 0; rY < 5 && y + rY < regions.GetLength(1); rY++) // creates a region as large as possible up to 5x5
{
for (int rX = 0; rX < 5 && x + rX < regions.GetLength(0); rX++)
{
if (regions[x + rX, y + rY] == -1 && spaceOpen(x + rX, y + rY))
{
regions[x + rX, y + rY] = regionCnt;
}
else if (regions[x + rX, y + rY] == -1) //grid square is a wall
{
regions[x + rX, y + rY] = 0;
regionList[regionCnt].Right = x + rX;
regionList[regionCnt].Bottom = y + rY;
#if DisplayRegions
printRegions();
#endif
if (!spaceOpen(x + rX + 1, y + rY)) // hit horizontal wall end region
if(x + rX >= regions.GetLength(0)-1)
break;
else
return;
else
break;
//todo: figure out how to get region to stop being created when
}
else //grid already assigned to region, do nothing
{
}
regionList[regionCnt].Right = x + rX;
}
regionList[regionCnt].Bottom = y + rY;
}
#if DisplayRegions
printRegions();
#endif
return;
}
private bool spaceOpen(int x, int y)
{
if (x >= regions.GetLength(0)) return false;
if (y >= regions.GetLength(1)) return false;
return !game.State.Map.IsWall(x, y);
}
//TODO: scans out from each corner, some areas are still missed
private void linkRegions()
{
foreach (Region r in regionList)
{
if (r.Label == 0)
continue;
//scan from center
//scan from corners
//top Left
int x = r.Left;
int y = r.Top;
//scan up
for (int t = 1; spaceOpen(x, y - t); t++)
{
if ( regions[x, y] != regions[x, y - t] )
{
regionList[regions[x, y]].AddVisible(regions[x, y - t]);
}
}
//scan left
for (int t = 1; spaceOpen(x - t, y); t++)
{
if ( regions[x, y] != regions[x - t, y] )
{
regionList[regions[x, y]].AddVisible(regions[x - t, y]);
}
}
//scan diag
for (int t = 1; spaceOpen(x - t, y - t); t++)
{
if (regions[x, y] != regions[x - t, y - t])
{
regionList[regions[x, y]].AddVisible(regions[x - t, y - t]);
}
}
//top Right
x = r.Right;
y = r.Top;
//scan up
for (int t = 1; spaceOpen(x, y - t); t++)
{
if (regions[x, y] != regions[x, y - t])
{
regionList[regions[x, y]].AddVisible(regions[x, y - t]);
}
}
//scan Right
for (int t = 1; spaceOpen(x + t, y); t++)
{
if (regions[x, y] != regions[x + t, y])
{
regionList[regions[x, y]].AddVisible(regions[x + t, y]);
}
}
//scan diag
for (int t = 1; spaceOpen(x + t, y - t); t++)
{
if (regions[x, y] != regions[x + t, y - t])
{
regionList[regions[x, y]].AddVisible(regions[x + t, y - t]);
}
}
//bottom Right
x = r.Right;
y = r.Bottom;
//scan down
for (int t = 1; spaceOpen(x, y + t); t++)
{
if (regions[x, y] != regions[x, y + t])
{
regionList[regions[x, y]].AddVisible(regions[x, y + t]);
}
}
//scan Right
for (int t = 1; spaceOpen(x + t, y); t++)
{
if (regions[x, y] != regions[x + t, y])
{
regionList[regions[x, y]].AddVisible(regions[x + t, y]);
}
}
//scan diag
for (int t = 1; spaceOpen(x + t, y + t); t++)
{
if (regions[x, y] != regions[x + t, y + t])
{
regionList[regions[x, y]].AddVisible(regions[x + t, y + t]);
}
}
//bottom left
x = r.Left;
y = r.Bottom;
//scan down
for (int t = 1; spaceOpen(x, y + t); t++)
{
if (regions[x, y] != regions[x, y + t])
{
regionList[regions[x, y]].AddVisible(regions[x, y + t]);
}
}
//scan Left
for (int t = 1; spaceOpen(x - t, y); t++)
{
if (regions[x, y] != regions[x - t, y])
{
regionList[regions[x, y]].AddVisible(regions[x - t, y]);
}
}
//scan diag
for (int t = 1; spaceOpen(x - t, y + t); t++)
{
if (regions[x, y] != regions[x - t, y + t])
{
regionList[regions[x, y]].AddVisible(regions[x - t, y + t]);
}
}
}
}
#endregion
//for testing print the region grid to the console
public void printRegions()
{
Console.WriteLine("--Printing Regions--");
for (int y = 0; y < regions.GetLength(1); y++)
{
for (int x = 0; x < regions.GetLength(0); x++)
{
Console.Write(regions[x, y]);
}
Console.WriteLine("");
}
}
}
///
/// a chuck of the map that is at most 5x5 used to determine line of sight
///
public class Region
{
List visibleRegions; //other regions that are in this regions sight
int label;
int centerX;
int centerY;
//edges
int left, right, top, bottom;
public Region(int _label)
{
label = _label;
visibleRegions = new List();
}
public void AddVisible(int region)
{
if(!visibleRegions.Contains(region))
visibleRegions.Add(region);
}
public void CalcCenter()
{
if (right != left) centerX = right + (right - left) / 2;
else centerX = right;
if (top != bottom) centerY = top + (bottom - top) / 2;
else centerY = top;
}
public int Left
{
get { return left; }
set { left = value; }
}
public int Right
{
get { return right; }
set { right = value; }
}
public int Top
{
get { return top; }
set { top = value; }
}
public int Bottom
{
get { return bottom; }
set { bottom = value; }
}
public Point Center { get { return new Point(centerX, centerY); } }
public int Label { get { return label; } }
public List VisibleRegions { get { return visibleRegions; } }
}
}