Банк рефератов содержит более 364 тысяч рефератов, курсовых и дипломных работ, шпаргалок и докладов по различным дисциплинам: истории, психологии, экономике, менеджменту, философии, праву, экологии. А также изложения, сочинения по литературе, отчеты по практике, топики по английскому.
Полнотекстовый поиск
Всего работ:
364139
Теги названий
Разделы
Авиация и космонавтика (304)
Административное право (123)
Арбитражный процесс (23)
Архитектура (113)
Астрология (4)
Астрономия (4814)
Банковское дело (5227)
Безопасность жизнедеятельности (2616)
Биографии (3423)
Биология (4214)
Биология и химия (1518)
Биржевое дело (68)
Ботаника и сельское хоз-во (2836)
Бухгалтерский учет и аудит (8269)
Валютные отношения (50)
Ветеринария (50)
Военная кафедра (762)
ГДЗ (2)
География (5275)
Геодезия (30)
Геология (1222)
Геополитика (43)
Государство и право (20403)
Гражданское право и процесс (465)
Делопроизводство (19)
Деньги и кредит (108)
ЕГЭ (173)
Естествознание (96)
Журналистика (899)
ЗНО (54)
Зоология (34)
Издательское дело и полиграфия (476)
Инвестиции (106)
Иностранный язык (62791)
Информатика (3562)
Информатика, программирование (6444)
Исторические личности (2165)
История (21319)
История техники (766)
Кибернетика (64)
Коммуникации и связь (3145)
Компьютерные науки (60)
Косметология (17)
Краеведение и этнография (588)
Краткое содержание произведений (1000)
Криминалистика (106)
Криминология (48)
Криптология (3)
Кулинария (1167)
Культура и искусство (8485)
Культурология (537)
Литература : зарубежная (2044)
Литература и русский язык (11657)
Логика (532)
Логистика (21)
Маркетинг (7985)
Математика (3721)
Медицина, здоровье (10549)
Медицинские науки (88)
Международное публичное право (58)
Международное частное право (36)
Международные отношения (2257)
Менеджмент (12491)
Металлургия (91)
Москвоведение (797)
Музыка (1338)
Муниципальное право (24)
Налоги, налогообложение (214)
Наука и техника (1141)
Начертательная геометрия (3)
Оккультизм и уфология (8)
Остальные рефераты (21692)
Педагогика (7850)
Политология (3801)
Право (682)
Право, юриспруденция (2881)
Предпринимательство (475)
Прикладные науки (1)
Промышленность, производство (7100)
Психология (8692)
психология, педагогика (4121)
Радиоэлектроника (443)
Реклама (952)
Религия и мифология (2967)
Риторика (23)
Сексология (748)
Социология (4876)
Статистика (95)
Страхование (107)
Строительные науки (7)
Строительство (2004)
Схемотехника (15)
Таможенная система (663)
Теория государства и права (240)
Теория организации (39)
Теплотехника (25)
Технология (624)
Товароведение (16)
Транспорт (2652)
Трудовое право (136)
Туризм (90)
Уголовное право и процесс (406)
Управление (95)
Управленческие науки (24)
Физика (3462)
Физкультура и спорт (4482)
Философия (7216)
Финансовые науки (4592)
Финансы (5386)
Фотография (3)
Химия (2244)
Хозяйственное право (23)
Цифровые устройства (29)
Экологическое право (35)
Экология (4517)
Экономика (20644)
Экономико-математическое моделирование (666)
Экономическая география (119)
Экономическая теория (2573)
Этика (889)
Юриспруденция (288)
Языковедение (148)
Языкознание, филология (1140)

Учебное пособие: Методические указания к курсу программирования для студентов физического факультета Сравнительное объектно-ориентированное проектирование

Название: Методические указания к курсу программирования для студентов физического факультета Сравнительное объектно-ориентированное проектирование
Раздел: Остальные рефераты
Тип: учебное пособие Добавлен 00:14:04 24 августа 2011 Похожие работы
Просмотров: 4 Комментариев: 13 Оценило: 0 человек Средний балл: 0 Оценка: неизвестно     Скачать

Министерство образования и науки Российской Федерации

Федеральное агентство по образованию

Государственное образовательное учреждение

высшего профессионального образования

«РОСТОВСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ»

МЕТОДИЧЕСКИЕ УКАЗАНИЯ

к курсу программирования

для студентов физического факультета

Сравнительное объектно-ориентированное проектирование

Delphi vs C++ vs C#

Часть 2

Ростов-на-Дону

2006

Методические указания разработаны кандидатом физико-математических наук, доцентом кафедры теоретической и вычислительной физики Г.В. Фоминым.

Ответственный редактор доктор физ.-мат. наук, профессор В.П. Саченко

Компьютерный набор и верстка Г.В. Фомин

Печатается в соответствии с решением кафедры теоретической и вычислительной физики физического факультета РГУ, протокол №1 от 17 января 2006 г.


Сравнительное объектно-ориентированное проектирование

Delphi vs C++ vs C#

Часть 2

Содержание настоящего пособия является продолжением его 1-ой части «Сравнительное объектно-ориентированное проектирование Delphi vs C++ vs C#».

Как и в первой части, здесь публикуются прокомментированные коды нескольких классов, написанных на трех языках. Слушателю предлагается создать приложения, тестирующие эти классы, предварительно разобравшись в структуре самих классов и их возможностях.

Спрайты

Это классы, реализующие алгоритм воспроизведения коллекции графических объектов, упорядоченных в третьем измерении (так называемое z -упорядочение). Каждый спрайт занимает свой «слой» в измерении, перпендикулярном экрану (z -направление), как отдельное окно. Однако в отличие от окна спрайт принадлежит коллекции, связанной лишь с одним окном.

Delphi

В Delphi код приложения разбивается на отдельные модули. Каждый модуль состоит из интерфейсной секции , секции реализации и, возможно, секции инициализации. В интерфейсной секции размещаются описания типов, переменных, заголовков процедур и функций, доступных тем частям приложения, которые ссылаются на данный модуль. В секции реализации размещается код, реализующий объявленные в интерфейсе методы классов, процедуры и функции, а также локальные типы, переменные, процедуры и функции, доступные только коду самого модуля.

Интерфейсная секция классов спрайтов

unit uSprite;

{В модуле описаны классы TSpriteList, TSprite и их наследники,

предназначенные для Z-упорядочения графических изображений

на любой канве (например канве объекта типа TPaintBox).

Конструктор класса TSpriteList имеет один параметр -

канву, на которой производится отрисовка.

Конструктор класса TSprite имеет два параметра, определяющие

прямоугольник спрайта и список, которому спрайт принадлежит.}

interface

//Модули VCL, в которых описаны используемые в интерфейсе типы

uses Controls,Graphics,Classes,Types;

type

// Предварительное объявление класса TSprite

TSprite=class;

// Тип переменных, содержащих ссылки на классы типа TSprite

TSpriteClass=class of TSprite;

// Список спрайтов

TSpriteList=class

private

// Поля

// Хранит канву ("контекст устройства"), используемую для отображения спрайтов списка

FCanvas:Controls.TControlCanvas;

// Хранит режим отображения графического объекта при его копировании на канву

FCanvasCopyMode:Graphics.TCopyMode;

// Хранит прямоугольник, ограничивающий область отображения спрайтов списка

FClientRect:Types.TRect;

// Хранит список указателей на спрайты

FList:Classes.TList;

// Хранит текущее число спрайтов в списке

FCount:integer;

// Метод

// Возвращает спрайт списка под номером aZ

function GetSprite(aZ:integer):TSprite;

public

// Свойства

// Возвращает спрайт из списка как элемент массива

property Sprites[aZ:integer]:TSprite read GetSprite;default;

// Возвращает текущее число спрайтов в списке

property Count:integer read FCount;

// Возвращает ссылку на список указателей спрайтов

property List:Classes.TList read FList;

// Возвращает ссылку на канву, с которой связаны спрайты списка

property Canvas:Controls.TControlCanvas read FCanvas;

// Возвращает прямоугольник, ограничивающий область изображения спрайтов списка

property ClientRect:Types.TRect read FClientRect;

// Конструктор

// Создает и инициализирует экземпляр списка спрайтов, связанного с данной канвой

constructor Create(const aCanvas:Controls.TControlCanvas);

// Методы

// Реализует действия перед освобождением объекта

procedure BeforeDestruction;override;

// Создает и добавляет в список объект класса aSpriteClass,

// занимающего прямоугольник SpriteRect

function AddSprite(const aSpriteClass:TSpriteClass;

const SpriteRect:Types.TRect):TSprite;

// Перемещает спрайт внутри списка в z-направлении (с одного слоя в другой)

procedure MoveSprite(const fromZ,toZ:integer);

// Удаляет спрайт с индексом aZ (слой) из списка

procedure DeleteSprite(const aZ:integer);virtual;

// Очищает список от указателей на спрайты

procedure Clear;virtual;

end;

