Смекни!
smekni.com

Методические указания к курсу программирования для студентов физического факультета Сравнительное объектно-ориентированное проектирование (стр. 7 из 8)

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>