Теперь нам необходимо организовать уничтожение той полоски, по которой пользователь щелкнул кнопкой мыши, и при этом уничтожаемая полоска должна находится поверх остальных.
Как это сделать?
Щелкнем по пустому месту формы, перейдем на вкладку Events инспектора, и создадим приведенный ниже обработчик события OnMouseDown:
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var SendObj, ListObj: TShape; i, j: integer; R, SendRect, ListRect: TRect;
begin
if not(Sender is TShape) then Exit; //Очень важная строка!
SendObj:=Sender as TShape;
SendRect:=SendObj.BoundsRect;
with List do begin
i:=-1;
repeat
inc(i);
ListObj:=Items[i];
until ListObj=SendObj;
for j:=i+1 to Count-1 do begin
ListObj:=Items[j];
ListRect:=ListObj.BoundsRect;
IntersectRect(R, SendRect, ListRect);
if not IsRectEmpty(R) then exit;
end;
SendObj.Free;
Delete(i);
if Count=0 then begin
Timer1.Enabled:=False;
ShowMessage(' УРА! ПОБЕДА! ');
end;
end;
end;
Кроме того, необходимо будет в конец созданной нами ранее процедуры Timer1Timer добавить строки, выделенные жирным шрифтом:
…………………………….
// определяем обработчик нажатия кнопки мыши
AObj.OnMouseDown:=Form1.OnMouseDown;
// добавляем созданную фигуру в список
List.Add(AObj);
Timer1.Tag:=Timer1.Tag+1;
end;
Запустите проект на выполнение, и Вы сможете уже поиграть в созданную Вами игру!
Разбор полетов
Однако теперь, конечно, необходимо разобраться в тексте созданной нами программы.
Процедура Form1.OnMouseDown вызывается той полоской, над которой находится курсор мыши в момент нажатия кнопки.
Мы щелкнули по пустому месту формы, и начал работать обработчик события OnMouseDown.
Если эта полоска не перекрыта ни одной другой полоской, то ее можно удалить. Несмотря на простоту идеи, ее реализация требует решения нескольких проблем.
Во-первых, как метод OnMouseDown узнает, какая полоска его вызвала? Его первым параметром является Sender -указатель на объект, вызвавший метод. Однако тип указателя есть TObject, поэтому сначала его нужно привести к типу TShape. Для этого в Delphi предусмотрен оператор as. Пусть, например, переменная SendObject объявлена как TShape. Тогда присваивание SendObj:=Sender as TShape; устанавливает указатель SendObj на объект типа TShape, над которым произошло отслеживаемое событие.
|
Во-вторых, требуется "достать" из списка List только те полоски, которые могли перекрыть исходную. Такую возможность имеют полоски, которые были включены список после исходной. Для поиска исходной полоски в списке используется цикл:
repeat
inc(i);
ListObj:=Items[i];
until ListObj=SendObj;
Здесь переменная ListObj также имеет тип TShape.
В-третьих, необходимо проверить, пересекаются ли полоски из второй части списка с исходной на самом деле. Поскольку размеры и положение полосок нам известны, то задача сводится к проверке нескольких неравенств. Однако намного проще воспользоваться готовыми функциями, предназначенными для работы с типом TRect — прямоугольной областью экрана.
Тип TRect представляет собой запись с вариантами: прямоугольник может задаваться четырьмя целыми числами — Left, Top, Right, Bottom — или двумя записями типа TPoint:
type
TPoint = record
X: Longint; У: Longint;
end;
TRect = record
case integer of
0: (Left, Top, Right, Bottom:Integer);
1: (TopLeft, BottomRight: TPoint);
end;
Область, занимаемая визуальным компонентом на экране, хранится в свойстве BoundsRect в виде записи типа TRect. Пересечение прямоугольников выполняет функция IntersectRect, объединение — функция UnionRect, проверку " прямоугольник пуст " — функция IsRectEmpty, проверку на совпадение — функция EqualRect и т.д. Использование этих функций делает программу более короткой и наглядной.
|
Обратим также внимание на «очень важную строку» в начале процедуры OnMouseDown:
if not(Sender is TShape) then Exit; //Очень важная строка!
Попробуйте закомментировать эту строку, запустите проект и щелкните по свободному от панели месту окна.
На экране появится приведенное ниже страшное сообщение:
Что произошло?
Да попросту в данном случае «посылателем» (параметр Sender) является уже не объект TShape, а сама форма. И в дальнейших операторах мы начинаем работать с формой, как с объектом TShape, что и приводит к ошибке (исключительной ситуации).
Кроме того, в программе мы использовали процедуру ShowMessage для вывода сообщения на экран. Сообщение выводится в отдельное окно, которое является модальным, то есть до закрытия окна не позволяет пользователю переключиться в другое приложение. Этим свойством обладают все диалоговые окна.
На рисунке показан внешний вид окна.
Заголовок содержит имя файла проекта, в клиентской части располагаются выводимый текст и кнопка " ОК ".
В целях повышения сложности игры для первых 5-10 полосок установите малый интервал времени срабатывания таймера, а только потом увеличьте его.
Содержание отчета:
5. Наименование, тема, цель работы.
6. Содержание задания 3.
7. Таблица идентификаторов к игре «Полоски».
8. Краткий алгоритм решения.
9. Результат выполнения и выводы.
Контрольные вопросы:
7. Что такое конструктор и деструктор?
8. Описание конструктора.
9. Описание деструктора.
10. Как обратиться к элементу с помощью конструктора?
11. Алгоритмы работы конструктора и деструктора.
12. Метод Free. Дайте пояснение ключевых слов – inherited, public, virtual, override.
13. Какие объекты вы использовали в программе? Дайте описание полей, свойств и методов.