// Тип обработчика события, наступающего перед смещением спрайта

OnMoveEvent=function(Sender:TSprite;var NewLocation:Types.TPoint):

Boolean of object;

// Абстрактный класс спрайта регулирует изображение и перемещение спрайта.

// Изображению спрайта на канве предшествует сохранение в памяти фона,

// который перекрывается изображением.

// Требуемый участок фона сохраняется в объекте типа TBitmap.

// Изображение спрайта исчезает в момент восстановления фона –

// обратного копирования на канву сохраненного участка.

TSprite=class(TObject)

private

// Поля

// Хранит состояние видимости спрайта

FVisible: boolean;

// Хранит номер слоя, занимаемого спрайтом

FZ: integer;

// Хранит маску - наличие пересечений с одним из выше лежащих спрайтов

FMask: boolean;

// Хранит ссылку на список, которому принадлежит спрайт

FSpriteList: TSpriteList;

// Хранит Bitmap, содержащий фон спрайта

FImage: Graphics.TBitmap;

// Хранит координаты левого верхнего угла спрайта

FLocation: Types.TPoint;

// Хранит размеры спрайта

FSize: Types.TSize;

// Хранит ссылку на обработчик смещения спрайта

FOnMove: OnMoveEvent;

// Методы

// Готовит спрайт к изображению

procedure BeginPaint;

// Завершает процесс изображения спрайта

procedure EndPaint;

// Устанавливает маску для спрайта из слоя aZ

procedure SetMask(const aZ:integer);

// Определяет факт перекрытия спрайтов из слоев First и Second

function Intersect(const First,Second:integer):boolean;

// Устанавливает состояние видимости спрайта

procedure SetVisible(const aVisible: Boolean);

// Возвращает прямоугольник спрайта

function GetSpriteRect:Types.TRect;

// Конструктор

// Создает и инициализирует спрайт, принадлежащий списку Sprites

// с прямоугольником SpriteRect

constructor Create(const SpriteRect: Types.TRect;const Sprites: TSpriteList);

protected

// Методы

// Восстанавливает изображение фона спрайта

procedure Restore;virtual;

// Изображает спрайт

procedure Paint;virtual;

// Формирует реальное изображение спрайта (в этом классе метод абстрактный)

procedure PaintPicture;virtual;abstract;

public

// Свойства

// Возвращает слой спрайта

property Z:integer read FZ;

// Устанавливает и возвращает обработчик при перемещении спрайта

property OnMove:OnMoveEvent read FOnMove write FOnMove;

// Устанавливает и возвращает состояние видимости спрайта

property Visible:Boolean read FVisible write SetVisible;

// Возвращает положение левого верхнего угла спрайта

property Location:Types.TPoint read FLocation;

// Возвращает размеры спрайта

property SpriteSize:Types.TSize read FSize;

// Возвращает прямоугольник спрайта

property SpriteRect:Types.TRect read GetSpriteRect;

// Возвращает ссылку на список, которому спрайт принадлежит

property SpriteList:TSpriteList read FSpriteList;

// Методы

// Выполняет инициализирующие действия сразу после создания спрайта

procedure AfterConstruction;override;

// Выполняет действия непосредственно перед освобождением спрайта

procedure BeforeDestruction;override;

// Перемещает спрайт на вектор drift

function Move(const drift: Types.TSize): boolean;virtual;

// Перемещает спрайт в новое положение NewLocation

function MoveTo(const NewLocation: Types.TPoint): boolean;virtual;

end;

// Тип массива, хранящего карту следов (пикселей) спрайтов на канве

TTraceMap=Array of array of Boolean;

// Список спрайтов, оставляющих след на канве

TTracedSpriteList=class(TSpriteList)

private

// Поле

// Хранит карту следов на канве

FTraceMap:TTraceMap;

public

//Возвращает карту следов на канве

property TraceMap:TTraceMap read FTraceMap;

// Методы

// Выполняет инициализирующие действия сразу после создания списка

procedure AfterConstruction;override;

// Выполняет действия непосредственно перед освобождением списка

procedure BeforeDestruction;override;

// Удаляет спрайт с индексом aZ (слой) из списка

procedure DeleteSprite(const aZ:integer);override;

// Очищает список от указателей на спрайты

procedure Clear;override;

end;

// Тип массива точек следа спрайта

TTracePoints=array of Types.TPoint;

// Класс, спрайты которого оставляют след перемещения

// по канве списка типа TTracedSpriteList

TTracedSprite=class(TSprite)

private

// Поля

// Хранит указание, оставляет ли спрайт след

FTraced:Boolean;

// Хранит точки со следом

FTracePoints:TTracePoints;

// Хранит указание, имеет ли след определенный цвет

FTraceColored:Boolean;

// Хранит цвет следа

FTraceColor:Graphics.TColor;

// Хранит центр спрайта

FCenter:Types.TPoint;

// Метод

// Устанавливает цвет спрайта

procedure SetTraceColor(const aTraceColor:Graphics.TColor);

public

// Свойства

// Возвращает и устанавливает указание на наличия следа

property Traced:Boolean read FTraced write FTraced;

// Возвращает и устанавливает указатель на точки следа

property TracePoints:TTracePoints read FTracePoints;

// Возвращает и устанавливает указание, имеет ли след определенный цвет

property TraceColored:Boolean read FTraceColored write FTraceColored;

// Возвращает и устанавливает цвет следа

property TraceColor:Graphics.TColor read FTraceColor write SetTraceColor;

// Возвращает центр спрайта

property Center:Types.TPoint read FCenter;

// Методы

// Выполняет инициализирующие действия сразу после создания спрайта

procedure AfterConstruction;override;

// Выполняет действия непосредственно перед освобождением спрайта

procedure BeforeDestruction;override;

// Перемещает спрайт на вектор drift

function Move(const drift:Types.TSize):boolean;override;

// Воспроизводит след

procedure PutTrace;

end;

const DefaultColor=$ffffff;//Цвет эллипса по умолчанию

type

// Класс, изображающий спрайт в форме сплошного эллипса

TEllipseSprite=class(TTracedSprite)

private

// Поле

// Хранит цвет эллипса

FColor:Graphics.TColor;

protected

// Методы

// Изображает эллипс

procedure PaintPicture;override;

// Устанавливает цвет эллипса

procedure SetColor(const aColor:Graphics.TColor);

public

// Свойство

// Возвращает и устанавливает цвет эллипса

property Color:Graphics.TColor read FColor write SetColor;

// Метод

// Выполняет инициализирующие действия сразу после создания спрайта

procedure AfterConstruction;override;

end;

Вспомним правила описания в Delphi в контексте приведенного выше интерфейса модуля uSprite. С этой целью рассмотрим фрагмент начала модуля

uses Controls,Graphics,Classes,Types;

type

// Предварительное объявление класса TSprite

TSprite=class;

// Тип переменных, содержащих ссылки на классы типа TSprite

TSpriteClass=class of TSprite;

// Список спрайтов

TSpriteList=class

// Описание членов класса

end;

· Директива uses означает, что в коде настоящего модуля используются типы, переменные, процедуры, функции или константы (короче – имена), описанные в интерфейсах модулей Controls, Graphics, Classes, Types. Все перечисленные модули принадлежат в данном случае библиотеке среды Delphi.

· Служебное слово type означает, что ниже следует описание типов . Тип – это формат переменных. Существуют стандартные типы такие как , , и другие. Их формат задан средой. Другие типы, которые оказываются необходимыми в конкретном приложении или модуле, требуют специального описания.

· Краткое описание TSprite=class; типа TSprite означает, что класс TSprite будет описан ниже, но упоминание о нем необходимо уже здесь. Дело в том, что описанный ниже класс TSpriteList использует в своем описании TSprite. В то же время полное описание класса TSprite в свою очередь содержит ссылку на класс TSpriteList. Эта взаимозависимость описаний двух классов не позволяет предпочесть в порядке описания один класс другому. Выход – дать краткое (пустое) описание одного из классов перед полным описанием другого.

· Тип TSpriteClass=class of TSprite описывает переменные, которые содержат в себе ссылки на таблицы виртуальных методов класса TSprite и его наследников. Такие переменные могут быть использованы, например, при создании экземпляра объекта, о котором во время программирования известно лишь то, что он принадлежит к семейству спрайтов, то есть является наследником класса TSprite. Так одним из параметров метода AddSprite(const aSpriteClass: TSpriteClass; const SpriteRect: Types.TRect) класса TSpriteList является переменная типа TSpriteClass, указывающая, экземпляр какого класса спрайтов следует добавить в список.

Строка TSpriteList=class открывает описание класса , которое содержит в себе поля , свойства и методы класса TSpriteList вплоть до служебного слова end, завершающего перечисление членов класса . Все поля объекта инициализируются при явном вызове конструктора в коде приложения. По умолчанию, если в теле конструктора не указаны другие значения, все поля будут инициализированы нулями.

