Программ-игра «Морской бой», с использованием анимированных графических объектов и возможностью управлять их движением с помощью клавиатуры
Работа из раздела: «
Программирование и комп-ры»
Домашняя работа
по программированию
за второй семестр
Игра «Морской Бой»
Выполнил: Макаров В. А.
группа: С-26
Игра «Морской Бой»
Требуется:
Разработать программу-игру «Морской бой», с использованием анимированных
графических объектов и возможностью управлять их движением с помощью
клавиатуры.
Эскиз:
[pic]
Аномалии:
|Аномалия |Действие программы |
|1) Произошла ошибка инициализации|Вывод сообщения: |
|графики |«InitGraph ERROR!» |
|2) При игре было допущено более |Вывод сообщения |
|пяти промахов. Проигрыш. |«GAME OVER» |
Внешняя спецификация:
Вход:
|Vipolnil: Makarov Vladimir |
|Group: C-26 |
| |
| |
| |
|Press to start play game! |
| |
| |
| |
Выход при проигрыше:
| |
| |
| |
| |
|GAME OVER |
| |
| |
| |
Метод:
Описание:
Во время игры на экране изображена водная поверхность и две скалы по
бокам. Время от времени из-за скал выплывают различные корабли, которые
движутся вдоль горизонта к противоположенной скале. Существует три типа
кораблей: маленький, средний и большой. Тип корабля всегда выбирается
случайным образом. Скорость каждого корабля зависит от размера самого
корабля: маленький самый быстрый, остальные соответственно обладают более
низкой скоростью. Цель игрока состоит в том, чтобы с помощью пушки и
прицела подбить как можно большое количество кораблей и не промахиваться.
Количество подбитых кораблей (scope) показывается в нижнем левом углу
экрана. Игрок должен нацеливать пушку влево или вправо и стрелять по
возможности на опережение, так как снаряд вылетающий из пушки обладает
относительно малой скоростью. В случае промаха игрока, корабль
разворачивается и уплывает в обратную сторону. Если игрок совершил более
пяти промахов, то он проигрывает и выходит из игры.
Прицеливание осуществляется с помощью стрелок (вправо и влево) на
клавиатуре, пробел – стрельба и escape – выход.
Основной метод:
В основе работы программы лежит главный зацикленный цикл, выход из
которого осуществляется только при выходе или при проигрыше. В цикле
выполняются действия, зависящие от состояния флагов, так как каждому
событию в программе соответствует свой флаг. Так же в этом цикле
отслеживаются нажатия определённых клавиш. Цикл прокручивается с, заранее
определённой и постоянной, временной задержкой.
Когда какой-нибудь флаг принимает истинное значение, в цикле
проделывается соответствующее ему действие, после чего флаг сразу
сбрасывается в положение ложь.
Рисование всех двигающихся объектов производится для удобства в отдельных
процедурах. В качестве параметров туда передаётся координата по оси или x
или y, так же туда передаётся флаг, указывающий на то – рисовать объект или
стирать. Под стиранием объекта понимается его рисование цветом фона.
Движение всех графических объектов в программе осуществляется стандартным
методом: сначала рисуется объект, а после временной задержки он рисуется на
том же месте цветом фона (стирается) и рисуется в новом месте.
Скорости всех двигающихся в программе объектов различны:
Vснаряда > Vкорабля №1 > Vкорабля №2 > Vкорабля №3
Временная задержка во всей программе постоянная и используется один раз
за цикл. Если один проход цикла назвать тактом, то разность скоростей
объектов реализована за счёт того, что каждый объект перемещается на
единицу расстояния не за каждый такт, а за каждый n-ный такт, а n
определено для каждого объекта по-разному. Чем меньше n, тем быстрее
скорость. В данной программе все скорости постоянны.
Алгоритм:
Procedure target (ix: integer; bb: boolean)
|Входные данные: ix:цел bb:лог |
|Внутренние постоянные переменные: iy=200 |
| |
|начало |
|если bb то {Отображение} |
|Установить цвет(green) |
|Установить тип заливки(SolidFill,green) |
|Нарисовать закрашенный эллипс(ix,430,26,100) |
|Выбрать цвет(lightgreen) |
|Нарисовать линию(ix-10,iy,ix+10,iy) |
|Нарисовать линию(ix,iy-10,ix,iy+10) |
|иначе {Стирание} |
|Установить тип заливки(SolidFill,blue) |
|Установить цвет(blue) |
|Нарисовать закрашенный эллипс( (ix,430,26,100) |
|Установить цвет(blue) |
|Нарисовать линию(ix-10,iy,ix+10,iy) |
|Нарисовать линию(ix,iy-10,ix,iy+10) |
|всё |
|конец |
Часть 2: Поиск в тексте единиц и вставка после них нулей
|Входные данные: var st:мас:стр r:цел var one:лог |
|Выходные данные: rez:масс:стр iz:цел |
|Внутренние переменные: k,l:цел |
| |
|начало |
|one:=ложь |
|цикл для k:=1 до r делать |
|l:=1 |
|цикл пока l<=длина(st[k]) делать |
|если st[k][l]='1' то |
|insert('0',st[k],l+1) {Вставить после нуля единицу} |
|one:=истина {Значит, в тексте есть единицы} |
|всё |
|inc(l) {l:=l+1} |
|кцикл |
|кцикл |
|всё |
Вспомогательная функция: Определяет, является ли символ цифрой
|Входные данные: с:сим |
|Выходные данные: лог |
|Внутренние переменные: e:цел fl:лог |
| |
|начало |
|fl:=ложь |
|d:='0123456789' {все цифровые символы} |
|цикл для e:=1 до 10 делать {перебор всех символов цифр} |
|если c=d[e] то fl:=истина |
|кцикл |
|{Ели символ является цифрой, то функция возвратит истину, |
|иначе возвратит ложь} |
|digs:=fl {функция возвращает значение} |
|всё |
Исходный код всей программы:
|{Домашнее задание на тему 'графика'} |
|{Выполнил студент: Макаров Владимир, группа С-26} |
|{Игра 'Морской Бой'} |
|program SeaWar; |
|uses Graph,crt; |
|var |
|GraphDriver:integer; |
|GraphMode:integer; |
|ErrorCode:integer; {Переменные для инициализации графики} |
|s_score:string; |
| |
|{Все переменные, используемые в программе} |
|x :integer; |
|y :integer; {Переменные для хранения координат} |
|xx :integer; {и переменные цикла} |
|typ :integer; {Тип текущего корабля} |
|xxx :integer; {Координаты} |
|tarx :integer; {Координаты прицела и пушки} |
|fx :integer; {Координаты} |
|fy :integer; |
|score :integer; {Кол-во очков} |
|old_score :integer; {Прошлое значение кол-ва очков} |
|mimo :integer; {Кол-во промахов} |
|oldx :integer; {Координаты} |
|oldy :integer; |
|crx :integer; |
|cr_type :integer; {Тип корабля} |
|flang :integer; {С какой стороны плывёт корабль} |
|croldx :integer; |
|cr_ind2 :integer; |
|cr_ind:longint; {Рабочая переменная} |
|c:char; {Хранение нажатых клавиш} |
|{Флаги} |
|b :boolean; {Флаг нажатия клавиш 'стрелок'} |
|fire :boolean; {Стрельба} |
|swim :boolean; {Перемещение} |
|promah :boolean; {Промах} |
|vzriv :boolean; {Взрыв} |
|const |
|{Два константных массива точек для хранения координат скал} |
|trin1:array[1..4] of PointType= |
|((x:-70;y:380),(x:60;y:20),(x:150;y:350),(x:-70;y:380)); |
|trin2:array[1..4] of PointType= |
|((x:670;y:380),(x:560;y:5),(x:500;y:350),(x:670;y:400)); |
| |
|{Процедура вывода прицела и пушки на экран} |
|procedure target(ix:integer;bb:boolean); |
|const iy=200; |
|begin |
|if bb then begin {Отображение} |
|SetColor(green); |
|SetFillStyle(SolidFill,green); |
|FillEllipse(ix,430,26,100); |
|SetColor(lightgreen); |
|Line(ix-10,iy,ix+10,iy); |
|Line(ix,iy-10,ix,iy+10); |
|end else begin {Стирание} |
|SetFillStyle(SolidFill,blue); |
|SetColor(blue); |
|FillEllipse(ix,430,26,100); |
|SetColor(blue); |
|Line(ix-10,iy,ix+10,iy); |
|Line(ix,iy-10,ix,iy+10); |
|end; |
|end; |
| |
|{Процедура вывода на экран различных кораблей} |
|procedure sheep(ix:integer;tip:integer;bb:boolean); |
|const |
|iy=200; |
|var |
|col,col2:integer; |
|sp1,sp2,sp3:array[1..5] of PointType; |
|begin |
|col:=brown; |
|col2:=yellow; |
|if not bb then begin {Если bb=true, то отображение корабля} |
|col:=blue; {Иначе стирание корабля} |
|col2:=blue; |
|end; |
|{Координаты кораблей, относительно центральной точки ix} |
|sp1[1].x:=ix-40; |
|sp1[1].y:=190; |
|sp1[2].x:=ix+40; |
|sp1[2].y:=190; |
|sp1[3].x:=ix+20; |
|sp1[3].y:=215; |
|sp1[4].x:=ix-20; |
|sp1[4].y:=215; |
|sp1[5].x:=sp1[1].x; |
|sp1[5].y:=sp1[1].y; |
|sp2[1].x:=ix-30; |
|sp2[1].y:=190; |
|sp2[2].x:=ix+30; |
|sp2[2].y:=190; |
|sp2[3].x:=ix+15; |
|sp2[3].y:=210; |
|sp2[4].x:=ix-15; |
|sp2[4].y:=210; |
|sp2[5].x:=sp2[1].x; |
|sp2[5].y:=sp2[1].y; |
|sp3[1].x:=ix-20; |
|sp3[1].y:=195; |
|sp3[2].x:=ix+20; |
|sp3[2].y:=195; |
|sp3[3].x:=ix+10; |
|sp3[3].y:=205; |
|sp3[4].x:=ix-10; |
|sp3[4].y:=205; |
|sp3[5].x:=sp3[1].x; |
|sp3[5].y:=sp3[1].y; |
|{Отображение одного из трёх типов кораблей} |
|case tip of |
|3: begin |
|SetColor(col); |
|SetFillStyle(SolidFill,col); |
|FillPoly(5,sp1); |
|Rectangle(ix-18,iy-30,ix+18,iy-2); |
|SetColor(col2); |
|SetFillStyle(SolidFill,col2); |
|Rectangle(ix-10,iy-25,ix+10,iy-15); |
|FillEllipse(ix-18,iy,5,5); |
|FillEllipse(ix+18,iy,5,5); |
|FillEllipse(ix,iy,5,5); |
|end; |
|2: begin |
|SetColor(col); |
|SetFillStyle(SolidFill,col); |
|FillPoly(5,sp2); |
|line(ix,200,ix,170); |
|line(ix-5,175,ix+5,175); |
|line(ix-10,180,ix+10,180); |
|end; |
|1: begin |
|SetColor(col); |
|SetFillStyle(SolidFill,col); |
|FillPoly(5,sp3); |
|line(ix,200,ix,185); |
|line(ix-5,185,ix+5,185); |
|line(ix-10,190,ix+10,190); |
|end; |
|end; |
|end; |
| |
|{Начало главной процедуры программы} |
|begin |
|x:=100; |
|xx:=0; |
|xxx:=0; |
|oldx:=0; |
|b:=false; |
|tarx:=320; |
|fire:=false; {инициализация переменных} |
|crx:=0; |
|croldx:=800; |
|score:=0; |
|old_score:=0; |
|mimo:=0; |
|promah:=false; |
|vzriv:=false; |
| |
|{Переключение в графический режим} |
|GraphDriver:=Detect; |
|InitGraph(GraphDriver,GraphMode,''); |
|if ErrorCode=grok then begin |
|SetColor(green); |
|SetBKColor(black); |
|end else begin |
|Writeln('ERROR!'); |
|exit; |
|end; |
| |
|SetColor(white); |
|OutText('Vipolnil: Makarov Vladimir'); |
|OutTextXY(0,10,'Group: C-26'); |
|SetTextJustify(CenterText,CenterText); |
|OutTextXY(640 div 2,480 div 2,'Press to start play game!'); |
|c:=ReadKey; |
| |
|{Подготовка экрана к игре} |
|ClearDevice; |
|SetBkColor(blue); |
|SetColor(lightgray); |
|SetFillStyle(SolidFill,lightgray); |
|FillPoly(4,trin1); |
|FillPoly(4,trin2); |
|SetColor(black); |
|Target(320,true); |
| |
|{Главный цикл обработки различных сообщений и событий} |
|repeat |
|repeat |
| |
|{Обработка сообщения 'Взрыв корабля'} |
|if vzriv then begin |
|if xx=0 then begin |
|typ:=cr_type; |
|xxx:=crx; |
|end; |
|if xx<150 then begin |
|{Рисование взрыва} |
|Sound(Random(100)); |
|swim:=false; |
|SetColor(red); |
|SetColor(red); |
|SetFillStyle(SolidFill,red); |
|FillEllipse(xxx,200,21*typ,17*typ); |
|inc(xx); |
|end else begin |
|NoSound; |
|swim:=false; |
|SetColor(blue); |
|SetFillStyle(SolidFill,blue); |
|FillEllipse(xxx,200,21*typ,17*typ); |
|xx:=0; |
|vzriv:=false; |
|end; |
|end; |
| |
|{Обработка сообщения 'Перемещение'} |
|if swim then begin |
|if cr_ind<400 then begin |
|Sheep(crx,cr_type,false); |
|if promah then promah:=false; |
|end else begin |
|if cr_ind mod cr_type*5=0 then begin |
|if promah then begin |
|if flang=0 then flang:=1 |
|else flang:=0; |
|promah:=false; |
|end; |
|if flang=0 then begin |
|if crx=485 then begin |
|inc(cr_ind2); |
|if cr_ind2<3 then Sheep(crx,cr_type,true) |
|else begin |
|Sheep(crx,cr_type,false); |
|swim:=false; |
|end; |
|end else begin |
|crx:=crx+1; |
|Sheep(croldx,cr_type,false); |
|Sheep(crx,cr_type,true); |
|croldx:=crx; |
|end; |
|end else begin |
|if crx=150 then begin |
|inc(cr_ind2); |
|if cr_ind2<3 then Sheep(crx,cr_type,true) |
|else begin |
|Sheep(crx,cr_type,false); |
|swim:=false; |
|end; |
|end else begin |
|crx:=crx-1; |
|Sheep(croldx,cr_type,false); |
|Sheep(crx,cr_type,true); |
|croldx:=crx; |
|end; |
|end; |
|end; |
|end; |
|inc(cr_ind); |
|end else begin |
|{Если корабля нет на экране, то случайным методом |
|выбирается новый корабль} |
|Randomize; |
|croldx:=800; |
|cr_ind2:=0; |
|if random(2)=0 then begin |
|crx:=150; |
|flang:=0; |
|end else begin |
|crx:=485; |
|flang:=1; |
|end; |
|swim:=true; |
|cr_ind:=0; |
|Randomize; |
|cr_type:=random(3)+1; |
|end; |
| |
|{Обработка сообщения 'Выстрел'} |
|{и рисование полёта снаряда} |
|if fire then begin |
|x:=x-10; |
|Sound(x); |
|SetColor(blue); |
|line(fx+1,fy-2,fx+1,fy+2); |
|line(fx-1,fy-2,fx-1,fy+2); |
|line(fx,fy-2,fx,fy+2); |
|fy:=fy-2; |
|SetColor(lightred); |
|line(fx+1,fy-2,fx+1,fy+2); |
|line(fx-1,fy-2,fx-1,fy+2); |
|line(fx,fy-2,fx,fy+2); |
|if fy<200 then begin |
|if (getpixel(fx-1,fy-3)=brown)or(getpixel(fx+1,fy-3)=brown) then begin |
|old_score:=score; |
|inc(score); |
|vzriv:=true; |
|end else begin |
|{Обработка сообщения 'Промах'} |
|promah:=true; |
|inc(mimo); |
|if mimo>5 then begin |
|{Выход из игры в случае проигрыша} |
|ClearDevice; |
|SetColor(white); |
|SetBkColor(black); |
|SetTextJustify(CenterText,CenterText); |
|OutTextXY(640 div 2,480 div 2,'GAME OVER!'); |
|Sound(200); |
|Delay(10000); |
|NoSound; |
|c:=ReadKey; |
|exit; |
|end; |
|end; |
|fire:=false; |
|NoSound; |
|SetColor(blue); |
|line(fx+1,fy-2,fx+1,fy+2); |
|line(fx-1,fy-2,fx-1,fy+2); |
|line(fx,fy-2,fx,fy+2); |
|end; |
|end; |
|if b then begin |
|{Перерисовка прицела и пушки в случае нажатия клавиш 'стрелок'} |
|target(oldx,false); |
|target(tarx,true); |
|b:=false; |
|end else target(tarx,true); |
|{В случае попадания, производится начисление очков и вывод их на экран} |
|if old_score<>score then begin |
|SetColor(blue); |
|SetTextJustify(LeftText,BottomText); |
|Str(old_score,s_score); |
|OutTextXY(70,460,s_score); |
|old_score:=score; |
|end; |
|SetColor(white); |
|SetTextJustify(LeftText,BottomText); |
|OutTextXY(20,460,'Score'); |
|Str(score,s_score); |
|OutTextXY(70,460,s_score); |
|delay(150); {Временная задержка главного цикла} |
|until keypressed; |
|{Обработка нажатия клавиш} |
|c:=readkey; |
|case c of |
|#75: begin {влево} |
|if tarx>220 then begin |
|oldx:=tarx; |
|tarx:=tarx-5; |
|b:=true; |
|end; |
|end; |
|#77: begin {вправо} |
|if tarx<420 then begin |
|oldx:=tarx; |
|tarx:=tarx+5; |
|b:=true; |
|end; |
|end; |
|#32: begin {пробел 'Выстрел'} |
|if not fire then begin |
|x:=800; |
|fire:=true; |
|fx:=tarx; |
|fy:=380; |
|end; |
|end; |
|#27: begin {esc 'Выход'} |
|NoSound; |
|exit; |
|end; |
|end; |
|until false; {Зацикливание главного цикла обработки сообщений} |
|end. |