Смекни!
smekni.com

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

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>

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