Каждый член класса TSpriteList имеет определенный уровень доступа . Так в описании класса TSpriteList имеется две секции, выделенные модификаторами доступа private и public.

Рассмотрим фрагмент кода, описывающий класс TSpriteList:

TSpriteList=class

private

// Поля

// Хранит канву ("контекст устройства"),используемую для отображения спрайтов списка

FCanvas:Controls.TControlCanvas;

// Метод

// Возвращает спрайт списка под номером aZ

function GetSprite(aZ:integer):TSprite;

public

// Свойства

// Возвращает ссылку на канву, с которой связаны спрайты списка

property Canvas:Controls.TControlCanvas read FCanvas;

// Возвращает спрайт из списка как элемент массива

property Sprites[aZ:integer]:TSprite read GetSprite;default;

// Конструктор

// Создает и инициализирует экземпляр списка спрайтов, связанного с данной канвой

constructor Create(const aCanvas:Controls.TControlCanvas);

end;

В Delphi модификатор доступа private применяется к членам класса, которые доступны лишь тому же модулю , в котором описан сам класс, но недоступны другим модулям программы. Обычно поля класса имеют уровень доступа private. Члены класса с уровнем доступа public доступны любой части программы . Свойства класса обычно имеют уровень доступа public. Так поле FCanvas (идентификаторы полей в Delphi принято начинать буквой F от field – поле) имеет уровень доступа private, но свойство Canvas открыто для доступа. Через свойство Canvas можно прочесть поле FCanvas, но нельзя изменить его значение. Так свойства могут регулировать доступ к полям.

Что касается методов, то их разделение по уровням доступа зависит от логики класса. Так, метод GetSprite(aZ:integer):TSprite класса TSpriteList «спрятан» от внешнего доступа под модификатором private. Его роль ограничивается обеспечением доступного свойства Sprites[aZ:integer] возвращаемым значением – спрайтом с индексом aZ из списка. Другие методы класса TSpriteList имеют открытый доступ. Среди них конструктор класса Create, создающий экземпляр объекта и инициализирующий его поля. Параметром конструктора является объект типа TControlCanvas из библиотечного модуля Controls. Объекты этого типа предоставляют спрайтам область изображения - прямоугольник с известными границами в окне приложения и инструменты изображения – кисть и карандаш с цветовой палитрой.

Модификатор const, указанный в описании параметра конструктора и многих других методов, не является обязательным. Он указывает лишь на то, что метод обязуется внутри не изменять значения параметра, передаваемого ему с этим модификатором.

Модификатор default в свойстве Sprites указывает на то, что доступ к объектам класса TSpriteList может осуществляться через свойство Sprites как к элементам массива – в индексном виде.

В коде настоящего модуля имена, описанные в других модулях, специально записаны в расширенном формате с тем, чтобы явно указать их принадлежность. Например, имя типа TControlCanvas, описанного в модуле Controls, записано в расширенном виде Controls.TControlCanvas. Вообще говоря, расширенное имя можно сократить, убрав имя модуля, если отсутствует конфликт имен.

Метод

procedure BeforeDestruction; override;

имеет модификатор override. Это означает, что метод BeforeDestruction является виртуальным и унаследован от предка класса TSpriteList, где он описан как виртуальный (virtual). Предком класса TSpriteList является класс TObject.

Другие методы

procedure DeleteSprite(const aZ:integer); virtual;

procedure Clear; virtual;

описаны как виртуальные в самом классе TSpriteList. У наследника TTracedSpriteList, эти же методы преобретают модификатор override.

Рассмотрим еще один фрагмент кода, относящийся к описанию Tsprite и следующий за описанием класса TSpriteList.

// Тип обработчика события, наступающего перед смещением спрайта

OnMoveEvent=function(Sender:TSprite;var NewLocation:Types.TPoint):Boolean of object;

// Абстрактный класс спрайта, регулирующий изображение и перемещение спрайта

TSprite=class(TObject)

private

// Конструктор

// Создает и инициализирует спрайт, принадлежащий списку Sprites

// с прямоугольником SpriteRect

constructor Create(const SpriteRect:Types.TRect;const Sprites:TSpriteList);

protected

// Формирует реальное изображение спрайта (в этом классе метод абстрактный)

procedure PaintPicture;virtual;abstract;

public

end;

Здесь

· Тип функции OnMoveEvent, описанный с модификатором of object, означает, что это тип метода класса , а не просто тип какой-то отдельной функции. Разница в том, что метод класса обязательно имеет один скрытый параметр Self - экземпляр класса, который его вызывает. У обычных процедур и функций такого параметра нет. Обработчики событий в Delphi обычно имеют тип метода . Тогда в них можно подставить ссылку на метод либо формы приложения, либо другого класса, использующего объявленное событие в своих целях.

· В заголовке описания класса TSprite в скобках указан предок TObject, хотя такое указание отсутствует в описании класса TSpriteList. В Delphi отсутствие предка по умолчанию означает, что предком является класс TObject. Так что в описании класса TSprite ссылку на TObject можно также опустить.

· Конструктор класса TSprite помещен в раздел private. Это делает невозможным создание экземпляров отдельных спрайтов из кода, написанного вне модуля uSprite. Логика классов TSprite и TSpriteList предполагает, что созданием спрайтов занимается только метод Add класса TSpriteList, который только и вызывает конструктор экземпляров класса TSprite.

· В описании класса TSprite присутствуют методы с уровнем доступа protected. Эти методы и вообще члены класса с доступом protected доступны любому предку класса TSprite, даже если они описаны в других модулях, но не доступны коду других классов, описанных в других модулях.

· Среди методов класса TSprite, защищенных модификатором protected есть абстрактный метод procedure PaintPicture; virtual; abstract. Он отмечен модификатором abstract. Абстрактный метод PaintPicture не имеет реализации в классе TSprite. Его реализация будет предложена наследниками. Наличие абстрактного метода делает сам класс TSprite абстрактным в том смысле, что его экземпляры не могут быть созданы.

После описания класса TSprite описаны один тип динамического массива

// Тип массива, хранящего карту следов (пикселей) спрайтов на канве

TTraceMap=Array of array of Boolean;

Тип TTraceMap описывает двумерный массив логических значений.

Динамичность массива в том, что его размер не фиксируется как постоянная величина в процессе разработки класса (design time), а определяется лишь в ходе счета (run time). Конкретные переменные, например, размеры области изображения спрайтов, приобретают реальные значения при создании экземпляра класса TTracedSpriteList=class(TSpriteList). Это происходит в методе AfterConstruction класса TTracedSpriteList, выполняющемся сразу вслед за созданием экземпляра объекта этого класса.

За описанием класса TTracedSpriteList и перед описанием класса TtracedSprite есть описание другого типа динамического массива

// Тип массива точек следа спрайта

TTracePoints=array of Types.TPoint;

Это уже одномерный массив точек - записей типа TPoint, описанных в стандартном модуле Types.

Вслед за этим описан класс

TTracedSprite=class(TSprite)

наследник класса TSprite.

Обратите внимание, что класс TTracedSprite, как и его предок TSprite, является абстрактным классом, так как не реализует абстрактный метод PaintPicture.

Вслед за описанием класса TTracedSprite расположен текст

const DefaultColor=$ffffff; //Цвет эллипса по умолчанию

type

// Класс, изображающий спрайт в форме сплошного эллипса

TEllipseSprite=class(TTracedSprite)

Здесь

· Служебное слово const указывает на то, что DefaultColor является постоянной величиной. Значение DefaultColor записано в 16-ной системе счисления, которая удобна при записи цветов. (В данном случае $ffffff означает максимальное число, содержащееся в трех байтах; в десятичной системе это число равно 224 – 1 = 1677215.) Дело в том, что информация о цвете в Delphi представляется четырехбайтовым целым числом. Старший байт используется для системных цветов, а в трех младших байтах находятся стандартные цвета – в младшем красный, в среднем зеленый и в старшем байте - синий. Другими словами чисто зеленый цвет, к примеру, отвечает числу $ff00. В 16-ричной записи видна структура байтов. Каждому байту отводится по две 16-ричные цифры. В данном случае число $ffffff означает, что все составляющие цвета входят одинаково и с полной интенсивностью – это белый цвет.

· Вслед за описанием постоянной идет описание класса TEllipseSprite, поэтому набирается служебное слово type, действие которого было отменено const.

· Класс TEllipseSprite является наследником класса TTracedSprite. В классе TEllipseSprite уже реализован абстрактный метод PaintPicture, поэтому можно создавать его экземпляры – сплошные эллипсовидые спрайты заданного цвета.

Секция реализации

В этой секции модуля находится код методов пяти классов, описанных выше

implementation uses SysUtils;

//Определяет, находится ли прямоугольник source внутри прямоугольника dest

function Contains(const source,dest:Types.TRect):Boolean;

begin

with dest do

Result:=(source.Left>=Left) and (source.Top>=Top)

and (source.Right<=Right) and (source.Bottom<=Bottom);

