176 lines
7.5 KiB
C#
176 lines
7.5 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Diagnostics;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
|
||
namespace AirBomber
|
||
{
|
||
internal abstract class AbstractMap
|
||
{
|
||
private IDrawningObject _drawningObject = null;
|
||
private Bitmap? _staticBitMap;
|
||
protected int[,] _map = null;
|
||
protected int _width;
|
||
protected int _height;
|
||
protected float _size_x;
|
||
protected float _size_y;
|
||
protected readonly Random _random = new();
|
||
protected readonly int _freeRoad = 0;
|
||
protected readonly int _barrier = 1;
|
||
|
||
public Bitmap CreateMap(int width, int height, IDrawningObject drawningObject)
|
||
{
|
||
_staticBitMap = null;
|
||
_width = width;
|
||
_height = height;
|
||
_drawningObject = drawningObject;
|
||
GenerateMap();
|
||
while (!SetObjectOnMap())
|
||
{
|
||
GenerateMap();
|
||
}
|
||
return DrawMapWithObject();
|
||
}
|
||
|
||
/// <summary>Проверяет наличие непроходимых участков в заданной области</summary>
|
||
/// <param name="area">Заданная область</param>
|
||
/// <param name="iBarrier">i-ый индекс первого барьера, который был найден в области</param>
|
||
/// <param name="jBarrier">j-ый индекс первого барьера, который был найден в области</param>
|
||
/// <returns>Есть ли барьеры</returns>
|
||
protected bool BarriersInArea(RectangleF area, ref int iBarrier, ref int jBarrier)
|
||
{
|
||
if (!(0 < area.Left && area.Right < _width && 0 < area.Top && area.Bottom < _height))
|
||
{
|
||
return true; // Если область попала за карту, считаем что она столкнулась с барьером
|
||
}
|
||
int rightArea = (int)Math.Ceiling(area.Right / _size_x);
|
||
int bottomArea = (int)Math.Ceiling(area.Bottom / _size_y);
|
||
for (int i = (int)(area.Left / _size_x); i < rightArea; i++)
|
||
{
|
||
for (int j = (int)(area.Top / _size_y); j < bottomArea; j++)
|
||
{
|
||
if (_map[i, j] == _barrier)
|
||
{
|
||
iBarrier = i;
|
||
jBarrier = j;
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
/// <summary>Проверяет наличие непроходимых участков в заданной области</summary>
|
||
/// <param name="area">Заданная область</param>
|
||
/// <returns>Есть ли барьеры</returns>
|
||
protected bool BarriersInArea(RectangleF area)
|
||
{
|
||
int a = 0, b = 0;
|
||
return BarriersInArea(area, ref a, ref b);
|
||
}
|
||
|
||
|
||
public Bitmap MoveObject(Direction direction)
|
||
{
|
||
var rect = _drawningObject.GetCurrentPosition();
|
||
var step = _drawningObject.Step;
|
||
// Вычисляем области смещения объекта
|
||
RectangleF? area = null;
|
||
if (direction == Direction.Left)
|
||
area = new(rect.Left - step, rect.Top, step, rect.Height);
|
||
else if (direction == Direction.Right)
|
||
area = new(rect.Right, rect.Top, step, rect.Height);
|
||
else if (direction == Direction.Up)
|
||
area = new(rect.Left, rect.Top - step, rect.Width, step);
|
||
else if (direction == Direction.Down)
|
||
area = new(rect.Left, rect.Bottom, rect.Width, step);
|
||
if (area.HasValue && !BarriersInArea(area.Value))
|
||
{
|
||
_drawningObject.MoveObject(direction);
|
||
}
|
||
return DrawMapWithObject();
|
||
}
|
||
private bool SetObjectOnMap()
|
||
{
|
||
if (_drawningObject == null || _map == null)
|
||
{
|
||
return false;
|
||
}
|
||
int x = _random.Next(0, 10);
|
||
int y = _random.Next(0, 10);
|
||
_drawningObject.SetObject(x, y, _width, _height);
|
||
|
||
// Если натыкаемся на барьер помещаем левый верхний угол чуть ниже этого барьера
|
||
// если при этом выходим за карту, пермещаем правый нижный угол чуть выше этого барьера
|
||
// если объект выходит за карту, генирируем новые координаты рандомно
|
||
int currI = 0, currJ = 0;
|
||
var areaObject = _drawningObject.GetCurrentPosition();
|
||
int cntOut = 10000; // Количество итераций до выхода из цикла
|
||
while (BarriersInArea(areaObject, ref currI, ref currJ) && --cntOut >= 0)
|
||
{
|
||
if ((currJ + 1) * _size_y + areaObject.Height <= _height)
|
||
{
|
||
areaObject.Location = new PointF((currI + 1) * _size_x, (currJ + 1) * _size_y);
|
||
}
|
||
else if ((currI - 1) * _size_x - areaObject.Width >= 0)
|
||
{
|
||
areaObject = new((currI - 1) * _size_x - areaObject.Width, (currJ - 1) * _size_y - areaObject.Height, areaObject.Width, areaObject.Height);
|
||
}
|
||
else
|
||
{
|
||
areaObject.Location = new PointF(_random.Next(0, _width - (int)areaObject.Width),
|
||
_random.Next(0, _height - (int)areaObject.Height));
|
||
}
|
||
}
|
||
_drawningObject.SetObject((int)areaObject.X, (int)areaObject.Y, _width, _height);
|
||
return cntOut >= 0;
|
||
}
|
||
/// <summary>
|
||
/// Заполняет BitMap для отрисовки статичных объектов. Выполняется один раз при создании карты
|
||
/// </summary>
|
||
private void DrawMap()
|
||
{
|
||
if (_staticBitMap != null) return;
|
||
_staticBitMap = new(_width, _height);
|
||
Graphics gr = Graphics.FromImage(_staticBitMap);
|
||
for (int i = 0; i < _map.GetLength(0); ++i)
|
||
{
|
||
for (int j = 0; j < _map.GetLength(1); ++j)
|
||
{
|
||
if (_map[i, j] == _freeRoad)
|
||
{
|
||
DrawRoadPart(gr, i, j);
|
||
}
|
||
else if (_map[i, j] == _barrier)
|
||
{
|
||
DrawBarrierPart(gr, i, j);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private Bitmap DrawMapWithObject()
|
||
{
|
||
Bitmap bmp = new(_width, _height);
|
||
if (_drawningObject == null || _map == null)
|
||
{
|
||
return bmp;
|
||
}
|
||
Graphics gr = Graphics.FromImage(bmp);
|
||
if (_staticBitMap == null)
|
||
DrawMap();
|
||
if (_staticBitMap != null)
|
||
gr.DrawImage(_staticBitMap, 0, 0);
|
||
_drawningObject.DrawObject(gr);
|
||
return bmp;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Генерация карты. При перегрузки определить поля _map, _size_x, _size_y
|
||
/// </summary>
|
||
protected abstract void GenerateMap();
|
||
protected abstract void DrawRoadPart(Graphics g, int i, int j);
|
||
protected abstract void DrawBarrierPart(Graphics g, int i, int j);
|
||
}
|
||
} |