ISEbd-21_Agliullov.D.A._Air.../AirBomber/AirBomber/AbstractMap.cs
2022-10-13 15:15:13 +04:00

176 lines
7.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
}
}