end {Contains};

//Реализация методов класса TSpriteList

constructor TSpriteList.Create(const aCanvas:Controls.TControlCanvas);

begin

inherited Create;

if Assigned(aCanvas) then FCanvas:=aCanvas else

raise SysUtils.Exception.Create('Конструктору класса TSpriteList не передана канва!');

FClientRect:=FCanvas.Control.ClientRect;

FCanvasCopyMode:=FCanvas.CopyMode;

FList:=Classes.TList.Create;

end {TSpriteList.Create};

procedure TSpriteList.BeforeDestruction;

begin

Clear;

FCanvas.CopyMode:=FCanvasCopyMode;

FList.Free;

FCount:=0;

inherited

end {TSpriteList.BeforeDestruction};

function TSpriteList.GetSprite(aZ:integer):TSprite;

begin

Result:=TSprite(FList[aZ]);

end {GetSprite};

function TSpriteList.AddSprite(const aSpriteClass:TSpriteClass;

const SpriteRect:Types.TRect):TSprite;

var aSprite:TSprite;

begin

Result:=nil;

if Assigned(aSpriteClass) and (SpriteRect.Right- SpriteRect.Left>0) and

(SpriteRect.Bottom-SpriteRect.Top>0) and Contains(SpriteRect,ClientRect) then

begin

aSprite:=aSpriteClass.Create(SpriteRect,Self);

aSprite.FZ:=FList.Add(aSprite);

FCount:=FList.Count;

Result:=aSprite;

end

end {AddSprite};

procedure TSpriteList.MoveSprite(const fromZ,toZ:integer);

var i,minZ:integer;

begin

if (fromZ<>toZ) and (fromZ>-1) and (fromZ<FCount) and

(toZ>-1) and (toZ<FCount) then

begin

if fromZ<toZ then minZ:=fromZ else minZ:=toZ;

for i:=FCount-1 downto minZ do

if Self[i].FVisible then Self[i].Restore;

FList.Move(fromZ,toZ);

for i:=minZ to FCount-1 do

begin

Self[i].FZ:=i;

if Self[i].FVisible then Self[i].Paint

end

end

end {MoveSprite};

procedure TSpriteList.DeleteSprite(const aZ:integer);

var i:integer;

begin

if (aZ>-1) and (aZ<FCount) then

begin

for i:= FCount-1 downto aZ do

with Self[i] do

if Visible then Restore;

Self[aZ].Free;

FList[aZ]:=nil;

FList.Delete(aZ);

FCount:=FList.Count;

for i:= aZ to FCount-1 do

with Self[i] do

begin

Dec(FZ);

if Visible then Paint;

end

end

end {TSpriteList.DeleteSprite};

procedure TSpriteList.Clear;

var i:integer;

begin

if Assigned(FList) then

for i:= FCount - 1 downto 0 do DeleteSprite(i);

end {TSpriteList.Clear};

//Реализация методов класса TSprite

constructor TSprite.Create(const SpriteRect:Types.TRect;const Sprites:TSpriteList);

begin

inherited Create;

FZ:=-1;

FSpriteList:=Sprites;

FLocation:=SpriteRect.TopLeft;

with FSize,SpriteRect do

begin

cx:=Right-Left;cy:=Bottom-Top

end;

end {TSprite.Create};

procedure TSprite.AfterConstruction;

begin

inherited;

FImage:=Graphics.TBitmap.Create;

FImage.Height:=FSize.cy;

FImage.Width:=FSize.cx;

end {TSprite.AfterConstruction};

procedure TSprite.BeforeDestruction;

begin

FImage.Free;

inherited

end {TSprite.BeforeDestruction};

procedure TSprite.SetVisible(const aVisible:Boolean);

begin

if aVisible<>FVisible then

begin

if aVisible then

begin

BeginPaint;

Paint;

EndPaint;

end else

begin

BeginPaint;

Restore;

EndPaint;

end;

FVisible:=aVisible

end

end {SetVisible};

function TSprite.Move(const drift:Types.TSize):boolean;

var NewPos:Types.TPoint;VisState:Boolean;

begin

Result:=true ;

NewPos:=Types.Point(FLocation.X+drift.cx,FLocation.Y+drift.cy);

if Assigned(FOnMove) then Result:=FOnMove(Self,NewPos);

Result:=Result and Contains(

Types.Rect(NewPos.X,NewPos.Y,NewPos.X+FSize.cx,NewPos.Y+FSize.cy),

FSpriteList.FClientRect);

if Result then

begin

VisState:=FVisible;

Visible:=false ;

FLocation:=NewPos;

Visible:=VisState

end

end {TSprite.Move};

function TSprite.MoveTo(const NewLocation:Types.TPoint):boolean;

begin

Result:=Move(Types.TSize(

Types.Point(NewLocation.X-FLocation.X,NewLocation.Y-FLocation.Y)))

end {MoveTo};

procedure TSprite.BeginPaint;

var i:integer;

begin

SetMask(FZ);

for i:=FSpriteList.FCount-1 downto FZ+1 do

with FSpriteList[i] do

if FMask and FVisible then Restore;

end {BeginPaint};

procedure TSprite.SetMask(const aZ:integer);

var i:integer;

begin

for i:=aZ+1 to FSpriteList.FCount-1 do

begin

with FSpriteList[i] do

FMask:= Intersect(aZ,i) or FMask;

if FMask then SetMask(i)

end

end {SetMask};

procedure TSprite.EndPaint;

var i:integer;

begin

for i:=FZ+1 to FSpriteList.FCount-1 do

with FSpriteList[i] do

if FMask then

begin

if FVisible then Paint;

FMask:=false

end

end {EndPaint};

procedure TSprite.Paint;

begin

with FSpriteList do

begin

FCanvas.CopyMode:=cmSrcCopy;

with FImage do

Canvas.CopyRect(Types.Rect(0,0,Width,Height),FCanvas,SpriteRect);

end;

PaintPicture

end {Paint};

procedure TSprite.Restore;

begin

with FSpriteList.FCanvas do

begin

CopyMode:= cmSrcCopy;

with FImage do CopyRect(SpriteRect,Canvas,Types.Rect(0,0,Width,Height));

end

end {Restore};

function TSprite.GetSpriteRect:Types.TRect;

begin

with FLocation,FSize do Result:=Types.Rect(X, Y, X+cx,Y+cy)

end {GetSpriteRect};

function TSprite.Intersect(const First,Second:integer):boolean;

var rect:Types.TRect;

begin

with FSpriteList[First] do

Result:=IntersectRect(rect,SpriteRect,FSpriteList[Second].SpriteRect);

end {Intersect};

//Реализация методов класса TTracedSpriteList

procedure TTracedSpriteList.AfterConstruction;

begin

inherited;

with ClientRect do SetLength(FTraceMap,Right-Left+1,Bottom-Top+1);

end {TTracedSpriteList.AfterConstruction};

procedure TTracedSpriteList.BeforeDestruction;

begin

inherited;

FTraceMap:=nil;

end {TTracedSpriteList.BeforeDestruction};

procedure TTracedSpriteList.DeleteSprite(const aZ:integer);

begin

if (aZ > -1) and (aZ < Count) then

begin

TTracedSprite(Self[aZ]).FTracePoints:=nil;

inherited DeleteSprite(aZ);

end

end {TTracedSpriteList.DeleteSprite};

procedure TTracedSpriteList.Clear;

var i,j:integer;

begin

for i:= Low(FTraceMap) to High(FTraceMap) do

for j:= Low(FTraceMap[i]) to High(FTraceMap[i]) do

FTraceMap[i,j]:= false ;

inherited Clear;

end {TTracedSpriteList.Clear};

//Реализация методов класса TTracedSprite

procedure TTracedSprite.AfterConstruction;

begin

inherited;

FCenter:=Types.CenterPoint(SpriteRect);

end {TTracedSprite.AfterConstruction};

procedure TTracedSprite.BeforeDestruction;

begin

FTracePoints:=nil;

inherited

end {TTracedSprite.BeforeDestruction};

procedure TTracedSprite.SetTraceColor(const aTraceColor:Graphics.TColor);

begin

FTraceColor:=aTraceColor;

FTraceColored:=true

end {SetTraceColor};

function TTracedSprite.Move(const drift:Types.TSize):Boolean;

begin

if FVisible and FTraced then PutTrace;

Result:=inherited Move(drift);

if Result then

FCenter:=Types.CenterPoint(SpriteRect)

end {TTracedSprite.Move};

procedure TTracedSprite.PutTrace;

var i:integer;

begin

with FCenter do

begin

for i:=FSpriteList.FCount-1 downto 0 do

begin

with FSpriteList[i] do

if FVisible and Types.PtInRect(SpriteRect,Self.FCenter)

then Restore;

end;

with TTracedSpriteList(FSpriteList),FClientRect do

if not TraceMap[x-Left,y-Top] then

begin

with FCanvas do

if FTraceColored then Pixels[x,y]:=FTraceColor else

