Навигация
Главная
Поиск
Форум
FAQ's
Ссылки
Карта сайта
Чат программистов

Статьи
-Delphi
-C/C++
-Turbo Pascal
-Assembler
-Java/JS
-PHP
-Perl
-DHTML
-Prolog
-GPSS
-Сайтостроительство
-CMS: PHP Fusion
-Инвестирование

Файлы
-Для программистов
-Компонеты для Delphi
-Исходники на Delphi
-Исходники на C/C++
-Книги по Delphi
-Книги по С/С++
-Книги по JAVA/JS
-Книги по Basic/VB/.NET
-Книги по PHP/MySQL
-Книги по Assembler
-PHP Fusion MOD'ы
-by Kest
Professional Download System
Реклама
Услуги

Автоматическое добавление статей на сайты на Wordpress, Joomla, DLE
Заказать продвижение сайта
Программа для рисования блок-схем
Инженерный калькулятор онлайн
Таблица сложения онлайн
Популярные статьи
OpenGL и Delphi... 65535
Форум на вашем ... 65535
21 ошибка прогр... 65535
HACK F.A.Q 65535
Бип из системно... 65535
Гостевая книга ... 65535
Invision Power ... 65535
Пример работы с... 65535
Содержание сайт... 65535
ТЕХНОЛОГИИ ДОСТ... 65535
Организация зап... 65535
Вызов хранимых ... 65535
Создание отчето... 65535
Имитационное мо... 65535
Программируемая... 65535
Эмулятор микроп... 65535
Подключение Mic... 65535
Создание потоко... 65535
Приложение «Про... 65535
Оператор выбора... 65535
Реклама
Сейчас на сайте
Гостей: 7
На сайте нет зарегистрированных пользователей

Пользователей: 13,361
новичок: uehuat
Новости
Реклама
Выполняем курсовые и лабораторные по разным языкам программирования
Подробнее - курсовые и лабораторные на заказ
Delphi, Turbo Pascal, Assembler, C, C++, C#, Visual Basic, Java, GPSS, Prolog, 3D MAX, Компас 3D
Заказать программу для Windows Mobile, Symbian

Моделирование процесса обработки заданий пакетным режимом работы с квант...
Моделирование круглосуточного интернет кафе на GPSS + Отчет
Моделирование ЭВМ на GPSS (три класса заданий) + Пояснительная записка

Работа с несколькими спрайтами
Сергей Андрианов

12.02.2002


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

Существуют различные методы создания программ. При разработке сверху вниз сначала намечают структуру программы, определяют набор процедур, распределение их по модулям и только потом переходят к программированию. Так, как правило, делают все крупные проекты, причем можно заранее распределить весь объем работ между несколькими программистами. Однако при таком подходе требуется написать немало текста, прежде чем может быть откомпилирована первая исполняемая программа, ведь для каждой процедуры к данному моменту уже должна быть написана как минимум заглушка:
Procedure ProcName;
Begin
End;

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

До сих пор все операции, выполняемые над спрайтами, находились в теле основной программы. Пора наконец вынести их в отдельный модуль. В предыдущих статьях в основном были приведены не полные листинги, а только их изменения (подробные тексты есть по адресу www.pcworld.ru). Если же изменения затрагивают почти весь текст модуля, то, конечно, следует привести его целиком. Поэтому целесообразно совместить переделку программы на вывод нескольких спрайтов с ее декомпозицией, а также привести полные листинги довольно сильно сократившейся основной программы (листинг 1) и нового модуля, названного sprites и выполняющего все действия над спрайтами (листинг 2).

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

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

Цикл 1 по спрайтам от дальнего до ближнего:
cохранить фон;
вывести спрайт;
конец цикла.

Последующее восстановление фона должно происходить в обратном порядке.

Цикл 2 по спрайтам от ближнего до дальнего:
восстановить фон;
конец цикла.

