- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Графика DirectX в Delphi - Михаил Краснов
Шрифт:
Интервал:
Закладка:
Образы рыбок для этой программы любезно предоставлены Kelly Villoch. Рыбки будут сновать в разные стороны с различной скоростью, а пузырьки подниматься плавно вверх и лопаться, достигнув верхнего края экрана.
Особенно интересным для этого примера является использование в качестве фона "тайлового", зацикленного образа. Фон окна состоит из нескольких повторяющихся одинаковых фрагментов, состыкованных друг с другом. Так получается бесконечный образ фона.
Чтобы получить простейший хранитель экрана, достаточно переименовать исполняемый модуль любого полноэкранного приложения в файл с расширением scr и поместить его в папку System системного каталога (как правило, это C:WindowsSystem).
Но, чтобы хранитель экрана не выбивался из ряда других "скринсэйверов", необходимо хорошенько потрудиться. Так, следует обеспечить его работу в небольшом окне при предварительном просмотре, когда пользователь выбирает вкладку Заставка при задании свойств экрана (рис. 4.3).
Итак, у хранителя экрана должны быть оконный и полноэкранный режимы работы. Причем, совсем не нужно делать приложение комбинированным,
поскольку переключения между режимами по ходу работы происходить не будет. Просто надо обеспечить работу в одном из этих режимов. Требуемый режим устанавливается один раз, в начале работы, и будет действительным до самого конца его выполнения.
Далее, необходимо снабдить приложение диалоговыми окнами настройки параметров работы и задания пароля для выхода. И еще, на тот случай, если указан пароль, следует предусмотреть режим просмотра, при выходе из которого пароль не вводится и комбинация клавиш <Ctrl>+<Alt>+<Del> при работе хранителя в этом режиме не блокируется.
Также нам надо обеспечить наличие единственного модуля. Все необходимые образы не должны загружаться из других файлов, что будет совершенно неудобно для пользователя.
В этом разделе мы только начнем работу над приложением, затем упростим нашу работу, немного ограничим функциональность хранителя экрана и не будем принимать в расчет ничего, что связанно с паролем.
Рассмотрение готовой работы, проекта каталога Ех08, начнем с разбора его сердцевины - механизма визуализации жизни подводного мира.
Для хранения образов использую компоненты класса Timage, располагающиеся на форме. Хранитель экрана разместится в единственном файле.
Мне потребовались четыре образа рыбок, один образ всплывающего пузырька воздуха и образ для построения фона (рис. 4.4).
Для загрузки на поверхность образа из компонента класса Timage введена пользовательская функция createFromimage. Рыбки и пузырьки на экране будут иметь случайные размеры, чтобы при использовании цветового ключа не появлялась окантовка. Для корректного масштабирования приходится применять длинную процедуру перекладывания образа на вспомогательные объекты класса TBitMap:
function TfrmDD.CreateFromimage (var FDDS : IDirectDrawSurface7;
const Image : Timage; const imgWidth, imgHeight : Integer) : HRESULT;
var
DC : HDC;
ddsd : TDDSurfaceDesc2;
hRet : HResult;
wrkBitmapl : TBitMap;
wrkBitmap2 : TBitMap;
begin
ZeroMemory (@ddsd, SizeOf(ddsd)); with ddsd do begin
dwSize := SizeOf(ddsd);
dwFlags := DDSD_CAPS or DDSD_HEIGHT or DDSD_WIDTH;
dwWidth := imgWidth;
dwHeight := imgHeight;
ddsCaps.dwCaps := DDSCAPS_OFFSCREENPLAIN;
end;
// Создаем поверхность нужных размеров
hRet := FDD.CreateSurfасе(ddsd, FDDS, nil);
if Failed(hRet) then ErrorOut(hRet, 'Create Surface');
// Первое изображение хранит растр,
// переложенный с компонента класса TImage
wrkBitmapl := TBitMap.Create;
wrkBitmapl.Width := Image.Width;
wrkBitmapl.Height := Image.Height;
// Копирование растра, StretchBlt исказит образ
BitBlt(wrkBitmapl.Canvas.Handle, 0, 0, wrkBitmapl.Width,
wrkBitmapl.Height, Image.Canvas.Handle, 0, 0, SRCCOPY);
// Второе изображение используется для корректного масштабирования
wrkBitmap2 := TBitMap.Create;
wrkBitmap2.Width := imgWidth;
wrkBitmap2.Height := imgHeight;
// Перекладываем растр во второй битмап
wrkBitmap2.Canvas.StretchDraw (Rect (0, 0, imgWidth, imgHeight),
wrkBitmapl);
// Воспроизводим масштабированный растр на сформированной поверхности
if FDDS.GetDC(DC) = DD_OK then begin
BitBlt(DC, 0, 0, imgWidth, imgHeight,
wrkBitmap2.Canvas.Handle, 0, 0, SRCCOPY);
FDDS.ReleaseDC(DC);
end;
wrkBitmapl.Free;
wrkBitmap2.Free;
// Задаем ключ, берем цвет первого пиксела
Result := DDSetColorKey (FDDS, Image.Canvas.Pixels [0, 0]);
end;
Класс TFish инкапсулирует свойства и методы наших рыбок:
TFish = class
XFish, YFish :Integer; // Позиция на экране
Direction :0..1; // Направление движения
WidthFish :Integer; // Ширина
HeightFish :Integer; // Высота
FDDSFish :IDirectDrawSurface7; // Поверхность с образом
SpeedFish :Integer; // Скорость движения
procedure Init; // Инициализация
procedure Render; // Воспроизведение
end;
При инициализации очередной рыбки ее размеры задаются случайно, чтобы создать иллюзию пространства, как будто некоторые рыбки удалены дальше от глаза наблюдателя. Но при указании размеров я соблюдаю пропорции первоначальной картинки. Чтобы рыбка могла плавать и слева направо, и справа налево, можно заготовить два образа на каждую рыбку. Но в этом случае размер файла хранителя экрана резко увеличится. Я выбрал другой путь: имеется одна картинка каждого вида рыбок, плывущих слева направо, а при необходимости содержимое поверхности зеркально переворачивается.
Размер исполнимого файла при таком подходе не увеличивается, но мы, конечно, при каждой инициализации рыбки теряем немного во времени:
procedure TFish.Init;
procedure Rotate; // Зеркальный поворот поверхности рыбки
var
desc : TDDSURFACEDESC2; i, j : Integer; wrkW : Word;
begin
ZeroMemory (@desc, SizeOf(desc));
desc.dwSize := SizeOf(desc);
if Failed (FDDSFish.Lock (nil, desc, DDLOCK_WAIT, 0)) then Exit;
for i := 0 to (WidthFish - 1) div 2 do // Цикл по столбцам растра
for j := 0 to HeightFish - 1 do begin // Цикл по строкам растра
wrkW := PWord (Integer (desc.IpSurface) + j * desc.lPitch +
i * 2)^; // Переставляем пикселы растра
PWord (Integer (desc.IpSurface) + j * desc.lPitch + i * 2) ^ :=
PWord (Integer (desc.IpSurface) + j * desc.lPitch +
(WidthFish - I - i) * 2)л; PWord (Integer (desc.IpSurface) + j * desc.lPitch +
(WidthFish - I - i) * 2)л := wrkW;
end;
FDDSFish.Unlock (nil);
end;
begin
case random (4) of // Случайный выбор одного из четырех видов рыбок
0 : begin
WidthFish := random (141) + 24;
HeightFish := WidthFish * 129 div 164; // Сохранение пропорций
if Failed (frmDD.CreateFromlmage (FDDSFish, frmDD.imgFishl,
WidthFish, HeightFish))
then frmDD.ErrorOut(DDJTALSE, 'CreateFish');
end;
1 : begin
WidthFish := random (161) + 22; HeightFish := WidthFish * 115 div 182;
if Failed (frmDD.CreateFromlmage (FDDSFish, frmDD.imgFish2,
WidthFish, HeightFish))
then frmDD.ErrorOut(DD_FALSE, 'CreateFish');
end;
2 : begin
WidthFish := random (161) +22;
HeightFish := WidthFish * 122 div 182;
if Failed (frmDD.CreateFromlmage (FDDSFish, frmDD.imgFish3,
WidthFish, HeightFish))
then f rmDD. ErrorOut (DD__FALSE, 'CreateFish');
end;
3 : begin
WidthFish := random (175) +22; HeightFish := WidthFish * 142 div 182;
if Failed (frmDD.CreateFromlmage (FDDSFish, frmDD.imgFish4,
WidthFish, HeightFish))
then frmDD.ErrorOut(DD_FALSE, 'CreateFish');
end;
end;
Direction := random (2); // Направление движения случайно
SpeedFish := random (6) +1; // Следим, чтобы скорость была ненулевой
if Direction =0 // Плывет слева направо, значит,
// должна появиться слева экрана
then XFish := -WidthFish
else begin
XFish := ScreenWidth; // Должна появиться справа экрана
Rotate;
// Требуется зеркальный поворот картинки
end;
YFish := random (360) +5; // Глубина, на которой поплывет рыбка
end;
При отображении проплывающей рыбки надо отдельно обрабатывать ситуацию вблизи границ, когда выводится только часть образа:
procedure TFish.Render;
var
wrkRect : TRect; begin
case Direction of
0 : begin
XFish := XFish + SpeedFish; // Рыбка плывет вправо
if XFish > ScreenWidth then Init; // Уплыла за границы экрана
end;
1 : begin
XFish := XFish - SpeedFish; // Рыбка плывет влево
if XFish < -WidthFish then Init;
end;
end;
if XFish <= 0 then begin
SetRect (wrkRect, -XFish, 0, WidthFish, HeightFish);
frmDD.FDDSBack.BltFast (0, YFish, FDDSFish,
SwrkRect, DDBLTFAST_WAIT or DDBLTFAST_SRCCOLORKEY);
end
else begin
//На экране помещается вся картинка целиком
if XFish <= ScreenWidth - WidthFish then begin
frmDD.FDDSBack.BltFast (XFish, YFish, FDDSFish,
nil, DDBLTFAST_WAIT or DDBLTFAST_SRCCOLORKEY);
end
else begin
SetRect (wrkRect, 0, 0, ScreenWidth - XFish, HeightFish);
frmDD.FDDSBack.BltFast (XFish, YFish, FDDSFish,
SwrkRect, DDBLTFAST_WAIT or DDBLTFAST_SRCCOLORKEY);
end;
end;
end;
Для описания пузырьков воздуха также используется концепция ООП:
TBubble = class
X, Y : Integer; // Позиция пузырька на экране
Length : Integer; // Образы квадратные, достаточно одной величины
FDDSBubble : IDirectDrawSurface"7;
SpeedBubble : Integer;
Pict : Array of Array of Word; // Массив образа, для полупрозрачности
Alpha : Integer; // Степень прозрачности пузырька
procedure Init; // Инициализация пузырька
procedure Render, // Воспроизведение
end;
Инициализацию пузырька можно упростить. Его поверхность используется только для заполнения массива pict:
procedure TBubble.Init;
var
desc : TDDSURFACEDESC2;
i, j : Integer;
begin
Length := random (30) + 20;
if Failed (frmDD.CreateFromlmage (FDDSBubble, frmDD.imgSphere,
Length, Length) )
then frmDD.ErrorOut(DD_FALSE, 'Create Bubble');
SetLength(Pict, Length); // Задаем размер динамического массива
for i := 0 to Length - 1 do
SetLength(Pict [i], Length);
ZeroMemory (Sdesc, SizeOf(desc));
desc.dwSize := SizeOf(desc);
if Failed (FDDSBubble.Lock (nil, desc, DDLOCK_WAIT, 0)) then Exit;
for i : = 0 to Length - 1 do // Заполняем массив
for j := 0 to Length - 1 do // масштабированным образом

