В этом проекте мы изучаем обработчики событий и некоторые способы работы с графическими объектами.
На форму ставится компонент Image1:TImage. Он используется для загрузки мишени из файла и для
перемещения мишени во время игры. Компонент Timer задает моменты времени, в которые
Image1 ( и мишень) занимает новое положение. Новые координаты (Left,Top) для Image1 вычисляются так:
Image1.Left := random(xmax); Функция Random генерирует целые случайные числа (в диапазоне 0..xmax-1).
Xmax вычисляется из расчета, чтобы окно Image1 не выходило за пределы клиентской части формы. Клиентская часть - то часть формы, на которой можно ставить компоненты, рисовать. Т е исключается заголовок (Caption) и обрамление. Можете посмотреть в инспекторе значения Width и ClientWidth для формы - отличие около 8 пиксел, т е это рамочка. А Height больше чем ClientHeight на 20-40 пиксел.
ymax вычисляется аналогично. Xmax и ymax вычисляются в начале работы проекта, когда появляется форма (см текст процедуры FormShow) и, естественно, перевычисляются при изменении размеров формы (проц. FormResize).
Кстати, в FormResize предотвращаются слишком малые размеры формы:
if ClientWidth < 610 then width:= 615;
Заодно поясним, что ClientWidth и Form1.ClientWidth - это одно и то же, т е внутри описания класса TForm1 имя объекта Form1 можно не указывать.
Однако, вернемся к процедуре FormShow, которая выполняется при старте проекта.
После вычисления xmax, ymax она создает объект BM для работы с картинкой мишени.
BM := TBitmap.Create;
Как видите, для создания объекта известного класса достаточно объявить переменную этого класса
и присвоить ей результат работы процедуры Create(создать) этого класса. Потому что описание класса
хранящееся в Делфи есть как бы рабочие чертежи, по которым можно создать объект.
Далее этот объект BM, используя свой метод (т е процедуру) LoadFromFile загружает картинку из файла на диске.:
BM.LoadFromFile('mishen3.bmp'); //загружаю его картинкой (мишень) из файла BM.Transparent:= true; // объект прозрачный BM.TransparentMode:= tmAuto; //прозрачный цвет взять в пикселе [0,0]Image1.Canvas.Draw(50,50,BM); //рисую на поверхности Canvas картинку BM, т е мишень
Рассмотрим работу компонента Timer1. Нужно поставить его на форму с палитры компонентов.
При работе проекта: если свойство Timer1.Enabled = true, то объект активен. Это проявляется в том, что каждые Timer1.Interval (миллисекунд) выполняется процедура - обработчик события onTimer. В нашем проекте это Timer1Timer. Как уже было сказано, вычисляются и устанавливаются новые координаты объекта Image1, в результате чего мишень появляется в новом месте. Затем запускается процедура TrackBar1Change - обработчик события: изменилось состояние (настройка) объекта TrackBar1. Ниже займемся этим TrackBar1, а пока отметим, что имеется кнопка (Вкл/выкл) обработчик щелчка которой (btnTimerClick) выключает и включает таймер и, следовательно прыжки мишени - при помощи оператора:
Timer1.Enabled := not Timer1.Enabled;
Объект TrackBar1: TTrackBar; - используется в качестве графического регулятора какой-либо величины. В нашем проекте - TrackBar1 регулирует время, в течение которого мишень неподвижна (потом она прыгает в другое место), более конкретно - регулирует Timer1.Interval. Если изменить положение движка регулятора TrackBar1, то сработает процедура TrackBar1Change, а в ней записаны следующие операторы:
procedure TForm1.TrackBar1Change(Sender: TObject); begin Timer1.Interval := Round(5000/TrackBar1.Position); // Timer1.Interval вычисляется в зависимости от TrackBar1.Position sb1.SimpleText := 'Уровень = '+ IntToStr(TrackBar1.Position) + ' (пауза = ' + floattostr(Timer1.Interval/1000) + ' сек )'; // выводится сообщение в sb1 (TStatusBar) end;sb1 - это объект класса TStatusBar - полоска в нижней части формы, куда обычно записывают сообщения о состоянии проекта.
Игрок должен поражать мишень. Для этого он наводит мышкурсор (крест) на центр мишени и нажимает левую мышкнопку. Если курсор находится в окне объекта Image1 (об этом свидетельствует форма курсора - крест), то срабатывает процедура-обработчик Image1MouseDown. Вот ее текст:
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); //Происходит при нажатии мышкнопки // в параметрах передаются координаты мышкурсора, нажатая мышкнопка, // нажатость спецклавиш (Alt, Shift, Ctrl ) var ocki: double; ball,ii,jj: Integer; bus: String; begin beep; // звук выстрела. inc(count); // счетчик выстрелов увеличим на 1 bus:= ' '; // чтобы двигалось число в Caption ocki:= sqrt(sqr(x-121) + sqr(y-121)); //расстояние от центра мишени. if ocki <= 7 then ball:=10 else ball:= trunc(-9/63*ocki+11); // вычислим : сколько очков дал выстрел. if ball < 0 then ball:=0; if count <= 10 then begin inc(suma,ball); // суммируем (накапливаем) баллы выстрелов. for ii:= 1 to 20 do // чтобы двигалась оценка выстрела в Caption begin delete(bus,1,1); // удаляю из строки bus 1-й символ sleep(20); // пауза 20 миллисекунд (чтобы замедлить процесс) Caption := bus + IntToStr(ball); // в Caption помещаю эту стриженую строку пробелов, // а справа цепляю оценку выстрела. (длина строки меняется) end; if count = 10 then // т е конец игры begin Caption := ' ' + IntToStr(suma) + ' очков (10 выстрелов)'; Timer1.Enabled := false; // отключаю работу таймера. end; end; end;В ней достаточно комментариев. Дополнительно отмечу следующее:
Рисование фона формы выполено за счет:
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, ComCtrls; type TForm1 = class(TForm) Timer1: TTimer; btnTimer: TButton; Image1: TImage; TrackBar1: TTrackBar; btnRepeat: TButton; sb1: TStatusBar; Label1: TLabel; procedure btnTimerClick(Sender: TObject); procedure Timer1Timer(Sender: TObject); procedure FormShow(Sender: TObject); procedure TrackBar1Change(Sender: TObject); procedure Image1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure btnRepeatClick(Sender: TObject); procedure FormResize(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormPaint(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} var BM,BM_fon: TBitmap; xmax, ymax: Integer; count: integer = 0; suma: integer =0; procedure TForm1.btnTimerClick(Sender: TObject); begin Timer1.Enabled := not Timer1.Enabled; end; procedure TForm1.Timer1Timer(Sender: TObject); begin {Перемещает мишень, изменяя координаты верхне-левого угла (Left, Top) объекта Image1} Image1.Left := random(xmax); Image1.Top := random(ymax); TrackBar1Change(Sender); //Запускает процедуру TrackBar1Change end; procedure TForm1.FormShow(Sender: TObject); begin xmax := ClientWidth - 280; //верхний предел изменения координаты Image1.Left // (см Timer1Timer) ymax := ClientHeight - 320; //верхний предел изменения координаты Image1.Top BM := TBitmap.Create; //создаю объект BM класса TBitmap. BM.LoadFromFile('mishen3.bmp'); //загружаю его картинкой (мишень) из файла BM.Transparent:= true; // объект прозрачный BM.TransparentMode:= tmAuto; //прозрачный цвет взять в пикселе [0,0] Image1.Canvas.Draw(50,50,BM); //рисую на поверхности Canvas картинку BM end; procedure TForm1.TrackBar1Change(Sender: TObject); begin Timer1.Interval := Round(5000/TrackBar1.Position); // Timer1.Interval вычисляется в зависимости от TrackBar1.Position sb1.SimpleText := 'Уровень = '+ IntToStr(TrackBar1.Position) + ' (пауза = ' + floattostr(Timer1.Interval/1000) + ' сек )'; // выводится сообщение в sb1 (TStatusBar) end; procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); //Происходит при нажатии мышкнопки // в параметрах передаются координаты мышкурсора, нажатая мышкнопка, // нажатость спецклавиш (Alt, Shift, Ctrl ) var ocki: double; ball,ii,jj: Integer; bus: String; begin beep; // звук выстрела. inc(count); // счетчик выстрелов увеличим на 1 bus:= ' '; // чтобы двигалось число в Caption ocki:= sqrt(sqr(x-121) + sqr(y-121)); //расстояние от центра мишени. if ocki <= 7 then ball:=10 else ball:= trunc(-9/63*ocki+11); // вычислим : сколько очков дал выстрел. if ball < 0 then ball:=0; if count <= 10 then begin inc(suma,ball); // суммируем (накапливаем) баллы выстрелов. for ii:= 1 to 20 do // чтобы двигалась оценка выстрела в Caption begin delete(bus,1,1); // удаляю из строки bus 1-й символ sleep(20); // пауза 20 миллисекунд (чтобы замедлить процесс) Caption := bus + IntToStr(ball); // в Caption помещаю эту стриженую строку пробелов, // а справа цепляю оценку выстрела. (длина строки меняется) end; if count = 10 then // т е конец игры begin Caption := ' ' + IntToStr(suma) + ' очков (10 выстрелов)'; Timer1.Enabled := false; // отключаю работу таймера. end; end; end; procedure TForm1.btnRepeatClick(Sender: TObject); begin // нажатие кнопки "Снова" count := 0; // сбрасываю счетчик suma:=0; // сбрасываю счетчик суммы очков Timer1.Enabled := true; // включаю таймер Caption := 'Начало'; end; procedure TForm1.FormResize(Sender: TObject); begin // срабатывает при изменениии размеров формы if ClientWidth < 610 then width:= 615; //ограничиваю размеры снизу. if ClientHeight < 450 then height := 500; xmax := ClientWidth - 280; // пересчитываю xmax ymax ymax := ClientHeight - 320; end; procedure TForm1.FormCreate(Sender: TObject); begin // срабатывает при запуске приложения, когда создается форма. Bm_fon := TBitMap.create; // создаю объект TBitMap для фона. try // защита от ошибок при работе с файлами. if fileexists ('.\parket2.bmp') then // если существует файл parket2.bmp begin BM_fon.LoadFromFile('.\parket2.bmp'); // загружаю рисунок из файла. Canvas.Brush.BitMap :=BM_fon; // эту картинку присваиваю холсту формы. end except end; end; procedure TForm1.FormDestroy(Sender: TObject); begin // при выходе из проекта освобождается память, выделенная // объектам. Canvas.Brush.Bitmap := nil; BM_fon.Free; BM.Free; end; procedure TForm1.FormPaint(Sender: TObject); begin Canvas.FillRect(ClientRect); // рисую прямоугольник с фоном, причем в качестве фона // ранее была установлена картинка с фоном. end; end.