Практическая работа № 34
«Игра»
Цель работы - создать программу – игру. Игрок управляет пушкой зенитки, его боевое задание – справиться с нашествием воздушных шаров. Воздушные шары несут бомбы, которые они сбросят, как только окажутся над пушкой. Необходимо не допустить этого и уничтожить их все на подлете. Снаряды не ограничены, но следующий выстрел можно делать только после того, как выпущенный снаряд поразит цель, упадет на землю или уйдет из зоны видимости. В игре участвуют: · воздушные шары, · знитная пушка, · пушечный снаряд, · бомба, · внешняя среда. Для шаров введен специальный тип TBalloon., в котором содержатся данные о координатах шара, его скорости, состоянии и цвете. Массив переменных Balloons типа TBalloon будет содержать полную информацию обо всех шарах. Индексирование идет, начиная с нуля. Общее число шаров в массиве задается соответствующей константой. Кроме того, к шарам относятся константы, определяющие: · количество шаров, · их возможные цвета, · возможную высоту над землей (всего предполагается четыре уровня), · интервал между шарами и их радиус. Type TBalloon = record x, y, v, Explosion: integer; Color: TColor; End; Const BallCount = 10;
Зенитная пушка описывается переменными: · угол наклона пушки, · ее положение · ее состояние. Пушечный снаряд описывается переменными: · координатами, · текущей скоростью, · начальной скоростью при выстреле. Бомба, сбрасываемая с воздушного шара, имеет: · координату, · скорость. Для расчета положений объектов нужно знать ускорение падения и шаг по времени. В качестве состояния шара и пушки мы используем переменные 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);
В обработчик события формы OnCreate вводится датчик случайных чисел, устанавливается клиентский размер формы (ClientWidth:= 455; ClientHeight:= 315;). Размер клиентской области формы в приложениях определяется автоматически как Width и Height формы минус ширина заголовка и бордюров. procedure TForm1.FormCreate(Sender: TObject);
Пушка танка будет управляться с помощью компонента 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);
В обработчике изменения положения бегунка TrackBar меняем наклон пушки. procedure TForm1.TrackBar1Change(Sender: TObject);
Выстрел происходит, если:
Процедура MoveAll, вызываемая каждый такт таймера, отвечает за то, чтобы все процессы шли своим чередом. Вставьте ее сразу после implementation.
procedure MoveAll;
Процедура пододвигает все шары, которые живы (у них 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; В этом блоке возможная ошибка связана с использованием 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); Процедура DrawExplosion обеспечивает доступ к координатам снаряда. procedure DrawExplosion(x, y, Phase: integer); Кроме того, пушка меняет цвет, когда готов очередной снаряд. В довершение, нужно соединить все написанное воедино. Процедуры рисования объединяются в процедуре, рисующей все поле боя: · небо, · шары, · пушка, · ядро, · бомба. Объединять все вместе обработчик таймера.
procedure DrawBattleField;
|