КАТЕГОРИИ: Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748) |
WithForm1.Image1.Canvasdo begin
Try Begin Else begin Begin Try Try Begin Const Type Begin Begin
Caption:= ‘Выделена клетка (‘ + IntToStr(Acol) + ‘:’ + IntToStr(Arow) + ‘) ‘; end;
В качестве параметров обработчик получает (кроме Sender) номер столбца, номер строки и переменную CanSelect, которую можно изменить внутри обработчика, так как она передается как var.
Рис. 62.
Можно, например, запретить выделение ячеек третьего столбца. Для этого вставьте в этот обработчик еще строчку: CanSelect:= (Acol <> 3); В этом случае CanSelect будет равен false, если Acol = 3. 7. Настроить сетку в зависимости от значения констант, которые надо объявить в interface. Теперь при запуске программы сетка имеет размер, заданный в константе, и выглядит значительно аккуратнее. Если изменить значение константы, то при запуске и размер сетки будет соответствующим. 8. Установить размер сетки согласно значению констант Num и сSize, объявленных в interface: const Num = 4;cSize = 30; …… procedure Tform1.FormCreate(Sender: Tobject); begin
MyGrid.DefaultColWidth:= cSize; MyGrid.DefaultRowHeight:= cSize; MyGrid.ColCount:= Num; MyGrid.RowCount:= Num; MyGrid.Width:= Num * (cSize + 1) + 3; MyGrid.Height:= Num * (cSize + 1) + 3; MyGrid.Font.Size:= cSize div 2; end;
Рис. 63.
В приведенном участке кода изменяются ширина и высота сетки, установленные по умолчанию, а также количество строк и столбцов сетки. Добавление единицы к ширине каждой ячейки связано с наличием линий между ячейками, а добавление тройки ко всей сумме – наличием бордюра вокруг сетки. В последней строчке устанавливается соответствующий величине клетки размер шрифта.
9. Для расчета суммы по столбцам и строкам вводимых чисел написать собственную процедуру и две функции.
Функции будут рассчитывать сумму в строке и столбце, получая их номер в качестве параметра. Процедура будет в цикле вызывать эти функции и соответствующим образом заполнять клетки. Теперь надо создать обработчик для нажатия на саму форму и описать в нем вызов расчета. Собственная процедура стоит в коде раньше, чем обработчик, из которого она вызывается. Когда описывается собственная процедура, нужно обращаться к компонентам через форму.
При запуске программы требуется ввести числа в сетку и кликнуть на саму форму.
Function ColSum(n: integer): integer; var i: integer; begin
Result:= 0; for I:= 1 to Num – 1 do Result:= Result + StrToInt (Form1.MyGrid.Cells[n, i]); end;
function RowSum(n: integer): integer; var
i: integer; begin
Result:= 0; for I:= 1 to Num – 1 do Result:= Result + StrToInt(Form1.MyGrid.Cells[I, n]); end;
procedure Calculate; var i: integer; for I:= 1 to Num – 1 do begin Form1.MyGrid.Cells[I, 0]:= IntToStr(ColSum(i)); Form1.MyGrid.Cells[0, i]:= IntToStr(RowSum(i)); end; end; В данной программе используется свойство Cells, компонента сетки. Это свойство имеет тип двумерного массива строк. Счет в этом массиве начинается с нуля. Фиксированные (серые) клетки, с точки зрения индексирования массива, ничем не отличаются от прочих. В нашем случае фиксированы первая строка и первый столбец (в массиве они имеют соответствующие нулевые координаты). Поэтому при расчете суммы проходят от 1 (а не от 0) до Num – 1 (при индексировании с нуля последний столбец/строка имеют, понятно, номер Num – 1).
Однако, если произойдет ввод какой-нибудь буквы, сразу возникнет исключительная ситуация. Она, очевидно, возникает из-за невозможности перевода буквы в число в функции StrToInt. Если нежелательно, чтобы при возникновении исключительной ситуации программа в Delphi переходила в режим отладки, можно отключить флажок Menu => Tools => Debugger Options => Language Exceptions => Stop on Delphi Exceptions. Теперь программа будет выполняться так, как если бы она выполнялась из-под Windows. Теперь каждый раз, когда вводится нечисловой символ, программа не останавливается, а только появляется стандартное окно Windows с сообщением об ошибке. С помощью обработки исключений можно избежать появления этого окна. Для этого надо добавить в функцию конструкцию try..except. Таким образом «опасная» команда (или целый блок) помещается внутрь конструкции try..except..end или try..finally..end: function StrToVal(s: string): integer; begin if S = ‘’ then Result:= 0 else try Result:= StrToInt(s); except Result:= 0; Form1.Caption:= ‘Вводить надо числа!’; end; end; Если возникает исключительная ситуация, т.е. введено нечисловое значение, считается, что введен ноль, а также выводится сообщение об этом пользователю. Еще нужно добавить вывод информации, что все в порядке. А также удалить код внутри обработчика Click формы. В результате, если введено неправильное значение, то окно ошибки не появляется, а в Caption формы выводится напоминание. Практическая работа № 18 «Игра»
Цель работы -создать программу–игру.Игрок управляет пушкой зенитки,егобоевое задание – справиться с нашествием воздушных шаров. Воздушные шары несут бомбы, которые они сбросят, как только окажутся над пушкой. Необходимо не допустить этого и уничтожить их все на подлете. Снаряды не ограничены, но следующий выстрел можно делать только после того, как выпущенный снаряд поразит цель, упадет на землю или уйдет из зоны видимости.
В игре участвуют: • воздушные шары, • знитная пушка, • пушечный снаряд, • бомба, • внешняя среда. Для шаров введен специальный тип TBalloon., в котором содержатся данные о координатах шара, его скорости, состоянии и цвете. Массив переменных Balloons типа TBalloon будет содержать полную информацию обо всех шарах. Индексирование идет, начиная с нуля. Общее число шаров в массиве задается соответствующей константой.
Кроме того, к шарам относятся константы, определяющие: • количество шаров, • их возможные цвета, • возможную высоту над землей (всего предполагается четыре уровня), • интервал между шарами и их радиус. TBalloon = record x, y, v, Explosion: integer; Color: TColor; end;
BallCount = 10; BallColors: array [0.. 9] of TColor = (clRed, clGreen, clNavy, clMaroon, clPurple, clOlive, clLime, clYellow, clFuchsia, clSilver); BallAltitude: array [0.. 3] of integer = (240, 160, 200, 120); BallInterval = 40; BallRadius = 15; V = 150; g = -9.8 * 3; dt = 0.1; var Form1: TForm1; x, y, Vx, Vy, BombY, BombV: double; Angle, GunPosition, GunExplosion: integer;
Balloons: array [0.. BallCount - 1] of TBalloon;
Зенитная пушка описывается переменными:
• угол наклона пушки, • ее положение • ее состояние. Пушечный снаряд описывается переменными: • координатами, • текущей скоростью, • начальной скоростью при выстреле. Бомба, сбрасываемая с воздушного шара, имеет: • координату, • скорость. Для расчета положений объектов нужно знать ускорение падения и шаг по времени.
В качестве состояния шара и пушки мы используем переменные TBalloon. В определенный момент времени каждый элемент должен находиться в каком-то состоянии, определяющем то, как элемент выглядит на экране. Шары и пушка могут быть боеспособными, взрывающимися и уничтоженными. Если Explosion = 0 - шар боеспособен, если Explosion = 10, то он уничтожен, а значения от 1 до 9 обозначают фазы взрыва. Чтобы инициировать взрыв боеспособного шара, нужно присвоить Explosion:= 1. То же самое касается и пушки. Состояние, в котором скорость снаряда равна нулю: Vx = 0 и Vy = 0. В этом случае считают, что можно сделать новый выстрел. Пока же снаряд летит (то есть скорость его не нулевая), новый выстрел сделать нельзя.
Бомба будет сбрасываться шаром, когда он поравняется с пушкой. Таким образом, X - координата бомбы всегда равна X - координате пушки. Следовательно, необходимо хранить только Y-координату бомбы. Бомба не сброшена, если BombY = 1000. Если BombY < 1000, то она считается сброшенной и начинает падать. Поместите на форму TrackBar, Button, Image и Timer и настройте их параметры. Timer: Interval = 100; Image: Width = 440, Heigth = 260; Button: Caption = ‘Новая игра’; TrackBar: Min = -90, Max = 90, Frequency = 10. Image - сражение в реальном времени. Timer - реальное время. Button - запуск новой игры. TrackBar - управление зенитной пушкой. В обработчике нажатия на кнопку "Новая игра" необходимо обнулить параметры, расставить пушку и шары. Для каждого шара устанавливается случайное направление движения: v = 1 или –1. В зависимости от направления, определяется высота, на которой находится шар (на одном и том же уровне шары летят в одну сторону). По x-координате шары расставляются так, чтобы они шли с примерно равным интервалом в направлении пушки из-за границ экрана.
Каждый шар Balloons[i], элемент массива Balloons, имеет тип записи TBalloon, и для того, чтобы получить доступ к его элементам, нужно писать: Balloons[i].Explosion:= 0, Color:= BallColors[random(10)] и т.д. Конструкция with Balloons[i] do begin.. end позволяет избежать повторения.
procedure TForm1.Button1Click(Sender: TObject); var
i: integer; begin Caption:= 'Нашествие';
TrackBar1.Position:= 0; GunPosition:= 170 + random(100); Vx:= 0; Vy:= 0; GunExplosion:= 0;
for i:= 0 to BallCount – 1 do with Balloons[i] do if random < 0.5 then v:= –1 else v:= 1; y:= BallAltitude[1 + v + random(2)] + random(10); x:= 220 - v * (220 + i * BallInterval + random(20)); Explosion:= 0; Color:= BallColors[random(10)]; end;
BombY:= 1000; end;
В обработчик события формы OnCreate вводится датчик случайных чисел, устанавливается клиентский размер формы (ClientWidth:= 455; ClientHeight:= 315;). Размер клиентской области формы в приложениях определяется автоматически как Width и Height формы минус ширина заголовка и бордюров.
procedure TForm1.FormCreate(Sender: TObject); begin
Randomize; ClientWidth:= 455; ClientHeight:= 315; Button1.Click; end;
Пушка танка будет управляться с помощью компонента TrackBar. Выстрел производится нажатием пробела на клавиатуре. При этом фокус ввода должен быть у TrackBar. В обработчике OnKeyPress реализуется выстрел, задавая начальную скорость и положение снаряду, а также издавая звук выстрела.
Процедура, проигрывающая этот звук из wav-файла, описана в модуле, который необходимо подключить в разделе uses. В модуле MMSystem имеется функция PlaySound, с помощью которой можно проигрывать файлы wav. Для асинхронного воспроизведения (приложение не приостанавливает работу на время воспроизведения, а проигрывает его в фоновом режиме) вызов выглядит так:
PlaySound(PChar('имяфайла.wav'), 0, SND_ASYNC). В стандартных звуках Microsoft Office можно подобрать звуки для выстрела и взрыва.
В зависимости от версии программы, эти файлы хранятся в C:\Windows\Media\ Microsoft Office 2000, C:\Program Files\Microsoft Office\Office\Media или в какой-то подобной папке.
Найдите звуки для выстрела (условно назовем GunShot.wav) и взрыва (условно назовем Explode.wav) и скопируйте их в папку, в которой сохранен проект.
procedure TForm1.TrackBar1KeyPress(Sender: TObject; var Key: Char); var
i: integer; begin
if (Key = ' ') and (Vx = 0) and (Vy = 0) and (GunExplosion = 0) then begin PlaySound(PChar('GunShot.wav'), 0, SND_ASYNC); except end; Vx:= V * Sin(Angle * pi / 180); Vy:= V * Cos(Angle * pi / 180);
x:= GunPosition + 15 * Sin(Angle * pi / 180); y:= 20 + 15 * Cos(Angle * pi / 180); end;
if (Key = 'Q') then begin
PlaySound(PChar('Explode.wav'), 0, SND_ASYNC); except end; for i:= 0 to BallCount - 1 do if Balloons[i].Explosion = 0 then Balloons[i].Explosion:= 1; Caption:= 'Уничтожен';
end;
end;
В обработчике изменения положения бегунка TrackBar меняем наклон пушки.
procedure TForm1.TrackBar1Change(Sender: TObject); begin
Angle:= TrackBar1.Position; end;
Выстрел происходит, если:
1) нажат пробел;
2) снаряд готов (Vx = 0) и (Vy = 0); 3) пушка боеспособна (GunExploion = 0).
Процедура MoveAll, вызываемая каждый такт таймера, отвечает за то, чтобы все процессы шли своим чередом. Вставьте ее сразу после implementation.
procedure MoveAll; var i: integer; for i:= 0 to BallCount - 1 do with Balloons[i] do if Explosion = 0 then x:= x + v if Explosion < 10 then inc(Explosion); end; if (Vx <> 0) or (Vy <> 0) then begin x:= x + Vx * dt; y:= y + Vy * dt; Vy:= Vy + g * dt; end; if BombY < 1000 then begin BombY:= BombY + BombV * dt; BombV:= BombV + g * dt end; if (GunExplosion > 0) and (GunExplosion < 10) then inc(GunExplosion); end; Процедура пододвигает все шары, которые живы (у них Explosion = 0), в направлении вектора их скорости. Остальные шары, если они находятся в фазе взрыва (0 < Explosion < 10), переходят в следующую фазу.
Если снаряд выпущен (Vx <> 0) или (Vy <> 0), то его координата и скорость изменяются согласно законам природы. Если бомба сброшена (BombY < 1000), то она также подчиняется закону всемирного тяготения. Если танк находится в фазе взрыва (0 < GunExplosion < 10), он переходит в следующую фазу. Ошибки, возникающие в обработчике таймера или процедурах, которые вызываются из обработчика, не останавливают таймер и, значит, через секунду возникают опять. Чтобы их остановить, приходится использовать Ctrl-Alt-Del… В этой процедуре мы работаем с массивом. Одной из самых частых ошибок, которые не так-то просто найти, является выход за границы массива. Для предотвращения подобных ситуаций включите проверку на выход из диапазона допустимых значений (Project => Options => Compiler => Runtime errors => Range checking), которая по умолчанию отключена.
Перемещения сами по себе могли бы продолжаться бесконечно. Необходимо проконтролировать: • не попал ли снаряд в шар, следовательно, взорвать его; • не уничтожены ли все шары, следовательно, выдать надпись о победе; • не поравнялся ли шар с пушкой, следовательно, сбросить бомбу; • не упал ли снаряд и не вышел ли он из зоны контроля, следовательно, перезарядить пушку; • не упала ли бомба на пушку, следовательно, закончить игру. Для контроля за передвижениями предусмотрена процедура:
procedure CheckCollisions; var
i, j: integer; HappyEnd: boolean; begin for i:= 0 to BallCount - 1 do with Balloons[i] do if (Explosion = 0) then begin if (sqr(x - Unit1.x) + sqr(y - Unit1.y) < sqr(BallRadius)) then begin PlaySound(PChar('Explode.wav'), 0, SND_ASYNC); except end; Explosion:= 1; Unit1.x:= 0; Unit1.y:= 0; Unit1.Vx:= 0; Unit1.Vy:= 0;
HappyEnd:= (GunExplosion = 0); for j:= 0 to BallCount - 1 do HappyEnd:= HappyEnd and (Balloons[j].Explosion > 0); if HappyEnd then Form1.Caption:= 'Победа!'; end; if (x = GunPosition) and (BombY = 1000) and (GunExplosion = 0) then begin
BombY:= y - BallRadius - 5; BombV:= 0; end;
end; end;
if (y < 0) or (x < 0) or (x > 440) then begin x:= 0; y:= 0; Vx:= 0; Vy:= 0;
end; if BombY < 10 then begin BombY:= 1000; GunExplosion:= 1; try PlaySound(PChar('Explode.wav'), 0, SND_ASYNC); except end; Form1.Caption:= 'Увы...'; end; end; В этом блоке возможная ошибка связана с использованием with … do begin … end. X-координата снаряда хранится в глобальной переменной x, X-координата
воздушного шара – в переменной Balloons[i].x. Однако когда пишут код внутри with Balloons[i] do begin … en d,то именно к координате шара обращаются просто как кx.Еслинужно добраться до глобальной переменной, то теперь уже перед ней нужно ставить уточнение: Unit1.x, где Unit1 – имя модуля. Рисование отдельных элементов баталии также разумно поместить в специализированные для этого процедуры.
Художественные образы шаров, пушки и взрыва передаются с помощью процедур:
procedure DrawBalloon(x, y: integer; Color: TColor); begin
Pen.Color:= clBlack; Brush.Color:= Color;
Ellipse(x - BallRadius, y - BallRadius, x + BallRadius, y + BallRadius); Pen.Color:= clWhite; Brush.Color:= clWhite; Ellipse(x - BallRadius div 2 - 3, y - BallRadius div 2 - 3, x - BallRadius div 2 + 3, y - BallRadius div 2 + 3); Pen.Color:= clBlack; Brush.Color:= clOlive; Rectangle(x - 5, y + BallRadius + 5, x + 5, y + BallRadius + 10); MoveTo(x - 5, y + BallRadius + 5); LineTo(x - BallRadius, y); MoveTo(x, y + BallRadius + 5); LineTo(x, y);
MoveTo(x + 5, y + BallRadius + 5); LineTo(x + BallRadius, y);
end; end;
procedure DrawGun; begin
Дата добавления: 2017-02-01; Просмотров: 91; Нарушение авторских прав?; Мы поможем в написании вашей работы! |