/// Определяет факт пересечения прямоугольников двух спрайтов.
/// </summary>
/// <param name="First">
/// Индекс (слой) первого спрайта.
/// </param>
/// <param name="Second">
/// Индекс (слой) второго спрайта.
/// </param>
/// <returns>
/// true, если спрайты пересекаются, и false в противном случае.
/// </returns>
bool Intersect(int First, int Second)
{
return sprites[First].SpriteRect.IntersectsWith
(sprites[Second].SpriteRect);
}
/// <summary>
/// Создает конкретное изображение спрайта.
/// </summary>
/// <remarks>
/// Метод PaintPicture является абстрактным в этом классе и должен быть
/// перекрыт наследниками, формирующими изображение с помощью этого метода.
/// </remarks>
protected abstract void PaintPicture();
/// <summary>
/// Убирает спрайт с экрана.
/// </summary>
protected internal virtual void Restore()
{
sprites.Canvas.DrawImage(image, location);
}
/// <summary>
/// Помещает спрайт на экран.
/// </summary>
protected internal virtual void Paint()
{
bmpCanvas.CopyFromScreen(sprites.Parent.RectangleToScreen
(SpriteRect).Location, new Point(), image.Size);
PaintPicture();
}
/// <summary>
/// Смещает положение спрайта на плоскости XY.
/// </summary>
/// <param name="drift">
/// Вектор смещения.
/// </param>
/// <returns>
/// true, если смещение произошло, и false, если нет.
/// </returns>
public virtual bool Move(Size drift)
{
Point newPos = location + drift;
bool result = true;
if (onBeforeMove != null)
result = onBeforeMove(this, ref newPos);
if (result = result &&
sprites.ClientRect.Contains(new Rectangle(newPos, spriteSize)))
Set<Point>(ref location, newPos);
return result;
}
/// <summary>
/// Перемещает сайт в новое положение на плоскости XY.
/// </summary>
/// <param name="newLocation">
/// Новое положение левого верхнего угла спрайта.
/// </param>
/// <returns>
/// true, если перемещение произошло, false, если нет.
/// </returns>
public virtual bool MoveTo(Point newLocation)
{
return Move((Size)newLocation - (Size)location);
}
}
/// <summary>
/// Собирает и хранит информацию о следах спрайтов, формирующих список.
/// </summary>
/// <remarks>
/// Объекты класса TracedSpriteList в добавление к свойствам своего предка
/// SpriteList создают и поддерживают битовый массив, хранящий информацию о
/// каждом пикселе клиентской области. Если пиксел является следом спрайта,
/// то соответствующий элемент массива имеет значение true, если нет, то false.
/// Класс TracedSpriteList перекрывает методы RemoveSpriteAt и Clear, уничтожая
/// информацию о следе удаляемого спрайта.
/// </remarks>
public class TracedSpriteList : SpriteList
{
/// <summary>
/// Хранит двумерный битовый массив, отображающий состояние пикселей
/// прямоугольника объекта Control - принадлежит ли пиксел следу спрайта, или фону.
/// </summary>
BitArray[] traceMap;
/// <summary>
/// Возвращает ссылку на битовый массив состояния следов спрайтов.
/// </summary>
internal BitArray[] TraceMap { get { return traceMap; } }
/// <summary>
/// Инициализирует экземпляр объекта класса TracedSpriteList.
/// </summary>
/// <param name="control">
/// Объект, на котором изображаются спрайты.
/// </param>
public TracedSpriteList(Control control) : base(control)
{
traceMap = new BitArray[ClientRect.Width];
for (int i = 0; i < traceMap.Length; i++)
traceMap[i] = new BitArray(ClientRect.Height);
}
/// <summary>
/// Убирает спрайт из списка.
/// </summary>
/// <param name="z">
/// Индекс-слой устраняемого спрайта.
/// </param>
public override void RemoveSpriteAt(int z)
{
if (z > -1 && z < Count)
{
((TracedSprite)this[z]).TracePoints.Clear();
base.RemoveSpriteAt(z);
}
}
/// <summary>
/// Очищает список от спрайтов.
/// </summary>
public override void Clear()
{
for (int i = 0; i < traceMap.Length; i++)
for (int j = 0; j < traceMap[i].Count; j++)
traceMap[i][j] = false;
base.Clear();
}
}
/// <summary>
/// Спрайт, оставляющий след.
/// </summary>
/// <remarks>
/// Класс TracedSprite как и его предок является абстрактным.
/// Наследники класса TracedSprite получают возможность оставлять
/// след на клиентской области в форме отдельного пикселя на месте
/// положения своего центра в момент, предшествующий смене положения.
/// Порождать объекты класса TracedSprite должен метод Add, вызванный классом
/// TracedSpriteList. В противном случае будет сгенерирована
/// исключительная ситуация типа ArgumentException.
/// </remarks>
public abstract class TracedSprite : Sprite
{
/// <summary>
/// Хранит true, если спрайт оставляет след, и false, если нет.
/// </summary>
bool traced;
/// <summary>
/// Устанавливает и возвращает значение поля traced.
/// </summary>
public bool Traced { set { traced = value; } get { return traced; } }
/// <summary>
/// Хранит true, если пиксели следа
/// имеют специальный цвет, и false, если нет.
/// </summary>
/// <remarks>
/// Если пиксели следа не имеют специального цвета, то их цвет определяется
/// как дополнительный до белого от цвета пикселя фона.
/// </remarks>
bool traceColored;
/// <summary>
/// Устанавливает и возвращает значение поля traceColored.
/// </summary>
public bool TraceColored
{
set { traceColored = value; }
get { return traceColored; }
}
/// <summary>
/// Хранит цвет следа.
/// </summary>
Color traceColor = Color.White;
/// <summary>
/// Устанавливает и возвращает цвет следа.
/// </summary>
public Color TraceColor
{
set { traceColored = true; traceColor = value; }
get { return traceColor; }
}
/// <summary>
/// Хранит координаты точек следа.
/// </summary>
ArrayList tracePoints = new ArrayList();
/// <summary>
/// Возвращает ссылку на список координат точек следа.
/// </summary>
public ArrayList TracePoints { get { return tracePoints; } }
/// <summary>
/// Хранит относительное положение центра спрайта.
/// </summary>
Size centerOffset;
/// <summary>
/// Хранит абсолютное положение центра спрайта.
/// </summary>
Point center;
/// <summary>
/// Возвращает положение центра спрайта.
/// </summary>
public Point Center { get { return center; } }
/// <summary>
/// Инициализирует экземпляр объекта класса TracedSprite.
/// </summary>
/// <param name="SpriteRect">
/// Прямоугольник спрайта.
/// <param name="sprites">
/// Список спрайтов, которому принадлежит создаваемый экземпляр.
/// </param>
internal TracedSprite(Rectangle SpriteRect, SpriteList sprites) : base(SpriteRect, sprites)
{
if (!(Sprites is TracedSpriteList))
throw (new ArgumentException("Спрайт со следом может быть" +
" только членом списка - наследника TracedSpriteList!"));
centerOffset = new Size(SpriteSize.Width / 2, SpriteSize.Height / 2);
center = Location + centerOffset;
}
/// <summary>
/// Перемещает спрайт на плоскости XY.
/// </summary>
/// <param name="drift">
/// Вектор смещения.
/// </param>
/// <returns>
/// true, если перемещение произошло, и false, если нет.
/// </returns>
public override bool Move(Size drift)
{
if (Visible && Traced) PutTrace();
bool result = base.Move(drift);
if (result) center = Location + centerOffset;
return result;
}
/// <summary>
/// Изображает след спрайта.
/// </summary>
/// <remarks>
/// След спрайта изображается в виде пикселя измененного цвета в точке,
/// где находился центр спрайта на момент его перемещения.
/// </remarks>
public void PutTrace()
{
for (int i = Sprites.Count - 1; i >= 0; i--)
if (Sprites[i].Visible &&
Sprites[i].SpriteRect.Contains(center))
Sprites[i].Restore();
if (!((TracedSpriteList)Sprites).TraceMap[center.X - Sprites.ClientRect.Left]
[center.Y - Sprites.ClientRect.Top])
{
if (!traceColored)
using (Bitmap bitmap = new Bitmap(1, 1))
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.CopyFromScreen(Sprites.Parent.RectangleToScreen(
new Rectangle(center.X, center.Y, 1, 1)).Location,
new Point(), bitmap.Size);
Color clr = bitmap.GetPixel(0, 0);
using (Brush brush = new SolidBrush(
Color.FromArgb(0xff ^ clr.R, 0xff ^ clr.G, 0xff ^ clr.B)))
Sprites.Canvas.FillRectangle(brush, center.X, center.Y, 1, 1);
}
else
using (Brush brush = new SolidBrush(traceColor))
Sprites.Canvas.FillRectangle(brush, center.X, center.Y, 1, 1);
((TracedSpriteList)Sprites).TraceMap[center.X - Sprites.ClientRect.Left]
[center.Y - Sprites.ClientRect.Top] = true;
tracePoints.Add(new Point(center.X, center.Y));
}
foreach (TracedSprite sprite in Sprites)
if (sprite.Visible && sprite.SpriteRect.Contains(center))
sprite.Paint();
}
/// <summary>
/// Очищает коллекцию точек следа спрайта.
/// </summary>
~TracedSprite()
{
if (TracePoints != null && TracePoints.Count > 0) TracePoints.Clear();
}
}
/// <summary>
/// Спрайт в форме заполненного эллипса, заданного цвета и градиента.
/// </summary>
public class FillEllipseSprite : TracedSprite
{
/// <summary>
/// Хранит цвет спрайта.
/// </summary>
Color color = System.Drawing.Color.Gray;
/// <summary>
/// Возвращает и устанавливает цвет спрайта.
/// </summary>
public Color Color
{
set { Set<Color>(ref color, value); }
get { return color; }
}
/// <summary>
/// Хранит указание на то, является ли заполнение эллипса градиентным.
/// </summary>
bool isGradient = true;
/// <summary>
/// Устанавливает и возвращает поле isGradient.
/// </summary>
public bool IsGradient
{
set { Set<bool>(ref isGradient, value); }
get { return isGradient; }
}
/// <summary>
/// Хранит цвета границы градиентного заполнения.
/// </summary>
Color[] colors = { Color.FromArgb(0, 0, 0) };
/// <summary>
/// Устанавливает и возвращает цвета границы градиентного заполнения.
/// </summary>
public Color[] Colors
{
set { Set<Color[]>(ref colors, value); }
get { return colors; }
}
/// <summary>
/// Инициализирует экземпляр объекта класса FillEllipseSprite.
/// </summary>
/// <param name="SpriteRect">
/// Прямоугольник эллипса.
/// <param name="sprites">
/// Список спрайтов, которому принадлежит создаваемый экземпляр.
/// </param>
public FillEllipseSprite(Rectangle SpriteRect, SpriteList sprites)
: base(SpriteRect, sprites) { }
/// <summary>
/// Изображает спрайт в форме заполненного эллипса.
/// </summary>
protected override void PaintPicture()
{
if (!isGradient)
using (Brush brush = new SolidBrush(color))
Sprites.Canvas.FillEllipse(brush, SpriteRect);
else
using (GraphicsPath path = new GraphicsPath())
{
path.AddEllipse(SpriteRect);
using (PathGradientBrush pthGrBrush = new PathGradientBrush(path))
{
pthGrBrush.CenterColor = color;
pthGrBrush.SurroundColors = colors;
Sprites.Canvas.FillEllipse(pthGrBrush, SpriteRect);
}
}
}
}
}
Предлагается в среде MS Visual Studio 2005 составить проект, тестирующий описанные классы спрайтов.