Pixels[x,y]:=$ffffff xor Pixels[x,y];

TraceMap[x-Left,y-Top]:=true ;

SetLength(FTracePoints,High(FTracePoints)+2);

FTracePoints[High(FTracePoints)].X:=x;FTracePoints[High(FTracePoints)].Y:=y;

end;

for i:=0 to FSpriteList.FCount-1 do

begin

with FSpriteList[i] do

if FVisible and Types.PtInRect(SpriteRect,Self.FCenter)

then Paint;

end

end

end {PutTrace};

//Реализация методов класса TEllipseSprite

procedure TEllipseSprite.AfterConstruction;

begin

inherited;

FColor:=DefaultColor;

end {TEllipseSprite.AfterConstruction};

procedure TEllipseSprite.SetColor(const aColor: Graphics.TColor);

var VisState:Boolean;

begin

if FColor<>aColor then

begin

VisState:=FVisible;

Visible:=false ;

FColor:=aColor;

if VisState then Visible:=true

end

end {SetColor};

procedure TEllipseSprite.PaintPicture;

begin

with FSpriteList.FCanvas do

begin

Brush.Style:=bsSolid;

Brush.Color:=Color;

Pen.Color:=color;

Ellipse(SpriteRect);

end;

end {PaintPicture};

end {uSprite}.

Следует отметить, что в Delphi в разделе реализации можно указывать лишь имена методов, не повторяя список параметров и тип функции. Например, вместо строки кода

function TTracedSprite.Move(const drift: Types.TSize): Boolean;

можно было бы записать ее краткий вариант

function TTracedSprite.Move;

Здесь мы этим не пользовались, чтобы не затруднять чтение кода.

Предлагается составить оконное приложение, тестирующее представленные классы спрайтов. Для этого следует разместить на форме объект типа TPaintBox с произвольным фоном (в виде рисунка). Создать на нем произвольный список эллиптических спрайтов, имеющих разные атрибуты (цвет, размер) и перемещающихся в границах прямоугольника с произвольными скоростями, зеркально отражаясь от границ и оставляя след.

C++

Теперь рассмотрим версию тех же классов спрайтов, написанную на языке C++ в среде C++ Builder (6-ая версия) фирмы Borland.

Структура программного модуля в C++ несколько отличается от структуры модуля, написанного на Object Pascal в Delphi. В некотором смысле интерфейсной секции дельфийского модуля соответствует отдельный физический файл программного модуля на C++, именуемый «хэдер», или файл заголовков. Хэдер имеет расширение .h. Хэдер все же отличается от дельфийской секции interface тем, что в него можно помещать содержательную часть кода, а не только заголовки. Смотрите, к примеру, функцию Contains, описанную в хэдере.

Другой файл, имеющий расширение .cpp и то же имя, что хэдер, содержит реализацию кода, как в секции реализации дельфийского модуля. Оба файла образуют пару, соответствующую одному программному модулю типа unit в Delphi.

Хэдер

В начале рассмотрим подробнее содержание хэдера классов спрайтов модуля uSprite.

#ifndef uSpriteH

#define uSpriteH

//---------------------------------------------------------------------------

/*Модуль, в котором описаны классы TSpriteList и TSprite

для Z-упорядочения графических изображений

на любой канве (например, канве объекта типа TPaintBox).

Конструктор класса TSpriteList имеет один параметр - канву,

на которой производится отрисовка.

Конструктор класса TSprite имеет также один параметр - прямоугольник спрайта.

Объекты типа TSprite помещаются в список

методом AddSprite класса TSpriteList*/

class TSprite;

//TSpriteList

class TSpriteList

{

private :

// Поля

int count;

TControlCanvas* canvas;

TRect clientRect;

TList* list;

TCopyMode canvasCopyMode;

// Метод

TSprite* __fastcall GetItems(int );

public :

// Свойства

__property int Count={read=count};

__property TControlCanvas* Canvas={read=canvas};

__property TRect ClientRect={read=clientRect};

__property TList* List={read=list};

__property TSprite* Items[int Index]={read=GetItems};

// Конструктор

__fastcall TSpriteList(TControlCanvas* const );

// Деструктор

__fastcall virtual ~TSpriteList();

// Методы

TSprite* __fastcall AddSprite(TSprite* const );

void __fastcall MoveSprite(int const , int const );

void __fastcall virtual DeleteSprite(int const );

void __fastcall virtual Clear();

};

// Тип массива следов спрайтов на канве

typedef DynamicArray< DynamicArray < bool > > TTraceMap;

//TTracedSpriteList

class TTracedSpriteList:public TSpriteList

{

private :

// Поле

TTraceMap traceMap;

public :

// Свойство

__property TTraceMap TraceMap = {read=traceMap};

// Конструктор

__fastcall TTracedSpriteList(TControlCanvas* const );

// Деструктор

__fastcall ~TTracedSpriteList();

// Методы

void __fastcall virtual DeleteSprite(int const );

void __fastcall virtual Clear();

};

typedef bool __fastcall (__closure *OnMoveEvent)(TSprite* ,TPoint&);

//TSprite

class TSprite:public TObject

{

// Класс TSpriteList, объявленный friend , получает доступ

// к private и protected членам класса TSprite

friend class TSpriteList;

private :

// Поля

bool visible;

int z;

TSpriteList* spriteList;

OnMoveEvent onMove;

TSize size;

TPoint location;

Graphics::TBitmap* image;

bool mask;

// Методы

void __fastcall SetVisible(bool const );

TRect __fastcall GetSpriteRect();

void __fastcall BeginPaint();

void __fastcall EndPaint();

void __fastcall SetMask(int const );

bool __fastcall Intersect(int const ,int const );

protected :

// Методы

void __fastcall virtual PaintPicture()=0;

void __fastcall virtual Restore();

void __fastcall virtual Paint();

public :

// Свойства

__property bool Visible={read=visible,write=SetVisible};

__property int Z={read=z};

__property TSpriteList* SpriteList={read=spriteList};

__property OnMoveEvent OnMove={read=onMove,write=onMove};

__property TSize Size={read=size};

__property TPoint Location={read=location};

__property TRect SpriteRect={read=GetSpriteRect};

// Конструктор

__fastcall TSprite(TRect const );

// Деструктор

__fastcall virtual ~TSprite();

// Методы

bool __fastcall virtual Move(TSize const );

bool __fastcall virtual MoveTo(TPoint const );

};

// Тип динамического массива точек со следами спрайта

typedef DynamicArray <TPoint> TTracePoints;

//TTracedSprite

class TTracedSprite:public TSprite

{

private :

// Поля

TTracePoints trPoints;

bool traced;

bool traceColored;

TColor traceColor;

TPoint center;

// Метод

void __fastcall SetTraceColor(TColor const );

public :

// Свойство

__property TTracePoints TrPoints={read=trPoints};

__property bool Traced={read=traced,write=traced};

__property TColor TraceColor={read=traceColor,write=SetTraceColor};

__property bool TraceColored={read=traceColored,write=traceColored};

__property TPoint Center={read=center};

// Конструктор

__fastcall TTracedSprite(TRect const );

// Деструктор

__fastcall ~TTracedSprite();

// Методы

bool __fastcall virtual Move(TSize const );

void __fastcall PutTrace();

};

const TColor DefaultColor=0xffffff;

//TEllipseSprite

class TEllipseSprite:public TTracedSprite

{

private :

// Поле

TColor color;

protected :

// Методы

void __fastcall virtual PaintPicture();

void __fastcall SetColor(TColor const );

public :

// Свойство

__property TColor Color={read=color, write=SetColor};

// Конструктор

__fastcall TEllipseSprite(TRect const );

};

bool Contains(TRect const source,TRect const dest)

{

return source.Left>=dest.Left && source.Top>=dest.Top &&

source.Right<=dest.Right && source.Bottom<=dest.Bottom;

}

#endif

Весь код хэдера заключен «в скобки» защитного блокиратора вида

#ifndef uSpriteH

#define uSpriteH

#endif

Это директивы компилятору , которые переводятся так

#ifndef uSpriteH – если не определен символ uSpriteH

#define uSpriteH – определи символ uSpriteH

#endif – заверши область действия директивы «если».

Таким образом, если перед началом компиляции модуля символ uSpriteH определен , то все, что находится дальше вплоть до директивы #endif , то есть все операторы модуля, компилироваться не будут . Символ uSpriteH определяется при первой компиляции, когда он еще не определен, поэтому все повторные компиляции модуля блокируются .

Рассмотрим отдельные фрагменты кода.

class TSprite;

//TSpriteList

class TSpriteList

{

private :

// Поля

int count;

TControlCanvas* canvas;

void __fastcall SetVisible(bool const );

TRect __fastcall GetSpriteRect();

__property int Count = {read=count};

__property TSprite* Items[int Index]={read=GetItems};

// Конструктор

__fastcall TSpriteList(TControlCanvas* const );

// Деструктор

__fastcall virtual ~TSpriteList();

TSprite* __fastcall AddSprite(TSprite* const );

}