Зритель должен видеть экран со спрайтами, а не пустой фон, поэтому следует минимизировать время от начала цикла 2 до конца 1-го. Другими словами, все дополнительные операции (вычисление координат спрайтов, реакция на органы управления и т. п.), а также обеспечение синхронизации следует располагать в теле основного цикла между концом цикла 1 и началом цикла 2.

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

Перед тем как запускать новую программу, требуется нарисовать с помощью графического редактора изображение еще одного спрайта и сохранить его на диске под именем sprt02.bmp.

Итак, на экране присутствуют два спрайта. А можно больше? Да!

Чтобы для работы этой демонстрационной программы не пришлось рисовать несколько сотен спрайтов, применена маленькая хитрость. Вы, наверное, обратили внимание, что в листинге при определении имен файлов спрайтов переменная NumSprites «закомментирована», а вместо нее указано число 2. Сами же спрайты создаются в цикле:
for i := 1 to NumSprites do
CreateSprite(NameSprt[(i mod 2)+1],random(320-Xsize),
random(200-Ysize),1,1,Sprt[i]);
где вместо i используется (i mod 2)+1.

Иначе говоря, все четные спрайты будут прочитаны из одного файла, а нечетные — из другого. Далее можно произвольно изменять количество спрайтов, варьируя переменную NumSprites и не заботясь о наличии достаточного числа файлов и об описании их имен в программе. Когда будете создавать игру, не забудьте назначить каждому спрайту свое уникальное имя.

Теперь можно увеличить количество спрайтов и посмотреть, что же произойдет. Здесь надо быть внимательным, ведь программа написана для среды DOS и может использовать примерно 450—500 Кбайт памяти, причем независимо от того, сколько ее установлено в ПК. Сейчас спрайт занимает два поля по 400 байт, т. е. около 0,78 Кбайт. В зависимости от производительности компьютера советую установить от 100 до 500 спрайтов.

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

Листинг 1
program Sprite;

uses dos, {для работы с прерыванием VideoBIOS}
crt, {для работы с клавиатурой}
pal, {для работы с палитрой}
text256, {для вывода текста}
timer18, {для измерения времени и синхронизации}
sprites; {для работы со спрайтами}
const
TextColor : byte = 0; {текущий цвет текста}
NumSprites = 2; {количество спрайтов}
NameSprt : array[1..2{NumSprites}]of string =
('sprt01.bmp','sprt02.bmp');
{имена файлов спрайтов}
var
Sprt : array[1..NumSprites]of SpriteType; {спрайты}
r : registers; {для вызова прерывания BIOS}
i : integer; {счетчик спрайтов}
s : string; {для вывода сообщений на экран}
FPS : single; {темп вывода кадров в секунду}

function sign(a:single):integer;
begin
if a = 0 then
sign := 0
else
if a > 0 then
sign := 1
else
sign := -1;
end;

begin
GetPal(p[0],0,256);
FadeOut(p);
randomize;
for i := 1 to NumSprites do
CreateSprite(NameSprt[(i mod 2)+1],random(320
-Xsize),random(200-Ysize),1,1,Sprt[i]);
r.ax := $13; { устанавливаем режим }
intr($10,r); { 320х200х256 цветов }
BlackPal;
PutBackGround; {рисуем фон}
FadeIn(p);
for i := 1 to NumSprites do begin
GetBuffer(Sprt[i]);{сохраняем фон под спрайтом}
PutSprite(Sprt[i]);{и рисуем на его месте спрайт}
end;
repeat {теперь спрайт будет двигаться по экрану}
{до тех пор, пока мы не нажмем на клавишу}
for i := NumSprites downto 1 do
PutBuffer(Sprt[i]); {восстанавливаем фон}
for i := 1 to NumSprites do begin
CalcSpritePosition(Sprt[i]);
GetBuffer(Sprt[i]); {сохраняем фон}
PutSprite(Sprt[i]); {выводим спрайт}
end;
inc(TextColor);
SetTextParm(TextColor div 16,
(TextColor + 48) div 16,1);
PutText(56,16,'Демонстрационная');
SetTextParm(TextColor and $F,0,0);
PutText(192,16,'программа');
SetTextParm(15,0,1);
FPS := GetFPS;
str(FPS:0:1,s);
PutText(120,184,' '+s+' fps ');
if FPS > 1 then {изменяем приращение}
for i := 1 to NumSprites do begin
Sprt[i].dx := sign(Sprt[i].dx)*round(70/FPS);
Sprt[i].dy := sign(Sprt[i].dy)*round(70/FPS);
end;
WaitVerticalRetrace;
{ожидаем обратный ход луча кадровой развертки}
until keypressed;
readkey; {чистим буфер клавиатуры}
FadeOut(p);
r.ax := $3;
intr($10,r); {возвращаемся в текстовый режим}
for i := NumSprites downto 1 do
DestroySprite(Sprt[i]);
end.
Листинг 2
unit sprites;
interface

