Рассылка закрыта
При закрытии подписчики были переданы в рассылку "RFpro.ru: Программирование на языке Pascal" на которую и рекомендуем вам подписаться.
Вы можете найти рассылки сходной тематики в Каталоге рассылок.
← Ноябрь 2004 → | ||||||
1
|
2
|
3
|
4
|
5
|
6
|
7
|
---|---|---|---|---|---|---|
8
|
9
|
10
|
11
|
12
|
13
|
14
|
15
|
16
|
17
|
18
|
19
|
20
|
21
|
22
|
23
|
24
|
25
|
27
|
28
|
|
29
|
30
|
Статистика
-5 за неделю
Pascal с нуля by [CPM] Выпуск №15
Информационный Канал Subscribe.Ru |
[Ø] Рассылка "Pascal с нуля" by [CPM]. Выпуск №15 [Ø]
::[Ø]BEGIN[Ø]::
Автор: FreeMan[CPM] mailto: vovanc@bigmir.netАвтор: MedL[CPM] mailto: medlmail@bigmir.net |
Editorial
Доброе время суток, уважаемые подписчики.
Сразу хочется извиниться за непереодичность выхода рассылки. Это связано с учёбой, поступлением в ВУЗ.
Тем не менее, рассылка не будет закрыта. Сегодня мы думали над тем, что стоит закрыть рассылку до Нового Года, но это была бы её смерть. Осознав это, мы решили написать новый выпуск. После споров о теме было решено посвятить его работе
с графикой. Это очень важная тема. После прочтения данного выпуска вы сможете нарисовать осмысленный рисунок
в графическом режиме, а может кто-нибудь захочет сделать свой графический редактор... Если у нас хватит сил, то мы опишем вам принципы создания элементарного движения. А теперь приготовьтесь к восприятию информации. Не пытайтесь за один раз прочесть весь выпуск, можете читать его частями. После объяснения чего-либо я буду показывать пример использования.
Intro
Раньше мы писали программы в текстовом режиме, где условно представляли экран как массив из 80 столбцов и 25 строк.
В каждую ячейку помещался один символ.
Но если рассмотреть каждый символ внимательнее мы можем увидеть,
что он состоит из некоторого количества точек. Отсюда возникает вопрос:
"А как нам работать с этими точками?".
Дисплей(экран) может работать в текстовом и графическом режимах.
В графическом режиме, в отличие от текстового, мы можем менять цвет
каждой отдельной, любой точки.
Это очень хорошо, что вы теперь знаете о существовании такого
замечательного режима, но этих знаний мало даже для того, чтоб установить графический режим.
Представляю крики продвинутых программеров: "А мы можем вызвать
функцию 00 прерывания BIOS 10h и перейти в графический видеорежим!"
Действительно можно так сделать, тем более каждый видеоадаптер
(начиная с VGA) поддерживает стандартные Графические Видеорежимы
(далее просто ГВ). Приведу таблицу некоторых из них:
Номер режима | Разрешение | Число цветов |
11h | 640x480 | 2 |
12h | 640x480 | 16 |
13h | 320x240 | 256 |
Хорошо, а теперь попробуйте нарисовать прямую в таком видеорежиме! Подсказка: можете использовать что-то типа алгоритма Берзенхама, который сейчас является самым распространенным алгоритмом рисования прямых.
Те, кто дочитал до этого места - люди, которые действительно интересуются программированием, которым надоел тупой текстовый режим. Некоторые, возможно, сели писать процедуры и функции для реализации рисования прямой и перехода в ГВ...
Теперь, когда остались только заинтересованные люди, расскажу вам о том, что на самом деле всё не так уж сложно... Потому, что фирма Borland Int., которая заботится о качестве и быстродействии наших программ, а также, чтоб сделать процесс "графического" программирования более эффективным выпустила специальный модуль (библиотеку) для работы с графикой, куда для того, чтоб не сильно вас нагружать программированием, уже "забито" 79 графических функций, процедур, констант и типов!!!!
Кроме самого модуля, компания запихнула в комплект несколько драйверов и шрифтов, за что им огромное спасибо.
Это в принципе и всё, что хотелось рассказать про графику. Теперь расскажу о том, как ёё программировать.
Part1. Программирование графического режима
Итак, начнём с общей структуры программы, которая будет работать с графикой.
1) Вам хочется работать с графикой? Вам надоел текстовый режим? Вам не хочется писать все процедуры для работы в графическом режиме? Подключайте модуль Graph, и ваши мечты станут реальностью.
Первое, что мы должны сделать - подключить модуль Graph. Сделать это можно в разделе Uses.
Uses graph;
Если кроме этого модуля вам надо подключить ещё какой-нибудь, то не делайте это так:
Uses crt;
Uses graph;
Делайте так:
Uses graph, crt;
2) Толку от того, что у нас подключен модуль, мало. Надо "врубить" графику. Что ж, это тоже просто.
Нужно:
а) объявить пару переменных
б) вызвать процедуру инициализации
в) проверка на ошибки.
Переменные... Объявляются в разделе объявления переменных. Нам достаточно 3 шт.
var
grDriver, grMode, ErrCode:integer;
grDriver - для инициализации адаптера
grMode - для инициализации графического режима
ErrCode - результат инициализации графики
Если grDriver=Detect, тогда производится автоматический режим, в котором можно даже не юзать grMode.
Если не равно, то в качестве номера драйвера принимается значение grDriver, а система переходит в режим, номер которого лежит в grMode.
Для инициализации надо вызвать процедуру InitGraph(var grDriver, grMode:integer; PathToDriver:string);
PathToDriver - строка, в которой содержится путь к графическому файлу. Мы будем работать с драйвером EGAVGA.bgi.
Для этого стоит закинуть его в одну папку с программой (копировать из папки BGI).
Инициализация:
begin
grDriver:=Detect;
InitGraph(grDriver, grMode, '');
Проверка на наличие ошибок:
ErrCode:=GraphResult;
{GraphResult - функция, которая возвращает число, которое зависит от результата выполнения
той или иной графической процедуры или функции}
If ErrCode=grOk then begin
{если успешно инициализировали, то работаем с графикой}
CloseGraph;
{после работы, отключаем графику}
end else
Writeln('Error:', GraphErrorMSg(ErrCode));
{если неудачно инициализировали, то известим об этом пользователя, указав причину ошибки}
end.
В результате таких нехитрых манипуляций рождается программа, которая работает
с графикой. Если слить все части в одну, то вы увидите, что получилась прога,
которая переходит в графический режим и завершается. Вот её код, в который я для
наглядности добавил процедуру рисования прямой.
Uses graph;
var
grDriver, grMode, ErrCode:integer;
begin
grDriver:=Detect;
InitGraph(grDriver, grMode, '');
ErrCode:=GraphResult;
If ErrCode=grOk then begin
Line(0,0,GetMaxX,GetMaxY);
Readln;
CloseGraph;
end else
Writeln('Error:', GraphErrorMSg(ErrCode));
end.
Результатом работы проги должна стать нарисованная из левого верхнего в
правый нижний угол прямая.
Мы разобрались с инициализацией графики. Теперь осталось рассмотреть
основные (базовые) функции и процедуры для работы в графическом режиме.
Part2. Базовые процедуры и функции.
Система координат в графическом режиме очень похожа на оную в текстовом. То есть координаты (0,0) имеет крайняя точка в левом верхнем углу
+-------------------> | | | v
В отличие от текстового режима, в графическом мы не видим курсора, хоть он
и существует.
А теперь переёдём непосредственно к описанию процедур и функции для работы
с графикой.
0) Самая первая процедура, которую мы уже достаточно успешно использовали -
процедура рисования прямой линии Line(x0,y0,x1,y1:integer);
, которая выводит прямую, которая соединяет точки с координатами (х0,у0)
и (х1,у1).
Теперь, как и обещал, текст программы, которая иллюстрирует работу этой
великолепной процедуры.
Uses graph;
var
grDriver, grMode, ErrCode:integer;
begin
grDriver:=Detect;
InitGraph(grDriver, grMode, '');
ErrCode:=GraphResult;
If ErrCode<>grOk then begin
Writeln('Error:', GraphErrorMSg(ErrCode));
readln;
halt(1);
end;
Line(120,210,120,250);
Line(120,210,160,210);
Line(120,250,160,250);
Line(160,210,160,250);
Readln;
CloseGraph;
end.
Результатом выполнения этой программы должен быть нарисованный квадрат со
стороной 40 пикселов.
1) Теперь рассмотрим пару очень похожих процедур MoveTo(x,y:integer); и MoveRel(x,y:integer);.
Первая передвигает курсор в точку с координатами (х,у). Вторая передвигает
курсор на заданное расстояние от текущей позиции на x по горизонтали и на y по
вертикали. Рассматривать работу этой процедуры будем, когда рассмотрим
следующую полезную процедуру.
2) Эта процедура LineTo(x,y:integer); рисует прямую
от текущего положения указателя до точки с координатами (х,у).
Uses graph;
var
grDriver, grMode, ErrCode:integer;
begin
grDriver:=Detect;
InitGraph(grDriver, grMode, '');
ErrCode:=GraphResult;
If ErrCode<>grOk then begin
Writeln('Error:', GraphErrorMSg(ErrCode));
readln;
halt(1);
end;
MoveTo(120,210); {MoveRel в данном случае даёт такой же результат.}
LineTo(120,250); {левая сторона}
LineTo(160,250); {нижняя}
LineTo(160,210); {правая}
LineTo(120,210); {верхняя}
Readln;
CloseGraph;
end.
Выводит такой же рисунок, как и в первом случае.
3) Как вы заметили, рисунок был нарисован белым цветом. Это цвет,
который устанавливается после инициализации. Всё, что вы рисуете,
будет нарисовано этим цветом. Но когда вызывается процедура SetColor(Col: Word);
этот цвет изменяется на цвет, номер которого был передан процедуре в качестве параметра.
Что бы вы не рисовали, рисование происходит "текущим цветом рисования".
Uses graph;
var
grDriver, grMode, ErrCode:integer;
begin
grDriver:=Detect;
InitGraph(grDriver, grMode, '');
ErrCode:=GraphResult;
If ErrCode<>grOk then begin
Writeln('Error:', GraphErrorMSg(ErrCode));
readln;
halt(1);
end;
MoveTo(120,210); {MoveRel в данном случае даёт такой же результат.}
SetColor(red);
LineTo(120,250); {левая сторона}
SetColor(green);
LineTo(160,250); {нижняя}
SetColor(yellow);
LineTo(160,210); {правая}
SetColor(blue);
LineTo(120,210); {верхняя}
Readln;
CloseGraph;
end.
Результат - квадрат с разноцветными сторонами.
4) GetColor:word; - функция, которая возвращает текущий цвет рисования.
Как вы заметили, в программе я писал что-то типа SetColor(red);. В скобках должна быть целочисленное число, а я ставлю какое-то red... Дело в том, что red это константа, которая имеет значение 4. То есть, если в проге изменить SetColor(red); на SetColor(4); это не повлияет на результат. Таблица
Номер | Константа |
0 | Black |
1 | Blue |
2 | Green |
3 | Cyan |
4 | Red |
5 | Magneta |
6 | Brown |
7 | LightGray |
8 | DarkGray |
9 | LightBlue |
10 | LightGreen |
11 | LightCyan |
12 | LightRed |
13 | LightMagneta |
14 | Yellow |
15 | White |
Цвета подобраны не идеально, но я старался.
5) PutPixel(x,y:integer; col:word); - Изменяет цвет точки с координатами (х,у) на значение col.
Uses graph,crt;
var
grDriver, grMode, ErrCode:integer;
begin
grDriver:=Detect;
InitGraph(grDriver, grMode, '');
ErrCode:=GraphResult;
If ErrCode<>grOk then begin
Writeln('Error:', GraphErrorMSg(ErrCode));
readln;
halt(1);
end;
randomize;
repeat
putpixel(random(640),random(480),random(16));
until keypressed;
Readln;
CloseGraph;
end.
Результат - компилируйте и наблюдайте.
6) ClearDevice; то же, что и ClrScr; в текстовом.
7) Rectangle (x1, y1 , x2, y2:integer ); Рисует прямоугольник, у которого диагональ - прямая из точки (х1,у1) в (х2,у2).
Uses graph;
var
grDriver, grMode, ErrCode:integer;
begin
grDriver:=Detect;
InitGraph(grDriver, grMode, '');
ErrCode:=GraphResult;
If ErrCode<>grOk then begin
Writeln('Error:', GraphErrorMSg(ErrCode));
readln;
halt(1);
end;
SetColor(4);
Rectangle (120, 210 , 160, 250);
Readln;
CloseGraph;
end.
8) Circle(x,y,radius:word); Рисует окружность с центром в точке (х,у) с радиусом radius.
Uses graph,crt;
var
grDriver, grMode, ErrCode:integer;
begin
grDriver:=Detect;
InitGraph(grDriver, grMode, '');
ErrCode:=GraphResult;
If ErrCode<>grOk then begin
Writeln('Error:', GraphErrorMSg(ErrCode));
readln;
halt(1);
end;
SetColor(Yellow);
Circle(320,240,200);
Readln;
CloseGraph;
end.
9) Ellipse (x, y, a, b, Rx, Ry: integer);
Рисует эллиптическую дугу от угла a к b, используя (x, y) как центр, Rx, Ry - это два радиуса.
А) FillEllipse (x, y, Rx, Ry:integer);
Рисует закрашенный эллипс, Rx, Ry - радиусы, а х,у - координаты центра.
В) SetLineStyle(style,shablon,width:word);
Рисование всех фигур осуществляется линиями. Эта процедура позволяет менять стиль линии.
Style | Эффект |
0 | Сплошная |
1 | Пунктир |
2 | Штрихпунктир |
3 | Штриховая |
4 | "Пользовательская" |
Width Может быть 1 - нормальная или 3 - толстая.
Shablon. Если Style не равно 4, то Shablon=0. Иначе устанавливается шаблон в виде двухбайтового числа, что означает, что каждая элементарная часть прямой (отрезок) условно делится на 16 частей. Если часть надо показать, то соответствующий бит должен быть установлен в 1.
Пример:
1111111111111111=$FFFF=65535 - обычная линия
1010101010101010=$AAAA=43690 - "точечная"
Uses graph,crt;
var
grDriver, grMode, ErrCode:integer;
begin
grDriver:=Detect;
InitGraph(grDriver, grMode, '');
ErrCode:=GraphResult;
If ErrCode<>grOk then begin
Writeln('Error:', GraphErrorMSg(ErrCode));
readln;
halt(1);
end;
randomize;
setlinestyle(2,0,3);
line(120,210,120,250); {эта сторона отображена жирной штрихпунктирной линией}
setlinestyle(3,0,1);
line(120,210,160,210); {эта нормальной штриховой}
setlinestyle(4,$aaaa,1);
line(120,250,160,250); {"точечная"}
setlinestyle(4,random($ffff),1);
line(160,210,160,250); {стиль линии задаётся случайным числом}
Readln;
CloseGraph;
end.
С) Теперь перейдем к отрисовке текста. Две процедуры OutText (text: string); и OutTextxy(x, y: integer, text: string); производят отрисовку текста. Первая из текущей позиции, а вторая с точки (х,у).
D) Теперь основные функции:
GetBkColor Возвращает текущий фоновый цвет
GetX Возвращает координату X текущей позиции
GetY Возвращает координату Y текущей позиции
GetPixel Возвращает цвет точки (x, y).
В процессе написания программ вы сами поймете что к чему. Также хочется отметить, что в Паскале есть такая полезность, как помощь. Для того, чтоб посмотреть все функции и константы введите в программе слово graph и нажмите "аккорд" ctrl + F1.
Part3. Построение графика.
Эта глава подразумевает, что вы знакомы с понятием математической функции, в
особенности её графическим представлением.
Итак, для того, чтобы построить график функции, мы должны построить
координатную плоскость. Система координат экрана построена так, что точка с
координатами (0,0) находится в верхнем правом углу экрана. Для корректного
отображения графика нам нужно, чтоб точка с координатами (0,0) была в центре
экрана. Координаты центра экрана узнаются очень просто, а для большего удобства
их лучше поместить в переменные. Пусть это будут переменные с именами х0 и у0.
Также полезно в переменных сохранить разрешение экрана.
var
maxx,maxy,x0,y0:word;
....
begin
maxx:=GetMaxX;
maxy:=GetMaxY;
x0:=maxx shr 1; {всё равно, что maxx div 2}
y0:= maxy shr 1;
Теперь удобно построить оси координат.
Line(0,y0,maxx,y0);
Line(x0,0,x0,maxy);
Треть работы выполнили. Теперь, чтоб вывести точку с координатами (х,у),
нам нужно писать не PutPixel(x,y,color);, a PutPixel(x0-x,y0-y,color);.
Теперь мы можем выводить точку с отрицательными координатами.
Если мы сейчас попробуем вывести изображение той же синусоиды, то оно
получится очень маленьким. Маленьким на столько, что мы не поймем, что это
синусоида, ведь она будет подниматься над осью всего на 1 пиксел. Для того,
чтоб нормально видеть изображение, нам надо выбрать подходящий масштаб. Для
этого мы должны прикинуть горизонтальный и вертикальный размер графика, затем
определить масштаб по формуле (размер графика по горизонтали/размер экрана по
горизонтали). Например, если мы хотим вывести график синусоиды от -3*pi до
3*pi, то размер графика по горизонтали будет 3*pi-(-3*pi)=3*pi+3*pi=6*pi, а
масштаб будет 6*pi/maxx. Mы можем определить коэффициент увеличения графика по
вертикали - это 1/масштаб, но если рисунок сильно сжат по вертикали, то можно
этот коэффициент сделать больше(или меньше, если не помещается).
Для того, чтоб не считать координаты каждой точки на графике отдельно, это можно делать
в цикле. Сделаем программу, которая будет выводить график синуса, а после
нажатия на клавишу - косинуса.
uses crt,graph;
var mx,my,y,y1,i,x1,gd,gm:integer;
x:real;
Procedure Initgr;
var
grDriver: Integer;
grMode: Integer;
ErrCode: Integer;
begin
grDriver := Detect;
InitGraph(grDriver, grMode, '');
ErrCode := GraphResult;
if ErrCode <> grOk then
begin
Writeln('Graphics error:', GraphErrorMsg(ErrCode));
Halt(1);
end;
end;
procedure ris_osi;
begin
setcolor(15);
line(0,y1,mx,y1);
line(x1,0,x1,my);
end;
procedure ris_sin;
begin
for i:=0 to mx do
begin
x:=6*pi*i/mx; y:=y1+round(sin(x)*mx/(3*pi));
putpixel(i,y,9);
end;
setcolor(9);
outtextxy(100,30,'y=sin(x)');
end;
procedure ris_cos;
begin
for i:=0 to mx do
begin
x:=6*pi*i/mx; y:=y1+round(cos(x)*mx/(3*pi));
putpixel(i,y,10);
end;
setcolor(10);
outtextxy(100,50,'y=cos(x)');
end;
begin
initgr;
mx:=getmaxx;
my:=getmaxy;
x1:=mx shr 1;
y1:=my shr 1;
ris_osi;
ris_sin;
readln;
ClearDevice;
ris_osi;
ris_cos;
readln;
ris_sin;
readln;
closegraph;
end.
Теперь вы можете строить графики функций. Конечно, я показал построение
графиков элементарных функций. Построение графиков серьёзных функций не
рассматривается, так как это отдельная тема. Может когда-нибудь я и посвящу
ей выпуск, но к тому времени вы и без меня сможете это осуществить :)
Part4. Простейшее движение.
Движение подразумевает постепенное передвижения объекта из одной точки
в другую. Я расскажу про движение по эллипсу, из которого вы без труда
можете сделать движение по кругу.
Реализовать это очень просто через полярные координаты. То есть если нам
известна длина радиуса окружности, то координаты точки на этой окружности
будут (r*cos(alfa),r*sin(alfa)), где alfa - угол, который образует прямая,
которая соединяет эту точку с центром с горизонталью. Но чтоб перенести центр
вращения мы воспользуемся тем же приёмом, который использовали при перенесении
точки (0,0) в центр экрана. Для эллипса координата точки выглядит иначе
(r1*cos(alfa),r2*sin(alfa)).
Представляю вам исходный код своей проги.
uses graph,crt;
Procedure Initgr;
var
grDriver: Integer;
grMode: Integer;
ErrCode: Integer;
begin
grDriver := Detect;
InitGraph(grDriver, grMode, '');
ErrCode := GraphResult;
if ErrCode <> grOk then
begin
Writeln('Graphics error:', GraphErrorMsg(ErrCode));
Halt(1);
end;
end;
const
r1=200;
r2=100;
var
i:word;
begin
initgr;
i:=0;
repeat
setcolor(black);
circle(320-round(r1*cos((i-1)*pi/180)),240-round(r2*sin((i-1)*pi/180)),10);
if i=360 then i:=0;
setcolor(green);
circle(320-round(r1*cos(i*pi/180)),240-round(r2*sin(i*pi/180)),10);
inc(i);
delay(1000);
until keypressed;
end.
В программе мы в цикле изменяем угол, учитывая угол, выводим окружность,
которую не забываем вытирать. Для того, чтоб мы могли нормально наблюдать
за окружностью, я поставил небольшую задержку.
Outro.
То, что я рассказал - базовые знания, которые необходимы для работы с
графическим режимом. Для того, чтоб улучшить свои навыки в графическом
программирование, вы должны попытаться тщательно разобраться с кодом
представленных программ, попробовать самостоятельно сделать нечто подобное,
читать справку в паскале, также читать литературу, в которой рассматривается
эта тема. Немного порисовать картинки, потом перейти на графики, потом сделать,
например, бегущую строку. После того, как вы начнёте ощущать себя уверенно,
можете попробовать написать игру, пусть даже простую. Созданию простейшей игры
я хочу посвятить целый выпуск. Он выйдет после того, как мы рассмотрим создание
модуля, работу с файлом.
В следующем выпуске мы рассмотрим работу с файлами.
Если возникнут вопросы, то пишите мне или MedL'у. Наши адреса внизу.
Наша команда [CPM]:
Дизайн,
верстка и корректировка>>>
Ustas[CPM]
Тоже Пишет >>> MedL[CPM]ICQ:88883515 |
::[Ø]END.[Ø]::
© 2004 Kiev Ukraine [CPM] Group
http://subscribe.ru/
http://subscribe.ru/feedback/ |
Подписан адрес: Код этой рассылки: comp.soft.prog.pascalcpm |
Отписаться |
В избранное | ||