Здесь

· В описании типов и переменных на языке C в начале указывается идентификатор типа или тип, а затем имя типа или переменной: class TSpriteList или int count.

· Описание членов класса заключается в фигурные скобки. Эти скобки в C играют также роль ограничителей begin, end в Delphi.

· В описании TControlCanvas* canvas; стоит звездочка *. Это описание в языке С означает, что поле canvas является ссылкой на объект класса TControlCanvas, т.е. просто целым числом, содержащим адрес объекта в памяти. Если звездочку опустить, то canvas будет описана как объект типа TControlCanvas «по значению », т.е. содержать в себе все поля объекта типа TControlCanvas. В языке C описание объекта по значению приводит к тому, что в месте описания происходит создание реального экземпляра объекта – вызывается его «конструктор по умолчанию» и все поля инициализируются.

· В языке C нет процедур, как в Delphi, - только функции. Те функции, которые не возвращают значений, имеют тип void . Они являются аналогами процедур в Delphi.

· В C++ Builder в описании всех методов классов участвует модификатор __fastcall . Его смысл - обеспечить компиляцию в наиболее быстрый способ вызова метода при выполнении кода.

· В языке C даже, если функция не имеет параметров, в ее описании должны стоять скобки как в GetSpriteRect().

· В отличие от Delphi транслятор с языка C различает прописные и строчные буквы. Поэтому принято давать одинаковые имена полям и соответствующим свойствам, но начинать имена полей со строчной буквы, а свойств – с прописной буквы. Сравните, к примеру, описания поля count и свойства Count.

· Обратите внимание на синтаксис описания свойств в C++ Builder.

· Конструктор в C++ отличается от других методов тем, что его имя совпадает с именем класса и что он не возвращает никакой тип, даже void .

· Имя деструктора также совпадает с именем класса, но перед именем дается знак отрицания ~. Как и констуктор, деструктор не возвращает какой-либо тип. Кроме того, деструктор не должен иметь параметров. Деструктор часто объявляется виртуальным. В этом случае деструкторы всех наследников автоматически становятся виртуальными.

· В C++ модификатор virtual у виртуальных методов не заменяется у наследников на override , а остается virtual .

· В реализации на C++ у метода AddSprite есть только один параметр – ссылка на объект класса TSprite. Поэтому при обращении к методу AddSprite объект спрайта должен быть уже создан. В C++ нет возможности вызвать конструктор объекта, тип класса которого является переменной, как это делается в Delphi.

· При описании заголовков метода в хэдере языка C можно не указывать явно идентификаторы параметров – достаточно только типы. Так, в заголовке метода AddSprite указан только тип единственного параметра TSprite* const . Модификатор const играет ту же роль, что и в Delphi – параметр, объявленный как const , - не меняет своего значения внутри функции.

Прокомментируем другой фрагмент кода.

// Тип массива следов спрайтов на канве

typedef DynamicArray< DynamicArray < bool > > TTraceMap;

//TTracedSpriteList

class TTracedSpriteList:public TSpriteList

{

};

typedef bool __fastcall (__closure *OnMoveEvent)(TSprite* ,TPoint&);

//TSprite

class TSprite:public TObject

{

// Класс TSpriteList, объявленный friend , получает доступ

// к private и protected членам класса TSprite

friend class TSpriteList;

protected :

// Методы

void __fastcall virtual PaintPicture()=0;

};

Здесь

· Служебное слово typedef указывает на описание типа (подобно type в Delphi).

· Типом динамического массива, названного TTraceMap, является выражение DynamicArray< DynamicArray < bool > >. Оно имеет смысл двумерного массива («массива массивов») переменных логического типа. Имя DynamicArray является именем стандартного шаблона (template), находящегося в библиотеке C++Builder. Это параметризованные , или полиморфные (generic) функции. В Delphi нет аналогов шаблонам. Аргументом шаблона является тип. В данном случае аргументом внутреннего шаблона DynamicArray является тип bool , а аргументом внешнего – сам возвращаемый тип внутреннего шаблона DynamicArray< bool >.

· Класс TTracedSpriteList является наследником класса TSpriteList. В заголовке описания класса TTracedSpriteList присутствует ссылка на наследник TSpriteList с модификатором public . Модификатор public в данном контексте означает, что все члены, наследуемые от TSpriteList, сохраняют свою, заданную предком, доступность и в наследнике (public остается public и т.д.). Если бы модификатором был protected , то все наследуемые члены класса, объявленные в предке с модификаторами public и protected , приобрели бы в наследнике модификатор protected .

· В описании

typedef bool __fastcall (__closure *OnMoveEvent)(TSprite* ,TPoint&); именем описываемого типа является OnMoveEvent. Сам тип является методом класса с двумя параметрами типа TSprite* и TPoint&, который возвращает тип bool . То, что OnMoveEvent именно метод класса, а не просто функция, отмечено модификатором __closure . Тип TPoint является стандартным и описан в библиотеке C++Builder. Знак & служит для описания «параметра по ссылке» – аналог служебного слова var в Delphi.

· Модификаторы доступа к членам класса в C имеют слегка иной смысл, нежели в Delphi. Все члены с модификатором private доступны только методам этого же класса вне зависимости от того, в каком модуле класс описан. Члены класса с модификатором protected – только методам своего класса и классов-наследников. В Delphi члены с модификаторами private и protected доступны всему коду того модуля, в котором описан класс. Однако в C++ существует способ сделать доступными защищенные (private и protected ) члены класса другому классу. Для этого класс, методам которого разрешается доступ к защищенным членам, описывается как friend . Примером является декларация из описываемого кода friend class TSpriteList. Она говорит, что классу TSpriteList разрешается доступ ко всем без исключения членам класса TSprite.

· Обратите внимание на синтаксис описания абстрактного метода в C++ void __fastcall virtual PaintPicture()=0;

Реализация классов спрайтов

Ниже приведен полный код реализации классов спрайтов, описанных в хэдере. Комментарий к коду приводится непосредственно в тексте кода.

#include <vcl.h> //Модуль, несущий определения библиотеки VCL

/*Директива #pragma hdrstop означает окончание списка хэдеров,

компилируемых предварительно для использования в нескольких

файлах-исходниках одного проекта. В данном случае в этом списке

есть только файл vcl.h.

Директива #pragma hdrstop автоматически добавляется средой.*/

#pragma hdrstop

#include "uSprite.h" //хэдер нашего исходника

/*Директива #pragma package(smart_init) служит для «разумной»

последовательности в инициализации модулей при формировании

кода проекта. Она также автоматически добавляется средой

при создании нового модуля.*/

#pragma package(smart_init)

/*Далее располагается собственно авторский код.

Любой метод класса должен иметь в заголовке

имя класса, отделенного от имени самого метода

двойным двоеточием. В Delphi это была точка.*/

// Здесь реализуются методы класса TSpriteList.

// Конструктор инициализирует поля класса

__fastcall TSpriteList::TSpriteList(TControlCanvas* const canvas)

{

if (canvas) //Условие оператора if всегда пишется в скобках.

/* Проверку наличия не нулевого указателя можно проводить,

используя просто сам указатель, как в коде.

Это равносильно записи условия в виде (canvas!=NULL) –

указатель canvas не равен NULL*/

{

// служебное слово this в C имеет смысл self в Delphi – указатель на вызывающий объект

// вызов члена объекта, если объект задан своим указателем, происходит оператором ->

// оператор присвоения в С имеет вид =, а для сравнения используется двойной знак ==

this ->canvas=canvas;

clientRect=canvas->Control->ClientRect;

canvasCopyMode=canvas->CopyMode;

list=new TList(); // Так создается экземпляр объекта. Здесь TList() – конструктор.

} else

/*Служебное слово throw используется для создания исключительной ситуации.

После этого нормальный ход программы прерывается.

Управление передается на ближайший блок catch .*/

throw Exception("Канва не задана!");

}

// Деструктор очищает список от спрайтов, восстанавливает свойства канвы

// и убирает сам экземпляр списка list

__fastcall TSpriteList::~TSpriteList()

{

Clear();

canvas->CopyMode=canvasCopyMode;

delete list; // Так вызывается деструктор объекта.

}

// Возвращает элемент списка спрайтов, отвечающий слою aZ,

// как указатель на объект типа TSprite

TSprite* __fastcall TSpriteList::GetItems(int aZ)

{

// служебное слово return вызывает выход из метода и возвращение значения функции

// выражение (TSprite*) означает преобразование типа указателя, полученного после

// вызова свойства list->Items[aZ], в указатель на TSprite

return (TSprite*)list->Items[aZ];

}

// Добавляет в список объект типа TSprite и возвращает указатель на добавленный объект

TSprite* __fastcall TSpriteList::AddSprite(TSprite* const sprite)