uses bmpread;

const
Xsize = 20; {размеры спрайта, точек}
Ysize = 20;
TransparentColor = $FF; {"прозрачный" цвет}
type
SpriteArrayType =
array[0..Ysize-1,0..Xsize-1]of byte;
{массив, равный по размеру спрайту}
SpriteType = record
x,y : word; {текущие координаты спрайта}
dx,dy : integer; {приращения координат спрайта}
Img : ^SpriteArrayType;
{для массива с изображением спрайта}
Back : ^SpriteArrayType;
{для массива, хранящего фон под спрайтом}
end;
ScreenType = array[0..199,0..319]of byte;
{для экрана}
var
Scr : ^ScreenType; {экран}
p : array[0..767]of byte;

procedure GetBuffer(Sprite:SpriteType);
{сохранение фона под спрайтом в буфере}
procedure PutBuffer(Sprite:SpriteType);
{восстановление фона}
procedure PutSprite(Sprite:SpriteType);
{вывод спрайта на экран}
procedure CreateSprite(s:string; x,y,dx,dy:integer;
var Sprite:SpriteType); {"создание" спрайта}
procedure DestroySprite(Sprite:SpriteType);
{"уничтожение" спрайта}
procedure CalcSpritePosition(var Sprite:SpriteType);
{вычисление новых координат спрайта}
procedure PutBackground; {создание фона на экране}

implementation

procedure GetBuffer(Sprite:SpriteType);
{сохранение фона под спрайтом в буфере}
var
i,j : word; {переменные цикла}
begin
for j := 0 to Ysize-1 do
for i := 0 to Xsize-1 do
with Sprite do
Back^[j,i] := Scr^[j+y,i+x];
end;

procedure PutBuffer(Sprite:SpriteType);
{восстановление фона}
var
i,j : word; {переменные цикла}
begin
for j := 0 to Ysize-1 do
for i := 0 to Xsize-1 do
with Sprite do
Scr^[j+y,i+x] := Back^[j,i];
end;

procedure PutSprite(Sprite:SpriteType);
{вывод спрайта на экран}
var
i,j : word; {переменные цикла}
begin
for j := 0 to Ysize-1 do
for i := 0 to Xsize-1 do
with Sprite do
if Img^[j,i] <> TransparentColor then
{ставим только точки,}
{цвет которых отличается от "прозрачного"}
Scr^[j+y,i+x] := Img^[j,i];
end;

procedure CreateSprite(s:string; x,y,dx,dy:integer;
var Sprite:SpriteType); {"создание" спрайта}
var
f : file; {файл с изображением спрайта}
begin
getmem(Sprite.Img,sizeof(SpriteArrayType));
{выделяем память для спрайта}
getmem(Sprite.Back,sizeof(SpriteArrayType));
{выделяем память для буфера}
Readbmp(@(Sprite.Img^),Xsize,Ysize,@p,s);
Sprite.x := x;
Sprite.y := y; { задаем начальные значения }
Sprite.dx := dx; { координат и приращений }
Sprite.dy := dy;
end;

