ИИ для 2D игры - C#
Формулировка задачи:
Требовалось понять, не мешают ли стены (элементы world != 2) одному персонажу видеть другого. Решил делать через уравнение прямой y = k*x + b, в итоге видит через стены, за неделю так и не понял в чем проблема. plx,ply - координаты одного персонажа, x,y - другого.
private bool FOV(int plx, int ply)
{
if (x == plx)k = 0;
else k = (Convert.ToDouble(y - ply) / Convert.ToDouble(x - plx));
if (k > 0 ) b = System.Math.Min(ply, y);
else b = System.Math.Max(ply, y);
int i = System.Math.Min(plx, x);
do // Выполнить хоть раз
{
if (k > -1)
{
for (int j = Convert.ToInt32(k * (i) + b); j < Convert.ToInt32(k * (i+1) + b); j++)
{
if (world[i, b + j] != 2) return false;
}
}
else for (int j = Convert.ToInt32(k * (i) + b); j > Convert.ToInt32(k * (i + 1) + b); j--)
{
if (world[i, b + j] != 2) return false;
}
++i;
} while (i < System.Math.Max(plx, x)) ;
return true;Решение задачи: «ИИ для 2D игры»
textual
Листинг программы
class FloatComparer : IComparer<float>
{
private float Epsilon = 1e-6f;
public int Compare(float x, float y)
{
if (Math.Abs(x - y) < Epsilon)
return 0;
return x < y ? -1 : 1;
}
}
// Центром системы координат считается центр клетки мира (0; 0)
// Размер клеток - 1x1
class CellsEnumerator
{
// Возвращает клетки, пересекающиеся с отрезком [first; second]
public IEnumerable<Point> GetCellsBetween(PointF first, PointF second)
{
if (first.X > second.X)
{
var temp = first;
first = second;
second = temp;
}
float left = first.X;
float right = second.X;
// В случае попадания в одну вертикаль мира, разведём точки в стороны
if ((int)Math.Floor(left + 0.5) == (int)Math.Floor(right + 0.5))
{
left = (float)Math.Floor(left + 0.5) - 0.5f + 0.1f;
right = left + 0.8f;
}
float bottom = Math.Min(first.Y, second.Y);
float top = Math.Max(first.Y, second.Y);
// Строим уравнение прямой y = kx + b, содержащий отрезкок
float k = (second.Y - first.Y) / (right - left);
float b = first.Y - k * left;
var xLines = GetBorderLinesBetween(left, right).ToArray();
var yLines = GetBorderLinesBetween(bottom, top).ToArray();
var result = new List<Point>();
var nodes = new List<PointF>();
foreach (var x in xLines)
{
float y = x * k + b;
if (_comparer.Compare(y, (float)Math.Floor(y) + 0.5f) == 0)
{
nodes.Add(new PointF(x, y));
continue;
}
int cellX = (int)Math.Floor(x + 0.6);
int cellY = (int)Math.Floor(y + 0.5);
result.Add(new Point(cellX, cellY));
result.Add(new Point(cellX - 1, cellY));
}
foreach (var y in yLines)
{
float x = (y - b) / k;
if (_comparer.Compare(x, (float)Math.Floor(x) + 0.5f) == 0)
{
nodes.Add(new PointF(x, y));
continue;
}
int cellX = (int)Math.Floor(x + 0.5);
int cellY = (int)Math.Floor(y + 0.6);
result.Add(new Point(cellX, cellY));
result.Add(new Point(cellX, cellY - 1));
}
foreach (var node in nodes.Distinct())
{
var leftBottomX = (int)Math.Floor(node.X + 0.5 - 0.1);
var leftBottomY = (int)Math.Floor(node.Y + 0.5 - 0.1);
for (int dx = 0; dx < 2; dx++)
for (int dy = 0; dy < 2; dy++)
result.Add(new Point(leftBottomX + dx, leftBottomY + dy));
}
return result.Distinct();
}
private IEnumerable<float> GetBorderLinesBetween(float min, float max)
{
var x = (float)Math.Ceiling(min + 0.5) - 0.5f;
while (_comparer.Compare(x, max) < 0)
yield return x++;
}
private readonly FloatComparer _comparer = new FloatComparer();
};
class MainForm : Form
{
PointF first = PointF.Empty;
PointF second = PointF.Empty;
List<Point> cells = new List<Point>();
public MainForm()
{
var tb = new TextBox { Parent = this };
var enumerator = new CellsEnumerator();
tb.TextChanged += (_, __) =>
{
float[] numbers;
try
{
numbers = Regex.Split(tb.Text, @"\s")
.Select(word => float.Parse(word, CultureInfo.InvariantCulture))
.ToArray();
if (numbers.Length == 4)
{
first = new PointF(numbers[0], numbers[1]);
second = new PointF(numbers[2], numbers[3]);
cells = enumerator.GetCellsBetween(first, second).ToList();
Invalidate();
}
}
catch (FormatException) { }
};
tb.Text = "0 0 1 1";
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.TranslateTransform(10, 220);
e.Graphics.ScaleTransform(20, -20);
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
for (float x = -0.5f; x < 10.5f; x++)
e.Graphics.DrawLine(new Pen(Color.Green, 0.05f), x, -0.5f, x, 9.5f);
for (float y = -0.5f; y < 10.5f; y++)
e.Graphics.DrawLine(new Pen(Color.Green, 0.05f), -0.5f, y, 9.5f, y);
foreach (var cell in cells)
{
e.Graphics.DrawRectangle(new Pen(Color.Blue, 0.05f), cell.X - 0.5f, cell.Y - 0.5f, 1, 1);
}
e.Graphics.DrawLine(new Pen(Color.Red, 0.05f), first, second);
}
}
void Main()
{
new CellsEnumerator().GetCellsBetween(new PointF(0, 0), new PointF(0, 1)).Dump();
Application.Run(new MainForm());
}