Чтобы работать с графическим экраном, нужно использовать стандартный модуль Graph,
который подключается предложением uses:
uses ... , Graph;
При этом необходимо, чтобы среда могла найти файл graph.tpu. Обычно все стандартные модули (т е файлы *.tpu) помещают в папку ...\TPAS7\units\ где ...\TPAS7 - папка, содержащая среду Турбо Паскаль7, т е файлы:
turbo.exe - 402474 байта - среда
turbo.tp - файл конфигурации
turbo.tpl - основные библиотеки (System,Dos)
turbo.tph - файл справки
А в папку \units помещают остальные модули. Для доступности модулей среду настраивают: Меню | Options | Directories и здесь в окошко Unit directories записывают пути к необходимым модулям (если несколько - разделяют точкой с запятой). Описываемый проект хранится в папке
...\TPAS7\Juli_GR4\, и в эту же папку среда поместит после компиляции самодельный модуль, т е файл unit1.tpu, поэтому в окошко Unit directories вписано: units; Juli_GR4 чтобы это сохранилось - щелкните кнопку ОК. После того как Вы это сделаете и откроете файлы проекта: PRGRAF2.PAS и unit1.pas в среде, полезно сохранить конфигурацию (Меню | Options | Save Turbo.tp).Тогда для работы с проектом достаточно запустить среду (файл turbo.exe).
В случае, когда картинка не изменяется, а просто перемещается, выгодно
использовать хранение картинки в памяти с последующим выводом на экран из памяти. Это
быстрый способ.
В проекте - при нажатии клавиши s мяч перемещается используя режим XORPut, поэтому он проходит
по надписи, не повреждая ее. Если нажать клавишу S (т е Shift s), то мяч перемещается стирая
картинку цветом фона в режиме NormalPut, поэтому портит надпись. В конце полета мяч ударяет по шкафу и шкаф падает, вращаясь вокруг точки. Окончив падение, шкаф скользит по наклону.
Program Proba_Graph1; uses Graph,crt,unit1; begin Nacalo; {процедура устанавливает графический режим и его параметры} TTT; { процедура выводит надписи на графический экран } Repeat ch1:= #0; Menu1(5,310); {рисует меню} clearkey; {процедура очищает буфер клавиатуры} ch1:= readkey; {читаю нажатие на клавишу} case ch1 of {выбор в зависимости от нажатой клавиши} #27: begin closegraph; restorecrtmode; {востанавливаю текстовый режим экрана} exit; {Выход из программы} end; 'T','t','е','Е': TTT; {Выводит образцы графических шрифтов} 'C','c','с','С': begin ClearDevice; {очистка экрана} setcolor(gcol); setbkcolor(bcol); {восстановление цветов фона и символов} end; 'S','Ы': begin Osnova(240); {рисует треугольное основание} gaubica(50,240,10,10,'N'); {бросает мячик} pramoug(ara); {падает шкаф} siezd(ara); {шкаф скользит} end; 's','ы': begin Osnova(240); {рисует треугольное основание} gaubica(50,240,10,10,'X'); {бросает мячик} pramoug(ara); {падает шкаф} siezd(ara); {шкаф скользит} end; end; until ch1 = #27; {цикл прекратится, если нажать Esc} end.
Unit unit1; interface uses graph; type arpo = array [1..4] of PointType; {хранит коорд. вершин прямоугольника} { Справка: PointType = Record X, Y : Integer; End; } var grdriver, graphmode,errcode,maxx,maxy,ImSize: integer; ch1,ch2: char; bufs: string; bcol,gcol: byte; {хранит цвет символов и фона} alfa: double; {угол наклона основания (радиан)} P1: Pointer; {указатель на область памяти, где будет храниться картинка (мячик)} ara: arpo; {хранит коорд. вершин прямоугольника} Procedure Nacalo; {инициирует графический режим} Procedure Menu1(x0,y0: integer); {выводит меню в графическом режиме } procedure TTT; {Выводит образцы графических шрифтов} procedure Osnova(x0: integer); {рисует треугольное основание} procedure gaubica(x0,y0: integer; beta,vel: double; typ:char); {бросает мячик} procedure siezd(var ara: arpo); {шкаф скользит} procedure pramoug(var ara: arPo); {падает шкаф} procedure clearkey; procedure stopka; implementation uses crt; var hh, {высота шкафа} ww: {ширина шкафа} integer; beta: double; {угол наклона основания} Procedure Menu1(x0,y0: integer); {рисует меню} var buf1,buf2: string; begin SetTextStyle(2,0,6); {устанавливаю шрифт SmallFont, горизонтальное направление, размер = 6} str(maxx,buf1); str(maxy,buf2); {преобразую maxx,maxy в строки } setcolor(green); {устанавливаю цвет = зеленый (для рамки меню) } rectangle(x0+5,y0+5,x0+215,y0+160); {прямоугольник (рамка меню)} setfillstyle(SolidFill,8); {устанавливаю тип и цвет заливки (темносерый)} FloodFill(x0+7,y0+7, green); {Заливает фигуру, начиная от точки (x0+7,y0+7) и до границы цвета green} setcolor(11); {устанавливаю цвет (светлоголубой) - для надписей меню } OutTextXY(x0+10,y0+15, 'MaxX= '+buf1+' MaxY= '+buf2); OutTextXY(x0+10,y0+35, ' --- Menu: --- '); OutTextXY(x0+10,y0+55, ' Esc - Exit '); OutTextXY(x0+10,y0+75, ' T - Шрифты '); OutTextXY(x0+10,y0+95, ' C - CLEAR '); OutTextXY(x0+10,y0+115, ' S - NormalPut '); OutTextXY(x0+10,y0+135, ' s - XORPut '); end; Procedure Nacalo; {устанавливает графический режим и его параметры} begin bcol := 7; gcol := 11; {цвета по умолчанию} grdriver:= detect; {установка для автоматического определения графического драйвера} graphmode := 0; InitGraph(grdriver,graphmode,'..\'); {'..\'означает, что драйвер EGAVGA.BGI должен находиться во внешней папке по отношению к папке этой программы} errcode := graphresult; {проверяем успешность выполнения процедуры InitGraph } if errcode <> grOk then { если произошла ошибка} begin writeln (' ошибка инит граф режима N ',errcode); halt(1); {выход в систему с кодом возврата=1, т е аварийно} end else begin setgraphmode(graphmode); setcolor (gcol); setbkcolor(bcol); SetLineStyle(SolidLn, 0, 2); {устанавливаю: линия сплошная, толщиной 2} maxx:= getmaxx; maxy:= getmaxy; { сохраняю размеры экрана } SetTextStyle(2,0,6); {устанавливаю шрифт SmallFont, горизонтальное направление, размер = 6} end; end; procedure TTT; begin setcolor(blue); {цвет - синий (для вывода текста)} OutTextXY(10,10,'- Графические шрифты -'); SetTextStyle(1,0,4); if graphresult <> grOK then OutTextXY(10,30,'gr - ERROR') else OutTextXY(10,30,'Text ПРОБА'); SetTextStyle(2,0,8); if graphresult <> grOK then OutTextXY(10,60,'gr - ERROR') else OutTextXY(10,60,'Text ПРОБА'); SetTextStyle(3,0,4); if graphresult <> grOK then OutTextXY(10,80,'gr - ERROR') else OutTextXY(10,80,'Text ПРОБА'); SetTextStyle(4,0,4); if graphresult <> grOK then OutTextXY(10,110,'gr - ERROR') else OutTextXY(10,110,'Text ПРОБА'); SetTextStyle(4,0,6); if graphresult <> grOK then OutTextXY(10,150,'gr - ERROR') else OutTextXY(10,150,'Text ПРОБА'); setcolor(gcol); {восстанавливаю цвет по умоляанию} end; procedure moveto2(t: PointType); begin {это процедура moveto, приспособленная для работы с точками PointType} moveto(t.x,t.y); end; procedure lineto2(t: PointType); begin {это процедура lineto, приспособленная для работы с точками PointType} lineto(t.x,t.y); end; procedure siezd(var ara: arpo); var ii: Integer; sdvig,sdvigX,sdvigY: double; ar0: arpo; begin ar0:= ara; {запоминаю координаты прямоуг-ка в начальном положении } sdvig:=0; {в этой переменной хранится сдвиг (вдоль склона) скользящего шкафа относительно исходного положения } repeat {цикл скольжения шкафа} sdvig:=sdvig + 1; {на каждом шага перемещаю шкаф на 1 пикс} sdvigX:= sdvig*cos(beta); {проекция сдвига на ось X } sdvigY:= sdvig*sin(beta); {проекция сдвига на ось Y } setcolor(green); {устанавливаю цвет границы } setfillstyle(SolidFill,8); {устанавливаю режим заливки (темно-серый) } FillPoly(4, ara); {заливаю прямоугольник (шкаф) с коорд ara } delay(3000); {задержка (мсек) - чтобы увидеть шкаф. 3000 - на IBM286, на современных компах много меньше} setcolor(7); {готовлюсь стереть шкаф (цветом фона)} setfillstyle(SolidFill,7); {устанавливаю режим заливки (светло-серый, т е цвет фона) } FillPoly(4, ara); {заливаю шкаф цветом фона, т е стираю его} for ii:= 1 to 4 do {изменяю координаты шкафа, т е перемещаю его} begin {для этого использую вычисленные ранее сдвиги относительно исходного положения (т е координат ar0)} ara[ii].x := ar0[ii].x + round(sdvigX); ara[ii].y := ar0[ii].y + round(sdvigY); end; until ara[2].x > 620; {ограничиваю перемещение} setcolor(green); {делаю видимым шкаф в последнем положении} setfillstyle(SolidFill,8); FillPoly(4, ara); end; procedure pramoug(var ara: arPo); var alfa: double; ch: char; {эта процедура роняет шкаф поворотом вокруг правой нижней точки на угол Pi/2 стирание осуществляется прорисовкой цветом фона } begin SetWriteMode(NormalPut); alfa:= 0; repeat {используя тригонометрию, вычмсляем координаты вершин шкафа как функции высоты hh, ширины ww и углов: beta (наклон основания) и alfa (угол поворота относительно неподвижного правого-нижнего угла)} ara[2].x := ara[1].x + round(hh*sin(alfa+beta)); ara[2].y := ara[1].y - round(hh*cos(alfa+beta)); ara[3].x := ara[2].x - round(ww*cos(alfa+beta)); ara[3].y := ara[2].y - round(ww*sin(alfa+beta)); ara[4].x := ara[1].x - round(ww*cos(alfa+beta)); ara[4].y := ara[1].y - round(ww*sin(alfa+beta)); setcolor(green); setfillstyle(SolidFill,8); FillPoly(4, ara); {рисую 4-угольник по координатам ara, (заливка SolidFill цветом 8 - темносерый)} delay(3000); {задержка (мсек) - чтобы увидеть шкаф. 3000 - на IBM286, на современных компах много меньше} setcolor(7); {готовлюсь рисовать шкаф цветом фона, т е стирать} setfillstyle(SolidFill,7); FillPoly(4, ara); {стираю текущее положение шкафа} alfa:= alfa + 0.02; {изменяю угол наклона шкафа на 0.02 рад} until alfa > pi/2; {ограничиваю угол поворота - Pi/2 } end; procedure gaubica(x0,y0: integer; beta,vel: double; typ:char); {бросает мячик} var tt: PointType; {здесь храню коорд верхнего левого угла квадрата, описанного относительно мячика (круга), x0,y0 - координаты начального положения цнтра мячика.} RR: integer; {радиус мячика} function dy(xx: integer): integer; {вычисляет (по законам физики) вертикальное перемещение мячика, соответствующее заданному горизонтальному xx. Так как горизонтальная компонента скорости постоянна, то время движения t пропорционально xx (tt:= 0.1*xx), а вертикальное смещение yyy за единицу времени пропррционально tt, например yyy := bb*tt + cc коэффициенты bb,cc подобраны по картинке} const bb= 0.3; cc=-4; var t,yyy: double; begin t:= 0.1*xx; yyy := bb*t + cc; dy:=round(yyy); end; begin RR:= 10; tt.x:= x0-RR; tt.y:= y0-RR; {точка tt- верхний левый угол квадрата, описанного вокруг мячика (круга)} setbkcolor(7); setcolor(green); ImSize := ImageSize(x0-RR, y0-RR, x0+RR, y0+RR); {функция ImageSize вычисляет объем памяти, необходимый для хранения картинки, расположенной внутри этого описанного квадрата } GetMem(P1, ImSize); {указатель P1 будет указывать на этот фрагмент памяти} circle(x0,y0,RR); {рисую окружноость. x0,y0 - центр} setfillstyle(SolidFill,1); {готовлюсь залить круг цветом 1 = синий} FloodFill(x0,y0, green); {заливаю внутренность фигуры начиная с точки x0,y0 и до границы, заданной цветом green} GetImage(x0-RR, y0-RR, x0+RR, y0+RR, P1^); {сохраняю изображение, ограниченное квадратом (x0-RR, y0-RR, x0+RR, y0+RR) в памяти, связанной с указателем P1} while (tt.x < 296) and (tt.y < 500) and (tt.y > RR) do begin PutImage(tt.x, tt.y, P1^, XORPut); {помещаю картинку из памяти (P1) в ту же позицию, но использую тип записи XOR. В результате мячик исчезает} inc(tt.x,2); {увеличиваю координату x на 2} tt.y:= tt.y + dy(tt.x-x0+RR); {вычисляю соответствующую коорд y, используя функцию dy. Аргумент = горизонтальному перемещению относительно исходного положения} case typ of 'N': PutImage(tt.x, tt.y, P1^, NormalPut); 'X': PutImage(tt.x, tt.y, P1^, XORPut); end; {помещаю изображение в точку с новыми координатми. Сейчас оно видимое} delay(3000);{делаю задержкуЁ чтобы глаз успел увидеть мячик, прежде его стирания. Далее в начале цикла мячик стирается} end; PutImage(tt.x, tt.y, P1^, XORPut); end; procedure Osnova(x0: integer); {рисует треугольное основание} var xx: Integer; t1,t2,t3,t4,t5,t6,t7: PointType; alfa,dola:double; ch2: char; begin setcolor(green); t1.x:= x0; t1.y:= 300; t2.x:= x0; t2.y:= 470; t3.x:= 630; t3.y:= 470; {координаты вершин тр-ка} moveto2(t1); lineto2(t2); lineto2(t3); lineto2(t1); setfillstyle(SolidFill,green); {готовлюсь залить зеленым} FloodFill(x0+10,400, green); {заливаю до зеленой границы} dola:= 0.1; {это доля длины гипотенузы. Определяет положение шкафа на склоне } t4.x:= round(t1.x + dola*(t3.x-t1.x))+1; {Это коорд левого нижнего угла шкафа. (отрываю шкаф на 1)} t4.y:= round(t1.y + dola*(t3.y-t1.y))-1; hh:= 100; ww:= 40; {задаю высоту и ширину шкафа} beta:= arctan((t3.y-t1.y)/(t3.x-t1.x)); {вычисляю угол наклона основания} t5.x:= t4.x+round(hh*sin(beta)); {вычисляю коорд остальных углов шкафа, используя тригонометрию} t5.y:= t4.y-round(hh*cos(beta)); t6.x:= t5.x+round(ww*cos(beta)); t6.y:= t5.y+round(ww*sin(beta)); t7.x:= t6.x-round(hh*sin(beta)); t7.y:= t6.y+round(hh*cos(beta)); ara[1]:= t7; ara[2]:= t6; ara[3]:= t5; ara[4]:=t4; { помещаю эти коорд в массив, т к FillPoly использует массив } setfillstyle(SolidFill,8); {готовлю тип заливки - темносерым} FillPoly(4, ara); {рисую залитый 4-угольник} end; procedure clearkey; var cc:char; begin while keypressed do cc:= readkey; end; procedure stopka; {останавливает программу до нажатия любой клавиши} var cc:char; colr: byte; begin clearkey; colr:= getcolor; outtextxy(300,20,'Press any key'); cc:= readkey; setcolor(7); outtextxy(300,20,'Press any key'); setcolor(colr); end; end.