{

// двойной знак && есть операция логического умножения

if (sprite && Contains(sprite->SpriteRect,ClientRect))

{

sprite->spriteList=this ;

sprite->z =list->Add(sprite);

count=list->Count;

return sprite;

} else return NULL;

}

// Перемещает спрайт с одной плоскости в другую (в смысле z-упорядочения)

void __fastcall TSpriteList::MoveSprite(int const fromZ, int const toZ)

{

if (fromZ != toZ && fromZ > -1 && fromZ < count &&

toZ > -1 && toZ < count)

{

//В языке C локальные переменные (как minZ здесь)

// могут быть описаны в любой точке кода

// Выражение вида a = b?c:d называется условным выражением.

// В нем переменной a присваивается значение c, если выполняется условие b,

// и значение d, если оно не выполняется

// int minZ = fromZ < toZ ? fromZ : toZ;

// В операторе цикла значение i в начале инициализируется,

// затем проверяется условие окончания цикла,

// выполняется оператор внутри цикла (если условие соблюдено),

// затем меняется значение параметра i.

// В данном случае оператор i-- означает уменьшение i на 1.

for (int i = count - 1; i >= minZ; i--)

if (Items[i]->Visible) Items[i]->Restore();

list->Move(fromZ,toZ);

for (int i = minZ; i < count; i++)

{

Items[i]->z = i;

if (Items[i]->Visible) Items[i]->Paint();

}

}

}

// Освобождает экземпляр объекта типа TSprite,

// находящийся в списке под номером aZ, и убирает указатель из списка

void __fastcall TSpriteList::DeleteSprite(int const aZ)

{

if (aZ<count && aZ>-1)

{

for (int i= count-1;i>=aZ;i--)

if (Items[i]->Visible) Items[i]->Restore();

delete Items[aZ];

list->Items[aZ]=NULL;

list->Delete(aZ);

count=list->Count;

for (int i=aZ;i<count;i++)

{

Items[i]->z--;

if (Items[i]->Visible) Items[i]->Paint();

}

}

}

// Очищает список от всех спрайтов

void __fastcall TSpriteList::Clear()

{

if (list && count > 0)

for (int i = count - 1; i > -1; i--) DeleteSprite(i);

};

// Реализация методов класса списка спрайтов со следом TTracedSpriteList

// Конструктор вызывает конструктор предка и инициализирует поле traceMap

// После имени конструктора через двоеточие вызывается конструктор предка TSpriteList.

__fastcall TTracedSpriteList::TTracedSpriteList(TControlCanvas* const canvas):

TSpriteList(canvas) // Вызов конструктора предка

{

traceMap.Length=ClientRect.Right-ClientRect.Left+1;

for (int i=0;i<=traceMap.High;i++)

traceMap[i].Length=ClientRect.Bottom-ClientRect.Top+1;

}

// Деструктор вызывает очистку списка от спрайтов и вызывает деструктор предка

__fastcall TTracedSpriteList::~TTracedSpriteList()

{

Clear();

}

// Удаляет спрайт слоя aZ из списка и удаляет сам спрайт

void __fastcall TTracedSpriteList::DeleteSprite(int const aZ)

{

((TTracedSprite*)Items[aZ])->TrPoints.Length=0;

TSpriteList::DeleteSprite(aZ); // Вызывается метод предка

}

// Очищает следы спрайтов и вызывает унаследованный метод очистки

void __fastcall TTracedSpriteList::Clear()

{

for (int i=traceMap.Low;i<= traceMap.High;i++)

for (int j=traceMap[i].Low;j<traceMap[i].High;j++)

traceMap[i][j]=false ;

TSpriteList::Clear(); // Вызывается метод предка

}

// Реализация методов класса спрайт TSprite

// Конструктор инициализирует поля класса

__fastcall TSprite::TSprite(TRect const rect)

{

location=Point(rect.Left,rect.Top);

size.cx=rect.Width(); size.cy=rect.Height();

image=new Graphics::TBitmap();

image->Height=rect.Height();

image->Width =rect.Width();

z=-1;

}

// Деструктор уничтожает поле image

__fastcall TSprite::~TSprite()

{

delete image;

}

// Устанавливает новое значение поля visible и изображает или убирает спрайт с экрана

void __fastcall TSprite::SetVisible(bool const value)

{

if (value!=visible)

{

if (value)

{

BeginPaint();

Paint();

EndPaint();

} else

{

BeginPaint();

Restore();

EndPaint();

}

visible=value;

}

}

// Директива компилятору #define в данном случае вводит имя sprite

// для выражения ((TSprite*)(spriteList->Items[i])).

// Это укорачивает имя кода последующих методов

#define sprite ((TSprite*)(spriteList->Items[i]))

// Перемещает спрайт на вектор drift в плоскости изображения

bool __fastcall TSprite::Move(TSize const drift)

{

TPoint newPos=Point(location.x+drift.cx,location.y+drift.cy);

bool result=true ;

// В этом месте вызывается обработчик события onMove, если он задан

if (onMove) result=onMove(this ,newPos);

// Здесь используется то, что оператор присвоения в C возвращает присвоенное значение

// Переменная result приобретает новое значение и одновременно возвращает его как

// условие оператора if

if (result=result &&

Contains(Rect(newPos.x,newPos.y,newPos.x+size.cx,newPos.y+size.cy),

spriteList->ClientRect))

{

bool VisState=visible;

Visible=false ;

location=newPos;

Visible=VisState;

}

return result;

}

// Перемещает спрайт в точку newPos

bool __fastcall TSprite::MoveTo(TPoint const newPos)

{

TSize s;

s.cx=newPos.x-location.x;s.cy=newPos.y-location.y;

return Move(s);

}

// Готовит изображение спрайта

void __fastcall TSprite::BeginPaint()

{

SetMask(Z);

for (int i=spriteList->Count-1;i>=Z+1;i--)

if (sprite->mask && sprite->visible) sprite->Restore();

}

// Устанавливает маску для спрайта с индексом anID (слой)

void __fastcall TSprite::SetMask(int const anID)

{

for (int i=anID+1;i<spriteList->Count;i++)

{

sprite->mask= sprite->Intersect(anID,i) || sprite->mask;

if (mask) SetMask(i);

}

}

// Завершает изображение спрайта

void __fastcall TSprite::EndPaint()

{

for (int i=Z+1;i<spriteList->Count;i++)

if (sprite->mask)

{

if (sprite->visible) sprite->Paint();

sprite->mask=false ;

}

}

// Директива компилятору #undef отказывается от обозначения sprite

#undef sprite

// Директива компилятору #define в данном случае вводит имя canvas

#define canvas spriteList->Canvas

// Изображает спрайт на канве

void __fastcall TSprite::Paint()

{

canvas->CopyMode=cmSrcCopy;

image->Canvas->CopyRect(Rect(0,0,image->Width,image->Height),

canvas, SpriteRect);

PaintPicture();

}

// Убирает изображение спрайта с канвы, восстанавливая фон

void __fastcall TSprite::Restore()

{

canvas->CopyMode=cmSrcCopy;

canvas->CopyRect(SpriteRect, image->Canvas,

Rect(0,0,image->Width,image->Height));

}

// Директива компилятору #undef отказывается от обозначения canvas

#undef canvas

// Возвращает прямоугольник спрайта

TRect __fastcall TSprite::GetSpriteRect()

{

return Rect(location,Point(location.x+size.cx,location.y+size.cy));

}

// Определяет факт пересечения прямоугольников спрайтов,

// находящихся в слоях First и Second

bool __fastcall TSprite::Intersect(int const First,int const Second)

{

TRect rect;

return IntersectRect(rect,

((TSprite*)(spriteList->Items[First]))->SpriteRect,

((TSprite*)(spriteList->Items[Second]))->SpriteRect);

}

// Реализация методов класса спрайт со следом TtracedSprite

// Констуктор класса вызывает конструктор предка и инициализирует поле center

__fastcall TTracedSprite::TTracedSprite(TRect const rect):TSprite(rect)

{

center = CenterPoint(SpriteRect);

}

// Деструктор освобождает массив точек следа и вызывает деструктор предка

__fastcall TTracedSprite::~TTracedSprite()

{

trPoints.Length=0;

}

// Устанавливает цвет следа и, одновременно, делает след цветным

void __fastcall TTracedSprite::SetTraceColor(TColor const value)

{

traceColor=value;

traceColored=true ;

}

// Перемещает спрайт на вектор drift

bool __fastcall TTracedSprite::Move(TSize const drift)

{

if (Visible && Traced) PutTrace();

bool result=TSprite::Move(drift); // Так вызывается метод наследника

if (result) center =CenterPoint(SpriteRect);

return result;

}

#define sprite ((TTracedSprite*)(SpriteList->Items[i]))

#define sprList ((TTracedSpriteList*)SpriteList)

// Помещает пиксел следа на канву

void __fastcall TTracedSprite::PutTrace()

