Игра с корабликами, графический режим |
Игра с корабликами, графический режим |
Lazzy |
15.12.2007 17:37
Сообщение
#1
|
Группа: Пользователи Сообщений: 9 Пол: Мужской Реальное имя: тьома Репутация: 0 |
Привета!
Задача формулировалась преподом довольно размыто, поэтому может присутствовать некоторая вольность в выполнении, что не может не радовать. Смысл в том, чтоб написать на Pascal (к сожалению) игру, в которой есть кораблики, соревнующиеся между собой Препод седой уже, кстати. Он хотел там видеть возможность выбора направления ветра и хода корабликов галсами при встречном ветре, но реализовать управление парусами, по-моему, слишком сложно, а как без этого галсами ходить? Поэтому реализация мне видится так: вид сверху на остров либо замкнутый кольцевой канал, один кораблик с мотором, цель игры - управляя корабликом стрелками пройти дистанцию за наименьшее время. Если у кого-то возникнет желание помочь или вдруг есть какие-то наработки, буду очень признателен. Вот код: program MAPA3M;Тут нарисованы берега "лагуны" с островом посередине, вид сверху. Кораблик обозначен коричневой точкой и управляется с клавиатуры, это пока все =/ Как видите, нету навыка работы с процедурами, пишется сложно =/ Что конкретно неясно как реализовать: Как сделать чтоб кораблик при нажатиии клавиши начинал двигаться в направлении нажатой стрелки и не прекращал движение? Сейчас он двигается только, когда стрелка нажата. Можно ли сделать движение по диагонали? Сейчас судно движется только в четырех направлениях. Как реализовать крушение кораблика при столкновении с берегом? (Видимо, нужно написать функцию, возвращающую значение цвета пикселов вокруг кораблика, и если эти значения равны значению цвету берега - корабль тонет) Как с помощью Pascal реализовать счетчик времени? Ведь цель игры - пройти дистанцию за наименьшее время. Искал в учебниках, а там работа только с временем системы. Как сделать, чтоб игрок вводил свое имя и результаты записывались в текстовый файл? Как сделать скорость кораблика независимой от тактовой частоты? Ведь delay зависит, если не ошибаюсь, от этого параметра, значит на разных компьютерах игра с этой процедурой будет иметь разную скорость? Заранее спасибо. Файл pas в аттаче. Прикрепленные файлы _.PAS ( 2.16 килобайт ) Кол-во скачиваний: 367 |
andriano |
15.12.2007 18:06
Сообщение
#2
|
Гуру Группа: Пользователи Сообщений: 1 168 Пол: Мужской Реальное имя: Сергей Андрианов Репутация: 28 |
>Как сделать чтоб кораблик при нажатиии клавиши начинал двигаться в направлении нажатой стрелки и не прекращал движение? Сейчас он двигается только, когда стрелка нажата.
Сначала надо полностью продумать систему уравления. Как, например, остановить корабль? В играх от Sierra, например, было принято, что остановка происходит при повторном нажатии на клавишу. Но может оказаться целесообразной и остановка путем нажатия на клавишу противоположного направления. И в том, и в другом случае необходимы переменные, в которых запоминается текущее состояние движения. >Можно ли сделать движение по диагонали? Сейчас судно движется только в четырех направлениях. Можно, конечно. При этом даже различными способами. Например, при использовании цифровой клавиатуры либо при одновременном нажатии двух клавиш. >Как реализовать крушение кораблика при столкновении с берегом? (Видимо, нужно написать функцию, возвращающую значение цвета пикселов вокруг кораблика, и если эти значения равны значению цвету берега - корабль тонет) Можно и так. >Как с помощью Pascal реализовать счетчик времени? Ведь цель игры - пройти дистанцию за наименьшее время. Искал в учебниках, а там работа только с временем системы. Как сделать, чтоб игрок вводил свое имя и результаты записывались в текстовый файл? Правильно. Другого времени и не существует. В момент старта запоминаешь текущаа состояние времени, а потом вычитаешь его из текущих показаний. Ввод имени, очевидно, осуществляется процедурой realln, а запись его в файл - writeln. >Как сделать скорость кораблика независимой от тактовой частоты? Ведь delay зависит, если не ошибаюсь, от этого параметра, значит на разных компьютерах игра с этой процедурой будет иметь разную скорость? А она зависит? Delay специально сделана так, чтобы не зависела. Но с одной стороны - ты ее не используешь, а с другой - скорость в твоем случае определяется скоростью автоповтора клавиатуры. Чтобы избавиться от этого эффекта, можно использовать: if keypressed then ch := readkey; Но в этом случае тебе придется заботиться о скорости другим способом (пока ты вообще об этом не заботишься). Еще пара замечаний: - насколько я понял, при нажатии Esc у тебя происходит мгновенный выход из программы в обход конца цикла и восстановления режима. - целесообразно внутри case выполнять только минимум действий: в данном случае лишь вычисление приращений координат, а всю остальную работу делать в одном месте (чтобы при изменении способа отображения корабля не пришлось менять код в 4-х местах одновременно). |
Lazzy |
16.12.2007 3:28
Сообщение
#3
|
Группа: Пользователи Сообщений: 9 Пол: Мужской Реальное имя: тьома Репутация: 0 |
andriano, спасибо за обстоятельный ответ.
Я попробовал сделать движение без постоянного удержания клавиши, и реализовать столкновение с берегом. Насчет системы движения: корабль должен двигаться непрерывно, не останавливаясь, есть возможность только менять направление движения, поэтому переменных для описания состояния движения не вводил. Однако, я совсем запутался даже здесь. case ch of Для непрерывности движени ввел цикл, а для крушения, как видно, проверку цвета пикселей вокруг корабля. Но корабль двигаеся непрерывно именно до столкновения с берегом, то есть, движение прерывается только при выполнении условия цикла while, а дожен вроде бы и при нажатии клавиши (условие цикла repeat). Да и в столкновении с берегом ошибка - корабль наталкивается на берег, потом делает еще одно перемещение - уже по берегу, а только после этого движение прекращается. Еще и надпись 'Game over. Press Enter, then Esc to exit.' не выводится - поставил временно фигурные скобки, потому что программа не работает без них, не смог обнаружить ошибку. Цитата - целесообразно внутри case выполнять только минимум действий: в данном случае лишь вычисление приращений координат, а всю остальную работу делать в одном месте (чтобы при изменении способа отображения корабля не пришлось менять код в 4-х местах одновременно). Хорошо бы, но я не знаю как. Подскажи, если не затруднит.Цитата - насколько я понял, при нажатии Esc у тебя происходит мгновенный выход из программы в обход конца цикла и восстановления режима. Да. А как нужно? |
andriano |
16.12.2007 10:39
Сообщение
#4
|
Гуру Группа: Пользователи Сообщений: 1 168 Пол: Мужской Реальное имя: Сергей Андрианов Репутация: 28 |
Цитата корабль должен двигаться непрерывно, не останавливаясь, есть возможность только менять направление движения, поэтому переменных для описания состояния движения не вводил. Именно в этом случае и нужна переменная - в ней будет храниться направление движения, когда все клавиши отпущены.Собственно, путаница у тебя начинается с организации циклов. Основной цикл в игре должен быть ОДИН. А у тебя их 3 вложенных: - repeat ... until ch=#27 - repeat ... until keypressed=true - while (сразу отмечу, что "keypressed = true" и "keypressed" логически абсолютно эквивалентны, но первое вычисляется дольше и занимает в коде больше места) Так вот, второй repeat у тебя даже не дойдет до проверки условия, пока не закончится while. А while у тебя закончится только при столкновении с берегом. О первом repeat я уже не говорю - он не успеет совершить даже одного "оборота". Все должно делаться в одном цикле последовательно. repeat Естественно, ВСЕ вызываемые процедуры не содержат задержек и циклов с выходом по изменению состояния. Это в общем. Теперь несколько конкретных ошибок: (getpixel(posX+1,posY+1)and getpixel(posX-1,posY+1)and getpixel(posX-1,posY-1)and getpixel(posX+1,posY-1)<>14)Здесь ты пытаешься над цветом пикселя совершать логические операции. Правильно: (getpixel(posX+1,posY+1) <> 14) and (getpixel(posX-1,posY+1) <> 14) and (getpixel(posX-1,posY-1) <> 14)and (getpixel(posX+1,posY-1)<>14) Вот примерно так. Набивал прямо здесь, код синтаксически не проверял (да и не на чем - TP у меня нет). PS. В этом кодя я для простоты все-таки ввел один внутренний цикл, но он завершаеся не по изменению состояния, а по внутреннему счетчику, т.е. с точки зрения основного цикла может рассматриваться как просто задержка. Есть и еще кое-какие детали, к кторым можно будет вернуться в случае, если тебя интересует нечто большее, чем просто сдать и забыть. Сообщение отредактировано: andriano - 16.12.2007 11:16 |
Lazzy |
18.12.2007 23:19
Сообщение
#5
|
Группа: Пользователи Сообщений: 9 Пол: Мужской Реальное имя: тьома Репутация: 0 |
andriano, спасибо больщущее!
Благодаря тебе кое-что получилось, теперь уже можно играть. Конечно, пока все очень примитивно - анимация крушения, например, это всего лишь мигание кружка. Правила там не описал пока, поэтому здесь кратко: управляем корабликом - кружок, пока не врежемся в берег. Цель - не врезаться подольше. program MAPA3M;В аттаче - exe-шник, смотрите. Только у меня exe-шник всего лишь один раз запускается, не знаю почему, а потом пишет код графической ошибки "No error" и выкидывает. Буду теперь добавлять время, старт-финиш, пытаться сделать меню и прочее. Можно над парусом таки поработать. Пишите пожелания и предложения. P.S. Как репутацию подымать? Прикрепленные файлы Motor_boat.zip ( 14.97 килобайт ) Кол-во скачиваний: 342 |
Lapp |
19.12.2007 7:20
Сообщение
#6
|
Уникум Группа: Модераторы Сообщений: 6 823 Пол: Мужской Реальное имя: Лопáрь (Андрей) Репутация: 159 |
P.S. Как репутацию подымать? Есть два способа: 1. набрать 25 тематических постов; 2. попросить того, у кого они уже есть . Я поднимаю за тебя репу andriano - ты этого хотел? -------------------- я - ветер, я северный холодный ветер
я час расставанья, я год возвращенья домой |
andriano |
19.12.2007 9:06
Сообщение
#7
|
Гуру Группа: Пользователи Сообщений: 1 168 Пол: Мужской Реальное имя: Сергей Андрианов Репутация: 28 |
По поводу ошибки - ничего сказать не могу, нет у меня ТР/ВР, да и когда был, предпочитал не пользоваться модулем graph, так что тонкостей его использования просто не знаю.
По поводу кода, рекомендую все-таки вызывать из основной программы не 1, а 3 процедуры: RestoreBackground, MoveShip и DrawShip. Просто потому, что они выполняют разную работу. И еще: ты сначала рисуешь корабль, а потом удаляешь его старое изображение. Это неправильно. Правильно: сначала восстановить фон, затем нарисовать новое изображение. procedure RestoreBackground; Примерно так. PS. Если интересно, можно оснасить программу и более адекватным интерфейсом. В 2001-2002 гг. писал по этому поводу: http://www.osp.ru/pcworld/2001/07/161910/ Увы, сейчас там почему-то не смог найти листингов, зато они есть http://pascal.sources.ru/articles/087.htm |
spill |
19.02.2008 14:07
Сообщение
#8
|
Пионер Группа: Пользователи Сообщений: 58 Пол: Мужской Реальное имя: Андрей Репутация: 2 |
Да, Delay зависит от производительности ЦП.
Вот модуль, который позволит делать задержку независимо, от ЦП: Unit Timer;Тут есть 3 процедуры: Start, Stop, Pause Pause – тот же Delay, в параметрах – время задержки в миллисекундах, и выводить/не выводить текущее время (работает только в текстовом режиме). Start, Stop нужны для измерения времени работы программы. В старт нужно передать вещественную переменную, в стоп ту же переменную, но после процедуры в ней будет храниться время, которое прошло с момента вызова Старт с этой переменной (проще говоря, старт сохраняет туда текущее время, а стоп вычитает из текущего это время). Время хранится в тиках. Чтобы перевести в секунды нужно это число разделить на 18.2 |
andriano |
19.02.2008 20:35
Сообщение
#9
|
Гуру Группа: Пользователи Сообщений: 1 168 Пол: Мужской Реальное имя: Сергей Андрианов Репутация: 28 |
Вообще-то это не очень хороший вариант.
Начиная с IBM PC AT поддерживается 15h прерывание, одной из функций которого как раз и есть формирование временной задержки. Кстати, величина ее задается в микросекундах, но зачем - непонятно, все равно такая точность не выдерживается. Сейчас уже не 1992 год, компьютеры IBM PC и IBM PC XT свое отслужили и о совместимости с ними вряд ли надо заботиться. С другой стороны, на старших моделях 486 и большинстве Pentium'ов программы, содержащие модуль crt "падали" из-за переполнения при инициализации этого модуля, вызванного как раз вычислением константы для процедуры delay. Собственно, сегодня практически все компиляторы ТР содержат уже пропатченный модуль crt. Грамотно сделанный патч выглядит так: procedure delay(Wait:word); assembler; {єбсСαЄ¬б у јЯ} если это действительно так, то ничего изобретать не нужно. Если нет - можно воспользоваться приведенной выше процедурой. Сообщение отредактировано: andriano - 19.02.2008 20:35 |
spill |
20.02.2008 13:34
Сообщение
#10
|
Пионер Группа: Пользователи Сообщений: 58 Пол: Мужской Реальное имя: Андрей Репутация: 2 |
Вопрос в том, как проверить, пропаченый модуль или нет?
Проще описать вот эту процедуру, только назвать ее MyDelay (чтобы не конфликтовали) и использовать ее, чтобы не волноваться |
andriano |
20.02.2008 19:08
Сообщение
#11
|
Гуру Группа: Пользователи Сообщений: 1 168 Пол: Мужской Реальное имя: Сергей Андрианов Репутация: 28 |
Если на компе с тактовой частотой 200 МГц и выше работает, значит, патченый.
|
Lazzy |
24.03.2008 19:10
Сообщение
#12
|
Группа: Пользователи Сообщений: 9 Пол: Мужской Реальное имя: тьома Репутация: 0 |
Прошу прощения за долгое отсутствие.
Цитата По поводу ошибки - ничего сказать не могу, нет у меня ТР/ВР, да и когда был, предпочитал не пользоваться модулем graph, так что тонкостей его использования просто не знаю. Причина ошибки, по-видимому, в том, что в той директории, где находится исполняемый файл, для корректной его работы обязательно должен находиться еще и файл EGAVGA.BGI. Я увеличил задержку для того, чтобы программа была "играбельной" на более мощных, чем мой, ПК и перезалил архив Motor_boat.zip. И на всякий случай залил TP Цитата По поводу кода, рекомендую все-таки вызывать из основной программы не 1, а 3 процедуры: RestoreBackground, MoveShip и DrawShip. Просто потому, что они выполняют разную работу. И еще: ты сначала рисуешь корабль, а потом удаляешь его старое изображение. Это неправильно. Правильно: сначала восстановить фон, затем нарисовать новое изображение. Спасибо, я так и сделал. Здесь не привожу полный код программы, чтоб не загромождать топик. ####.pas можно глянуть в архиве. При разделении на три отдельные процедуры читать и редактировать программу гораздо легче. Цитата Есть и еще кое-какие детали, к которым можно будет вернуться в случае, если тебя интересует нечто большее, чем просто сдать и забыть. Какие еще замечания? Я собираюсь нарисовать получше сам кораблик, и сделать меню, таймер, таблицу рекордов и т. п. Эти элементы, насколько я понимаю, во всех играх однотипны, то есть можно не писать их с нуля, а адаптировать чужие, правильно? Всем еще раз спасибо! Цитата Я поднимаю за тебя репу andriano - ты этого хотел? Именно! Сообщение отредактировано: Lazzy - 24.03.2008 19:17 Прикрепленные файлы Motor_boat.zip ( 19.83 килобайт ) Кол-во скачиваний: 215 tp7.zip ( 976.18 килобайт ) Кол-во скачиваний: 298 |
Lazzy |
25.03.2008 19:42
Сообщение
#13
|
Группа: Пользователи Сообщений: 9 Пол: Мужской Реальное имя: тьома Репутация: 0 |
Я поискал по форуму меню, наткнулся на такую версию:
Цитата ch := readkey; SetColor(BLACK); X := TextWidth(Strings[i]) + 10; Y := TextHeight(Strings[i]) + 10; Rectangle(GetMaxX div 2 - X div 2, GetMaxY div 2 - (Count - 1) * H div 2 + i * H - Y div 2, GetMaxX div 2 + X div 2, GetMaxY div 2 - (Count - 1) * H div 2 + i * H + Y div 2); case ch of #0: case ReadKey of #72: begin Dec(i); if i < 0 then i := Count - 1; end; #80: begin Inc(i); if i >= Count then i := 0; end; end; end; until ch = #13; Menu := i; end; Примитивнее не могу. Пример вызова такой процедуры: Choise := Menu('New'#13'Open'#13'Save'#13'Exit'); Возвращает номер выбранного пункта, причём нумерация от нуля (New - это 0, а Exit - это 3) То есть параметр - одна строчка, которая содержит все пункты меню, разделённые #13. Количество пунктов - не более 15, каждый пункт не длинее 100 символов. Если перед вызовом написать SetTextStyle(4, 0, 7); то выглядит интересно... Правда, на самом деле это функция, а не процедура. Мое меню состоит всего из двух пунктов: "Play" и "Exit". Основное его предназначение - предоставление игроку выбора сыграть еще раз или выйти при проигрыше. Раньше при проигрыше нельзя было сыграть еще раз. Изменился текст основной программы: begin Смотрите в архиве, что получилось. Я хотел бы сделать игру, которая была бы интересна не только мне, а могла бы отнять у игрока хоть пять минут времени, поэтому пишите ваши пожелания, предложения и просто впечатления. Сообщение отредактировано: Lazzy - 25.03.2008 19:44 Прикрепленные файлы Motor_boat.zip ( 20.76 килобайт ) Кол-во скачиваний: 309 |
Гость |
22.06.2008 12:58
Сообщение
#14
|
Гость |
Программа была мною еще доработана - появилась анимация крушения и анимация поворота. Однако при доработке не удалось сохранить первоначальную стройную структуру, предложенную andriano. Видимо, эта проблема вызвана отсутствием навыка в построении блок-схем. Надеюсь услышать коструктивную критику
program MAPA3M; Как видно, я вставил ассемблерную вставку для того, чтобы программа работала с одинаковой задержкой на разных машинах, но корабль стал плавать слишком быстро, а при попытке увеличить параметр Delay выдается ошибка "Constant out of range", т. е. эта вставка не подходит, помогите пожалуйста сделать лучше. Еще возник вопрос: как осуществить движение корабля под разными углами, чтоб он при нажатии клавиши постепенно менял направление движения? С помощью FillEllipse нарисовать такой корабль не получится, видимо, нужно делать с помощью FillPoly, желательно с большим каоличеством вершин. Но главное - неясно, как задать перемещение, т. е. смену координат. |
Lazzy |
22.06.2008 13:02
Сообщение
#15
|
Группа: Пользователи Сообщений: 9 Пол: Мужской Реальное имя: тьома Репутация: 0 |
Предыдущее сообщение мое.
|
renesko1 |
22.06.2008 13:16
Сообщение
#16
|
поиск Группа: Пользователи Сообщений: 346 Пол: Мужской Реальное имя: nir Репутация: 2 |
Поставь 2 задержки подряд...
-------------------- typedef void Śūnyatā ;
|
andriano |
22.06.2008 16:29
Сообщение
#17
|
Гуру Группа: Пользователи Сообщений: 1 168 Пол: Мужской Реальное имя: Сергей Андрианов Репутация: 28 |
1. Если планируется отрабатывать несколько различных состояний, то основа главного игрового цикла остается, занчительная часть внутренности (кроме опроса клавиатуры, задержки и т.п.) выносится в отдельную процедуру и такие процедуры пишутся для каждого из состояний. Вводится новая переменная - номер текущего состояния, по которой (case) выбирается нужная процедура внутри цикла. Там же записываются условия перехода из одного состояния в другое (конечный автомат).
2. Почему проблемы с delay, честно говоря, не понимаю. В том виде, как она записана, она позволяет делать задержку до 65.5 сек, чего, думаю, более, чем достаточно. Если этого по каим-то причинам мало, то можно сделать так: procedure delay(Wait:longint); 3. Изменение координат - в полном соответствии со школьными курсами физики и геометрии: dx := V*dt*cos(alpha); dy := V*dt*sin(alpha); естественно, скорости, координаты и углы - величины вещественные, а при рисовании координаты округляются до целых. Полигон, образующий корабль, думаю, лучше всего вращать при помощи матрицы поворота. Это аналитическая геометрия за 1-й курс или любой FAQ по 3D-графике, только надо упростить до двумерного случая. |
Lazzy |
10.10.2008 0:30
Сообщение
#18
|
Группа: Пользователи Сообщений: 9 Пол: Мужской Реальное имя: тьома Репутация: 0 |
Вот что получилось - корабль нарисован из круга, прямоугольника и треугольника. Анимация реализована максимально просто - экран каждый раз очищается полностью. Константы s, v, c позволяют менять соответственно размер, скорость и цвет кораблика.
Код: uses crt,graph; Спасибо еще раз! Сообщение отредактировано: Lazzy - 10.10.2008 0:31 |
Текстовая версия | 28.04.2024 22:43 |