public Sprite this[int z] { get { return (Sprite)list[z]; } }
/// <summary>
/// Хранит текущее число спрайтов в списке.
/// </summary>
int count;
/// <summary>
/// Возвращает число спрайтов в списке.
/// </summary>
public int Count { get { return count; } }
/// <summary>
/// Инициализирует новый экземпляр объекта класса типа SpriteList.
/// </summary>
/// <param name="control">
/// Объект типа Control, на прямоугольнике которого предполагается размещать
/// спрайты - элементы списка SpriteList.
/// </param>
/// <remarks>
/// Конструктор списка создает объект типа Graphics для изображения спрайтов
/// и добавляет к событиям перерисовки и уничтожения объекта Control
/// вызов метода Clear
/// </remarks>
public SpriteList(Control control)
{
if (control == null) throw (
new ArgumentNullException("Аргумент конструктора SpriteList не определен!"));
parent = control;
canvas = parent.CreateGraphics();
clientRect = parent.ClientRectangle;
parent.HandleDestroyed += delegate { Clear(); };
parent.Invalidated += delegate { Clear(); };
}
/// <summary>
/// Возвращает перечислитель, позволяющий перемещаться по списку.
/// </summary>
/// <returns>
/// Ссылка на объект типа IEnumerator для списка SpriteList.
/// </returns>
/// <remarks>
/// Функция GetEnumerator позволяет использовать оператор foreach
/// для членов списка (спрайтов).
/// </remarks>
public IEnumerator GetEnumerator() { return list.GetEnumerator(); }
/// <summary>
/// Очищает список и освобождает объект типа Graphics,
/// используемый для изображения спрайтов.
/// </summary>
~SpriteList()
{
Clear();
if (canvas != null) canvas.Dispose();
}
/// <summary>
/// Создает новый экземпляр спрайта и добавляет его к списку.
/// </summary>
/// <param name="SpriteType">
/// Имя класса добавляемого спрайта.
/// </param>
/// <param name="SpriteRect">
/// Прямоугольник спрайта.
/// </param>
/// <returns>
/// Созданный и добавленный в список спрайт.
/// </returns>
/// <remarks>
/// Метод Add возвращает null, если прямоугольник спрайта не
/// вписывается в прямоугольник объекта Control.
/// </remarks>
public Sprite AddSprite(Type SpriteType, Rectangle SpriteRect)
{
if (SpriteType != null && SpriteRect != null
&& SpriteRect.Height > 0 && SpriteRect.Width > 0 &&
clientRect.Contains(SpriteRect))
{
Sprite sprite;
try
{
sprite = (Sprite)Activator.CreateInstance(SpriteType,
new object[2] { SpriteRect, this });
}
catch (Exception e)
{
throw (e is System.Reflection.TargetInvocationException ?
e.InnerException : e);
}
sprite.Z = list.Add(sprite);
count = list.Count;
return sprite;
}
return null;
}
/// <summary>
/// Меняет z-слой положения спрайта.
/// </summary>
/// <param name="fromZ">
/// Исходный слой.
/// </param>
/// <param name="toZ">
/// Конечный слой.
/// </param>
public void MoveSprite(int fromZ, int toZ)
{
if (fromZ != toZ &&
fromZ > -1 && fromZ < count &&
toZ > -1 && toZ < count)
{
Sprite tempSprite;
int minZ = fromZ < toZ ? fromZ : toZ;
for (int i = count - 1; i >= minZ; i--)
if (this[i].Visible) this[i].Restore();
tempSprite = this[fromZ];
list.RemoveAt(fromZ);
list.Insert(toZ, tempSprite);
for (int i = minZ; i < count; i++)
{
this[i].Z = i;
if (this[i].Visible) this[i].Paint();
}
}
}
/// <summary>
/// Удаляет спрайт заданного слоя из списка.
/// </summary>
/// <param name="z">
/// Слой удаляемого спрайта.
/// </param>
public virtual void RemoveSpriteAt(int z)
{
if (z > -1 && z < count)
{
for (int i = count - 1; i >= z; i--)
if (this[i].Visible) this[i].Restore();
list.RemoveAt(z);
count = list.Count;
for (int i = z; i < count; i++)
{
this[i].Z--;
if (this[i].Visible) this[i].Paint();
}
}
}
/// <summary>
/// Очищает список от спрайтов.
/// </summary>
public virtual void Clear()
{
if (list != null && count > 0)
for (int i = count - 1; i > -1; i--) RemoveSpriteAt(i);
}
}
/// <summary>
/// Тип делегата, предназначенного для обработки события,
/// наступающего в методе Move перед перемещением спрайта.
/// </summary>
/// <param name="sender">
/// Экземпляр наследника класса Sprite, вызывающий обработчик.
/// <param name="newLocation">
/// Новое положение левой верхней вершины спрайта,
/// которое может быть изменено обработчиком.
/// </param>
/// <returns>
/// true, если перемещение в новое положение разрешено, и false в противном случае.
/// </returns>
public delegate bool BeforeMoveEventHandler(Sprite sender, ref Point newLocation);
/// <summary>
/// Абстрактный класс спрайтов.
/// </summary>
/// <remarks>
/// Спрайт - это графический объект, ограниченный прямоугольной областью.
/// Объекты наследников класса Sprite создаются методом AddSprite класса SpriteList.
/// Изображения спрайтов могут независимо перемещаться на экране,
/// как бы занимая каждый свой слой (z-упорядочение).
/// Для перемещения спрайтов служат методы Move и MoveTo.
/// Свойство Visible определяет присутствие спрайта на экране.
/// </remarks>
public abstract class Sprite : Object
{
/// <summary>
/// Инициализирует экземпляр объекта класса Sprite.
/// Вызывается в методе AddSprite класса SpriteList.
/// </summary>
/// <param name="SpriteRect">
/// Прямоугольник спрайта.
/// <param name="sprites">
/// Список спрайтов, которому принадлежит создаваемый экземпляр.
/// </param>
/// <remarks>
/// Конструктор инициализирует поля объекта.
/// </remarks>
internal Sprite(Rectangle SpriteRect, SpriteList sprites)
{
spriteSize = SpriteRect.Size;
location = SpriteRect.Location;
image = new Bitmap(spriteSize.Width, spriteSize.Height);
bmpCanvas = Graphics.FromImage(image);
this.sprites = sprites;
}
/// <summary>
/// Деструктор. Освобождает объект image.
/// </summary>
~Sprite()
{
if (image != null) image.Dispose();
}
/// <summary>
/// Хранит текущий индекс-слой спрайта.
/// </summary>
int z = -1;
/// <summary>
/// Возвращает и устанавливает значение индекса-слоя спрайта.
/// </summary>
public int Z { get { return z; } internal set { z = value; } }
/// <summary>
/// Хранит текущее значение маски, используемой при определении фона спрайта.
/// </summary>
bool mask;
/// <summary>
/// Устанавливает маску спрайта.
/// </summary>
/// <param name="layer">
/// Индекс (слой) спрайта.
/// </param>
void SetMask(int layer)
{
for (int i = layer + 1; i < sprites.Count; i++)
{
sprites[i].mask = sprites[i].Intersect(layer, i) || sprites[i].mask;
if (mask) SetMask(i);
}
}
/// <summary>
/// Хранит ссылку на объект класса Bitmap,
/// временно хранящего фон спрайта.
/// </summary>
Bitmap image;
/// <summary>
/// Хранит ссылку на объект класса Graphics на Bitmap, содержащий фон спрайта.
/// </summary>
Graphics bmpCanvas;
/// <summary>
/// Хранит ссылку на список типа SpriteList, которому принадлежит спрайт.
/// </summary>
SpriteList sprites;
/// <summary>
/// Устанавливает и возвращает ссылку на SpriteList, которому принадлежит спрайт.
/// </summary>
public SpriteList Sprites
{
internal set { sprites = value; }
get { return sprites; }
}
/// <summary>
/// Хранит текущее состояние видимости спрайта на экране.
/// </summary>
bool visible;
/// <summary>
/// Устанавливает и возвращает состояние видимости спрайта на экране.
/// </summary>
public bool Visible
{
set
{
if (value != visible)
{
BeginPaint();
if (value) Paint(); else Restore();
EndPaint();
visible = value;
}
}
get { return visible; }
}
/// <summary>
/// Полиморфный метод установки значений полей класса.
/// </summary>
/// <typeparam name="T">
/// Тип устанавливаемого поля.
/// </typeparam>
/// <param name="outValue">
/// Результирующее значение поля.
/// </param>
/// <param name="inValue">
/// Устанавливаемое значение поле.
/// </param>
/// <remarks>
/// Метод Set убирает спрайт с экрана на время изменения его поля типа T.
/// </remarks>
protected void Set<T>(ref T outValue, T inValue)
{
if (!outValue.Equals(inValue))
{
bool VisState = visible;
Visible = false;
outValue = inValue;
Visible = VisState;
}
}
/// <summary>
/// Хранит положение верхнего левого угла спрайта.
/// </summary>
Point location;
/// <summary>
/// Устанавливает и возвращает положение верхнего левого угла спрайта.
/// </summary>
public Point Location { get { return location; } }
/// <summary>
/// Хранит размер спрайта.
/// </summary>
Size spriteSize;
/// <summary>
/// Возвращает размер спрайта.
/// </summary>
public Size SpriteSize { get { return spriteSize; } }
/// <summary>
/// Возвращает прямоугольник спрайта
/// </summary>
public Rectangle SpriteRect { get { return new Rectangle(location, spriteSize); } }
/// <summary>
/// Хранит обработчик движения спрайта.
/// </summary>
BeforeMoveEventHandler onBeforeMove;
/// <summary>
/// Устанавливает и возвращает обработчик движения спрайта.
/// </summary>
public BeforeMoveEventHandler OnBeforeMove
{
set { onBeforeMove = value; }
get { return onBeforeMove; }
}
/// <summary>
/// Готовит изображение спрайта.
/// </summary>
void BeginPaint()
{
SetMask(z);
for (int i = sprites.Count - 1; i >= z + 1; i--)
if (sprites[i].mask && sprites[i].Visible) sprites[i].Restore();
}
/// <summary>
/// Завершает изображение спрайта.
/// </summary>
void EndPaint()
{
for (int i = z + 1; i < sprites.Count; i++)
if (sprites[i].mask)
{
if (sprites[i].Visible) sprites[i].Paint();
sprites[i].mask = false;
}
}
/// <summary>