{

for (int i=SpriteList->Count-1;i>=0;i--)

if (sprite->Visible && PtInRect(sprite->SpriteRect,Center))

sprite->Restore();

// Знак ! означает оператор логического отрицания в C

if (!sprList->TraceMap[Center.x-sprList->ClientRect.Left]

[Center.y-sprList->ClientRect.Top])

{

SpriteList->Canvas->Pixels[Center.x][Center.y]=traceColored?traceColor:

// Знак ^ означает оператор логической симметрической разности.

(TColor)(0xffffff ^ SpriteList->Canvas->Pixels[Center.x][Center.y]);

sprList->TraceMap[Center.x-sprList->ClientRect.Left]

[Center.y-sprList->ClientRect.Top]=true ;

trPoints.Length++;

trPoints[trPoints.High].x=Center.x;

trPoints[trPoints.High].y=Center.y;

}

for (int i=0;i<SpriteList->Count;i++)

if (sprite->Visible && PtInRect(sprite->SpriteRect,Center))

sprite->Paint();

}

#undef sprite

#undef sprList

// Реализация методов класса эллиптического спрайта TEllipseSprite

// Констуктор вызывает конструктор предка и инициализирует поле color

__fastcall TEllipseSprite::TEllipseSprite(TRect const rect):

TTracedSprite(rect)

{

color=DefaultColor;

}

// Устанавливает цвет спрайта, меняя его изображение на экране

void __fastcall TEllipseSprite::SetColor(const TColor value)

{

if (color!=value)

{

bool VisState=Visible;

Visible=false ;

color=value;

if (VisState) Visible=true ;

}

}

#define canvas SpriteList->Canvas

// Создает изображение эллиптического спрайта на канве

void __fastcall TEllipseSprite::PaintPicture()

{

canvas->Brush->Style=bsSolid;

canvas->Brush->Color=color;

canvas->Pen->Color=color;

canvas->Ellipse(SpriteRect);

};

#undef canvas

Предлагается создать оконное приложение, тестирующее описанные классы спрайтов, в среде C++ Builder.

C#

В языке C# компилируемый модуль является отдельным файлом и содержит в себе сразу и описание, и реализацию методов класса. Хэдеры отсутствуют. Последовательность описания членов класса не имеет значения. Более того, такой модуль легко скомпилировать в форме отдельного исполняемого модуля с расширением .dll (dynamic link library). В отличие от exe-файла динамически загружаемая библиотека не имеет точки входа и не может выполняться независимо от вызывающего приложения.

В языке C# все типы являются классами – наследниками одного общего для всех класса Object. Это относится даже к простым типам int , double и т.д. Такие типы являются типами -значениями . К типам-значениям относится также перечислимый тип enum. Объекты типов-значений передаются целиком со всеми своими полями. Обычно это небольшие по объему структуры (struct). Другие типы классов передаются по ссылке (указателю, или адресу) и называются ссылочными типами . К ним относятся многие библиотечные и пользовательские классы (class ).

В C# cуществует специфический тип классов, обозначаемый служебным словом delegate . Тип delegate позволяет описывать указатели на любой метод класса, которые, в частности, могут служить обработчиками событий.

В нашей реализации спрайтов код всех классов помещается в отдельный компилируемый модуль, который компилируется в отдельный исполняемый модуль типа библиотеки – модуль с расширением .dll.

Весь код в C# разбит на пространства имен (namespace ). Часто отдельный компилируемый модуль относится к одному пространству имен, которое указывается в заголовке модуля (в нашем случае это namespace spritesdll). Но это не правило.

В общем случае

· один исполняемый модуль (.dll или .exe) может собираться из нескольких компилируемых модулей, образуя «сборку» (assembly);

· один компилируемый модуль может состоять из нескольких пространств имен;

· одно пространство имен может охватывать несколько компилируемых модулей;

· описание одного класса может охватывать несколько компилируемых модулей, но при этом каждый отдельный класс может принадлежать только одному пространству имен.

Далее весь комментарий находится в тексте.

/* В начале модуля обычно находится список используемых пространств имен.

Каждое из имен в списке предваряется служебным словом using .

Если имя пространства имен (например, в нашем случае, имя System.Collections)

присутствует в списке, то в коде модуля имя любого идентификатора из пространства

имен System.Collections (в нашем случае имя типа ArrayList) может быть записано

сокращенно (ArrayList) – без указания имени пространства имен

(т.е., не в виде System.Collections.ArrayList).*/

using System;

using System.Collections;

using System.Drawing;

using System.Drawing.Drawing2D;

using System.Windows.Forms;

namespace spritesdll

{

// Следующий ниже и далее в тексте комментарий, выделенный тройным слэшом ///,

// используется средой для поддержки справочной системы, описывающей элементы кода

/// <summary>

/// Поддерживает список спрайтов, используя объект типа ArrayList.

/// </summary>

/// <remarks>

/// Спрайт - плоский графический объект, занимающий прямоугольную область экрана.

/// Каждый спрайт списка принадлежит как-бы отдельной

/// изображающей плоскости экрана - z-слою.

/// Каждый спрайт списка имеет свое значение z - индекс спрайта в списке.

/// Ось z направлена перпендикулярно экрану по направлению к наблюдателю.

/// Единственным параметром конструктора класса SpriteList является

/// объект типа Control.

/// Объект Control ограничивает область перемещения спрайтов списка и

/// создает объект класса Graphics для изображения спрайта.

/// При перерисовке объекта Control или его уничтожении список очищается.

/// Каждый спрайт списка создается методом Add, параметрами которого являются

/// тип класса спрайта и занимаемый спрайтом прямоугольник.

/// Метод Add возвращает экземпляр созданного спрайта.

/// Прямоугольник спрайта должен полностью принадлежать прямоугольнику

/// объекта Control.

/// Списку могут принадлежать спрайты разного типа -

/// наследники абстрактного класса Sprite.

/// Метод RemoveSpriteAt удаляет из списка спрайт, принадлежащий конкретному слою.

/// Метод Clear удаляет все спрайты из списка.

/// Метод MoveSprite перемещает спрайт из одного слоя в другой.

/// Элементы списка доступны через индексы с нулевой базой.

/// </remarks>

public class SpriteList

{

/// <summary>

/// Хранит ссылку на объект типа Graphics для изображения спрайтов.

/// </summary>

Graphics canvas;

/// <summary>

/// Возвращает ссылку на объект типа Graphics для изображения спрайтов.

/// </summary>

// Так описываются свойства в C#. Модификатор доступа internal ограничивает

// доступ к члену класса тем исполняемым модулем, в котором этот член описан.

internal Graphics Canvas { get { return canvas; } }

/// <summary>

/// Хранит ссылку на Control, с которым связан список спрайтов.

/// </summary>

Control parent;

/// <summary>

/// Возвращает ссылку на Control, ограничивающий спрайты списка.

/// </summary>

internal Control Parent { get { return parent; } }

/// <summary>

/// Хранит ссылку на клиентский прямоугольник объекта Control.

/// </summary>

Rectangle clientRect;

/// <summary>

/// Возвращает ссылку на клиентский прямоугольник объекта Control.

/// </summary>

public Rectangle ClientRect { get { return clientRect; } }

/// <summary>

/// Хранит ссылку на список ссылок на спрайты.

/// </summary>

// ArrayList – стандартный класс, описанный в одной из библиотек .net.

ArrayList list = new ArrayList();

/// <summary>

/// Возвращает ссылку на список ссылок на спрайты.

/// </summary>

internal ArrayList List { get { return list; } }

/// <summary>

/// Возвращает спрайт - элемент списка из данного слоя.

/// </summary>

/// <param name="z">

/// Слой-индекс спрайта в списке.

/// </param>

/// <returns>

/// Спрайт из слоя z.

/// </returns>

// Так описывается свойство, индексирующее объекты класса – так называемый индексатор

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>

/// Определяет факт пересечения прямоугольников двух спрайтов.

/// </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 составить проект, тестирующий описанные классы спрайтов.

Оценить/Добавить комментарий
Имя
Оценка
Комментарии:
Хватит париться. На сайте FAST-REFERAT.RU вам сделают любой реферат, курсовую или дипломную. Сам пользуюсь, и вам советую!
Никита01:52:22 06 ноября 2021
.
.01:52:20 06 ноября 2021
.
.01:52:19 06 ноября 2021
.
.01:52:17 06 ноября 2021
.
.01:52:15 06 ноября 2021

Смотреть все комментарии (13)
Работы, похожие на Учебное пособие: Методические указания к курсу программирования для студентов физического факультета Сравнительное объектно-ориентированное проектирование

Назад
Меню
Главная
Рефераты
Благодарности
Опрос
Станете ли вы заказывать работу за деньги, если не найдете ее в Интернете?

Да, в любом случае.
Да, но только в случае крайней необходимости.
Возможно, в зависимости от цены.
Нет, напишу его сам.
Нет, забью.



Результаты(294145)
Комментарии (4230)
Copyright © 2005-2022 HEKIMA.RU [email protected] реклама на сайте