procedure DestroySprite(Sprite:SpriteType);
{"уничтожение" спрайта}
begin
{ возвращаем память }
freemem(Sprite.Back,sizeof(SpriteArrayType));
freemem(Sprite.Img,sizeof(SpriteArrayType));
end;

procedure CalcSpritePosition(var Sprite:SpriteType);
{вычисление новых координат спрайта}
begin { спрайта и их приращений}
{по достижении границы экрана делаем,}
{ чтобы спрайт "отразился" от нее}
with Sprite do begin
if (x + Xsize + dx) >= 319 then
dx := -dx; {вычисляем новые приращения}
if (x + dx) <= 0 then
dx := -dx; {реализующие "отражение"}
if (y + Ysize + dy) >= 199 then
dy := -dy; {спрайта от стенок}
if (y + dy) <= 0 then
dy := -dy;
x := x+dx; { вычисляем новые }
y := y+dy; { координаты спрайта }
end;
end;

procedure PutBackground; {создание фона на экране}
var
i,j : word; {переменные цикла}
begin
for j := 0 to 199 do
for i := 0 to 319 do
Scr^[j,i] := lo(i+j*8);
end;

begin
scr := ptr(SegA000,0); {указатель на экран}
end.
Опубликовал Kest October 31 2008 20:14:29 · 0 Комментариев · 23961 Прочтений · Для печати

• Не нашли ответ на свой вопрос? Тогда задайте вопрос в комментариях или на форуме! •


Комментарии
Нет комментариев.
Добавить комментарий
Имя:



smiley smiley smiley smiley smiley smiley smiley smiley smiley
Запретить смайлики в комментариях

Введите проверочный код:* =
Рейтинги
Рейтинг доступен только для пользователей.

Пожалуйста, залогиньтесь или зарегистрируйтесь для голосования.

Нет данных для оценки.
Гость
Имя

Пароль



Вы не зарегистрированны?
Нажмите здесь для регистрации.

Забыли пароль?
Запросите новый здесь.
Поделиться ссылкой
Фолловь меня в Твиттере! • Смотрите канал о путешествияхКак приготовить мидии в тайланде?
Загрузки
Новые загрузки
iChat v.7.0 Final...
iComm v.6.1 - выв...
Visual Studio 200...
CodeGear RAD Stud...
Шаблон для новост...

Случайные загрузки
Алгоритм трассиро...
BSButton
HtmlLerz PRO
Pass [Исходник на...
isoCanvas (Редакт...
Черный круг двига...
Пример работы с ф...
Indy in Depth Глу...
Разработка Web-пр...
MP3 Архив v.2.0
Delphi World 6.0
Просмотр коммент...
PCXReader. Програ...
Основы Delphi
WinPopup
Text3D
Панель случайной ...
Быстрое создание ...
BIOS
Fig [Исходник на ...

Топ загрузок
Приложение Клие... 100771
Delphi 7 Enterp... 97787
Converter AMR<-... 20259
GPSS World Stud... 17014
Borland C++Buil... 14186
Borland Delphi ... 10267
Turbo Pascal fo... 7372
Калькулятор [Ис... 5968
Visual Studio 2... 5205
Microsoft SQL S... 3661
Случайные статьи
Операции. Операции...
Что делает маска п...
годовую подписку н...
Проектирование алг...
Использование TFil...
Графические возмож...
Область визуализац...
Казино Эльдорадо и...
Требует наличия пр...
Введение в PowerShell
Как определить коо...
7.10. Просеивай ...
клиент, отправляет...
Триггеры событий, ...
ВЗЛОМ NT
Термин «инфографика»
Списки в Прологе
Цели, стоящие пере...
Сосредоточение на ...
Выбор режима экспо...
ПРИНЦИПЫ, ЛЕЖАЩИЕ ...
Что позволяет подд...
Внедрение технолог...
Использование толь...
Эти методы служат ...
Статистика



Друзья сайта
Программы, игры


Полезно
В какую объединенную сеть входит классовая сеть? Суммирование маршрутов Занимают ли таблицы память маршрутизатора?