Как сделать игру в паскале

Добавил пользователь Валентин П.
Обновлено: 19.09.2024

Насчет того, что мы делаем. Я уже говорил, что мы делаем НЕ игровой движок, а игру.

Н о вопрос такой: Что это такое игровой движок? Везде в OpenGL это встре чаю, но не понимаю что это такое. Чем это отличается от игры? Разве Doom3 или Need For Speed Underground - это движки какие-то? Не думаю. Так что это такое?

Весьма условно: Delphi - это движок, а созданная с ее помощью программа - это не движок . :), а прикладная программа (например игра), созданная, если угодно, на движке Delphi.

Движок - это просто виртуальная реализация некоей ограниченной версии физического мира. Запрограммированы законы этого мира и способы их быстрой и красивой визуализации па экране. А вот конкретное наполнение этого мира городами, сценариями развития, существами с собственным поведением, различными областями местности – уже задача дизайнеров и программистов конкретной игры. Как Duke Nukem Forever на основе движка Doom 3 - способы перемещения по трехмерному миру, законы гравитации, качество визуализации взяты из Doom, а сценарий, персонажи, внешний вид мира выдуманы заново.

При этом возможности движков могут сильно различаться. Одни - нечто, чуть более функциональное, чем DirectX, другие - готовые редакторы виртуальных миров и собственные языки сценариев итд. В принципе, то, что мы сейчас делаем - это наверное все же тоже в некоторой степени движок И по хорошему в нем можно еще разделить общие аспекты, связанные с игровым миром, с такими уже привязанными к конкретной игре моментами, как генерация пещер, конкретные виды монстров и предметов итд. Подписчик Дмитрий предложил как один из вариантов сразу задействовать Delphi:

По поводу вопроса про возможности Дельфи работать с текстовой ДОС-графикой – в версии б (насчет других не знаю) можно создать приложение типа Console Application. В этом случае формы не подключаются, вывод идет в текстовое окно. Однако возможностей по смене позиции курсора я не обнаружил (то, что в Паскале реализуется функциями Crt). Тоже относится к прямой записи в видеопамять. То есть можно делать вывод на экран, но только пользуясь операторами Wrile/WrileLn По поводу игры: если можно, в одном из ближайших выпусков хотя бы схематично изобразите пожалуйста структуру игры в виде перечня модулей и краткого описания функций каждого из них.

Пользуясь Вашей рассылкой, я начал самостоятельно писать игру, но есть вопросы по поводу разделения разных функций по разным модулям. Пишу на Дельфи б, уже реализовал один из алгоритмов генерации подземелья с указанного Вами сайта. Для вывода карты использую компонент SlringGrid, в каждую ячейку вывожу по одному тайлу (пока без использования цветов). Реализовал скроллинг (пока без использования клавиатуры, на экранных кнопках).

Кстати, очень хорошая идея, со стринггридом.

Дмитрий поднимает важный вопрос аккуратного разделения функций. Поэтому программируем главного героя

Создадим новый модуль и назовем его Не r о.

Пока мы не решили окончательно, какими характеристиками будет характеризоваться наш герой, хотя и наметили основные направления его реализации. Поэтому постараемся приготовить максимально гибкий код, чтобы в дальнейшем иметь возможность быстро его расширять и дополнять, не разрушая архитектуру всего приложения.

Характеристики поделим натри уже упоминавшиеся выше группы - базовые параметры, навыки (умения) и основные величины, не попадающие в две предыдущие группы. Каждую из этих групп представим в виде массива.

Chars : array[1..MaxChars] of Integer;

Skills: array[1..MaxSkills] of Integer;

x,y, HP, MaxHP, Exp, MaxExp, Level, VisLong: Integer;

На последнюю группу вошли такие характеристики, как текущее здоровье (HP) и максимально возможное на текущем уровне здоровье (Мах H Р), текущее количество опыта ( Exp ), и количество опыта, которое надо набрать для перехода на следующий уровень ( MaxExp ), дальность видения в тайлах (VisLong), а также текущий уровень героя (Level).

Очевидно также, что герой должен находиться в какой-то точке карты, заданной абсолютными координатами х,у (абсолютными - то есть связанными с левым верхним углом глобальной карты, а не видимого на экране окна).

Сколько исходно у героя будет базовых параметров и навыков? Для первого приближения воспользуемся здравым смыслом и известными примерами ролевых игр. Допустим, наш герой будет отличаться силой, ловкостью, телосложением и умом. Параметров конечно не очень много, но даже в таком четырехмерном пространстве параметров на самом деле можно придумать множество комбинаций, определяющих самые разные по своим возможностям персонажи. Каждому из этих параметров поставим в соответствие свою координату, означающую фактически номер элемента массива Chars:

Кроме того, герой должен как минимум уметь сражаться в ближнем бою и уметь обнаруживать ловушки. Опишем эти навыки схожим образом:

skill TrapSearch = 2;

Как нам обеспечить доступ к герою из других модулей программы? Таким же способом, мы организовали доступ к карте - выделением отдельной переменной. Только в данном случае мы пойдем на небольшую хитрость. Вместо скалярной переменной, ответственной за единственного героя, введем массив героев, а текущего героя, который в даный момент выполняет игровую миссию, отметим с помощью переменной, хранящей индекс этого героя в массиве.

Этот подходод очень полезен, если в будущем мы захотим организовать действие не одного, а целой группы героев, или даже армии. Такое решение может потребоваться, например, если возникнет желание создать на базе нашего ролевого движка стратегическую игру, в которой за каждую из сторон выступает множество персонажей.

Heroes:array[1..MaxHeroes] of THero;

Пока массив героев мы сделали содержащим одного персонажа - больше в ролевой тре нам и не надо. Однако принцип работы программы становится принципиально новым - в любой момент мы сможем расширить игру на большое число персонажей. Теперь нам требуется процедура начальной инициализации всех параметров и характеристик определенного героя. Назовем ее InitHero:

procedure InitHero(HeroNum: Integer);

with Heroes[HeroNum] do

begin for i := 1 to MaxChars do

for i := 1 to MaxSkills do

MaxHP := HPLevel_Table[Level]; HP := MaxHP; Exp := 0;

MaxExp := ExpLevelJTable[Level]; VisLong := 2;

Пока все параметры героя установим в ноль и будем развивать их в процессе игры. Единственные исключения - дальность видения VisLong (примем его равным двум тайлам и пока менять по ходу игры не будем), MaxExp - очередное пороговое значение опыта для очередного повышения уровня, и МахНР - текущее максимальное значение здоровья. Они берутся из заранее подготовленных массивов (таблиц). Ссылки на такие таблицы удобнее всего вынести в дополнительный модуль, хранящий все вспомогательные константы и таблицы (добавим ссылку на него в заголовок реализации Implementation модуля Него). Назовем этот модуль Tables:

Теперь надо определить размеры таких таблиц. Они определяются, очевидно, максимально достижимым в игре уровнем героя. Без глубокого и продолжительного тестирования вряд ли возможно даже приблизительно определить порядок высоких уровней героя. В коммерческих ролевых системах типа D&D все вопросы балансировки решены очень хорошо, но именно поэтому за использование этих систем надо платить - покупать лицензию.

Поэтому на первом этапе проще всего взять некое условное значение максимального порога - для начала выберем небольшой уровень, равный семи. Построим две таблицы, исходя из этого уровня:

Const MaxPlayerLevel = 7;

const ExpLevel_Table: array[0..MaxPlayerLevel] of Integer =

10, 20, 50, 100, 250, 500, 1000, 3000

const HPLevel_Table: array [0. .MaxPlayerLevel] of Integer =

10 , 20, 30, 50, 80, 130, 210, 340

Отметим, что N-й элемент каждого массива соответствует максимальному соответствующему значению для уровня N. Так, для уровня 0 надо брать элементы таблиц с индексом 0, для уровня 7 - элемент с индексом 7.

Каким образом заполнены эти таблицы? В значительной степени это сделано интуитивно.

Не представляет никакого груда в дальнейшем в ходе игры откорректировать соответствующие значения. Опыт растет экспоненциально, уровень здоровья – помедленнее (есть такая последовательность чисел Фибоначчи).

Особенностей формирования и корректировки этих таблиц мы коснемся позже, а пока создадим еще одну процедуру инициализации всех героев:

for i := 1 to MaxHeroes do

Обратите внимание, что переменная CurHero, определяющая индекс текущего героя в массиве Heroes, получает начальное значение.

Эту процедуру мы вызовем из главной программы, в начале блока инициализации, добавив также ссылку на модуль Не r о:

uses Map, LowLevel, Hero;

Map Generation (1) ;

Пока в выводимой на экран информации ничего нового не возникло (точнее, экран по прежнему пуст, так как все тайлы пока не видны - флажок I sVisible содержит значение 1.). Так произошло потому, что хотя мы подготовили массив героев, но не определили их координаты (точнее, координаты единственного главного героя). Как задать эти координаты? Удобнее всего это сделать в процедуре инициализации InitHero. Просто поставим героя в некоторую случайную точку в отображаемой на экране части карты, и сделаем видимой вокруг него некоторую область. Опишем процедуру InitHero так:

х := GameMap[CurMap].LocalMapLeft + LOCAL_MAP_WIDTH div 3

+ random(LOCAL_MAP_WIDTH div 3);

у := GameMap[CurMap].LocalMapTop + LOCAL_MAP_HEIGHT div 3 +

random(LOCAL_MAP_HEIGHT div 3);

Heroes[CurHero].x := x; Heroes[CurHero].у := у;

x и у получают значения, лежащие в центральной трети видимой части карты. Чтобы процедура могла обращаться к переменной GameMap, в заголовок Implementation надо добавить ссылку на модуль Map.

Следом за определением координат героя вызовем процедуру SetHeroVisible (пока неопределенную), которая делает видимыми тайлы вокруг героя на расстоянии от него, определенном параметром VisLong:

procedure SetHeroVisible(HeroNum: Integer);

var i, j: Integer;

for i := Heroes[HeroNum].x-Heroes[HeroNum].VisLong to

for j := Heroes[HeroNum].y-Heroes[HeroNum].VisLong to

Heroes[HeroNum].y+Heroes[HeroNum].VisLong do GameMap[CurMap].Cells[i,j].IsVisible := true;

Интересно, что если теперь запустить программу, то на экране будет видима область вокруг героя - размером она будет 5 па 5 тайлов (по два таила в каждую сторону от героя). Однако сам герой пока не отображен. Этим мы займемся далее.

Создание примитивного платформера на языке PascalABC.NET ссылка на скачивание - pascalabc.net

Это очень хорошо что вы сами занимаетесь программированием, кроме того что в школе застекляют - ибо только так можно хоть чему-то научится, но создавать "уроки" о чем-то, не освоив толком самому - по крайней мере, глупо. Ваш урок мог бы пригодится разве что таким же школьникам делающим контрольные ну или студентам для курсовой, хотя не знаю кто делает курсовые на паскале. Да только вот просто набрав в google: "игры на паскале", можно запросто скачать множество готовых игр с исходным кодом и с подробным описанием функций и процедур.

На всякий случай - вот код программы для тех, кому лень самому писать

uses GraphABC, ABCObjects;

var
x,y: integer;
Pikabu: CircleABC;

procedure keydown(key: integer);
begin
if key = VK_Left then x := x - 10;
if key = VK_Right then x := x + 10;
if key = VK_Up then y := y - 10;
if key = VK_Down then y := y + 10;
Pikabu.MoveTo(x,y);
end;

begin
x := 100;
y := 100;
Pikabu := CircleABC.Create(x,y,25,clYellow);
OnKeyDown := keydown;
end.

Однажды я выполнил три урока по construst2. Это было довольно увлекательно и информативно. Правда, с массивами до конца не разобрался.
И все же.

Зачем вы делаете такие обрывочные посты? Что, создаем шарик, который движется в сторону? Да брось, это же скучно.

Думаю, адекватная форма обучения игрострою - это создание работающего "серьезного" проекта в процессе. С описанием основных элементов (делаем рпг - описываем инвентарь, прокачку, рандомный лут и прочее).

Иллюстрация к комментарию

потом будут сложности с рисованием заднего фона и самой анимации передвижения. Я бы рекомендовал использовать SFML на c++. Довольно прост, разве что немного маловато документации на него, а так просто чудо)

p.s. а не проще создать простой класс для игрока, где методами как раз и будет движение?

p.s.s. автор, если надо могу скинуть куски своего кода на игру Марио. с принципом хотя бы разобраться сможешь.

Иллюстрация к комментарию

Ну что за кармодрочерство? Это прелестно, что ты увлекся программированием, что тебя зацепил игрострой. Но делать "туториал как сделать супер игру вашей мечты имея всего лишь паскаль и среду разработки для школьников", да еще и на пикабу, а не на какой-нибудь геймдев - это просто убого


Мрамор нннада?

Наглядный пример, как тяжело выбраться из подо льда. Это профессиональный спортсмен, 4 кратный чемпион мира по хоккею с мячом. Занимается так же кроссфитом, ледовым кроссом от РедБулл, и судя по тому что я почитал в интернете, попутно плаванием и другими видами спорта, но не на профессиональном уровне. Я уже молчу что здесь он днём, с командой и страховкой, в полностью прозрачной воде с прозрачным льдом. Думаю больше слов не надо, в видео всё максимально наглядно.

Ссылки на профиль спортсмена:

А нам больше и не надо!

А нам больше и не надо!


Скоро

Скоро Комментарии на Пикабу, Комментарии, Скриншот, Юмор, Дети

У пациента была паническая атака во время компьютерной томографии

У пациента была паническая атака во время компьютерной томографии Клаустрофобия, Томография, Панические атаки

Ну в целом да))

Ну в целом да))

Хороший обмен

Хороший обмен

Москвичка Ольга, как и многие ее соседи на Киевской улице, недовольна, что в их районе действует нелегальный хостел. Девушка много раз обращалась в полицию из-за шума и агрессивного поведения постояльцев заведения.

Теперь мигранты угрожают ей расправой. Местный участковый, по ее словам, покрывает бизнес. Каждый раз, когда жильцы звонят в дежурную часть и жалуются на шум, проживающие мигом покидают хостел до прибытия наряда. Люди полагают, что информацию о готовящейся проверке им сливает участковый.


Мастер переговоров

Продаю дачу на Авито, иногда попадаются и такие индивиды

Мастер переговоров Авито, Скриншот, Длиннопост, Переписка

Мастер переговоров Авито, Скриншот, Длиннопост, Переписка

Мастер переговоров Авито, Скриншот, Длиннопост, Переписка

Ну вот что за люди непонятливые, на что рассчитывают?

Сбер и мошенники

Довожу до вашего сведения, дорогие пикабутяне, что Сбер кое-что предпринимает в борьбе с "сотрудниками своей службы безопасности".

На днях маме моей позвонили очередные обеспокоенные её счётом граждане, мама их отбрила и. не смогла войти в свой ЛК.

Появился баннер, говорящий маме о том, что ей только что звонили мошенники, и что временно вход в ЛК для неё закрыт, во избежание лихорадочных переводов не известно кому.

Это прорыв и рывок, я щитаю. Сбер все-таки нашёл способ применить базу мошеннических номеров телефонов, которую сознательный граждане составляли на их сайте.

Мама позвонила им на 900, рассказала, что ничего нужного мошенникам не сообщила и ей разблокировали ЛК.

Просто хорошая новость и я ею поделилась:)


Невоспитанность

Спонтанно захотелось написать. Время 20.30.Еду в метро, Москва, красная ветка. Читаю Пикабу. Справа возле меня села тетка восточной национальности, смотрит видео на полной громкости, пофиг на окружающих . Несколько дальше сидит парень молодой ,тоже восточных кровей ,видео конечно же без наушников,на полную громкость. Блядь, вот что у таких людей в голове ? Личное пространство, воспитание, общественное место, в аулах такое не нужно скорее.

Сориентировались

Участились случаи QR-эксгибиционизма. Эксгибиционист дает для проверки QR-код, а он ведет не на госуслуги, а на дикпик.

Коммунальные проблемы

Коммунальные проблемы


Статья морского инженера о навальном способе погрузки собрала сто тысяч однотипных комментариев

Статья морского инженера о навальном способе погрузки собрала сто тысяч однотипных комментариев Из сети, Комментарии, Погрузка, Порт, Юмор, ИА Панорама, Алексей Навальный

Как и на другом любом языке. С помощью знаний и умений.

А учитывая всё прочее, прогать игру на этом деле это всё равно что выдумывать велосипед-костылеход.

велосипед-костылеход.
Нихрена. Паскаль - очень мощный и хороший язык, я в свое время на нем кучу чего писал. От всяких клонов Боулдер Даша до рогаликов и РПГ.

Ну, в смысле, тебе и свои сериализаторы надо будет писать, и ресурс менеджеры, и прочее и прочее. Лично я это вижу именно как создание велосипедов.

Так это для большинства языков программирования. Именно поэтому многие бегают за чужими библиотеками, потому что не хотят сами писать какую-нибудь сортировку пирамидой.

Игры можно хоть в блокноте писать. Так что чего бы и нет.

Ух какую же ты старинную вещь достал из дедушкиного шкафа. Положи обратно, ладно?

И пиши на Delphi 5

получается только на паскале

Так же как и на любом другом языке. С 2д там проблем никаких нет, да и для 3д помню были опенсорс библиотеки неплохие.
И да, здесь еще вопрос, что подразумевается под "Крутой игрой", например тетрис был в свое время написан на паскале

Крутая игра -это автомобильные гонки

Ну, чёт такое может и без проблем можно будет сделать.

А можно и вот такое. Это 1988, кстати.

что подразумевается под "Крутой игрой"
Майнкрафт? Гта 5?

Крутая игра -это автомобильные гонки

В юнити/анреал визуализатор объектов и физика уже сделаны, остается только написать код самой игры(старт, финиш, движения) и соединить их. А в паскале нужно все делать самому. Я делал проги в visual studio, там интерфейс сделать легко(тупо элементы в окне расставляешь и готово), но там также как в паскале по умолчанию все рисует процессор.

TSquareColor — это запись, хранящая в себе фоновый цвет и цвет текста. Функция createColor принимает на вход первым параметром цвет фона, а вторым — цвет текста и возвращает уже заполненную запись TSquareColor, которая потом уже используется для задания цвета определённой клеточки )

Вообще, код неплохо откомментирован. В некоторых местах даже избыточно, т.к. это курсовая работа, пришлось комментировать почти всё 🙂
А некоторые куски кода, которые можно было бы оптимизировать и вынести в отдельную функцию, лишь изменяя некоторые параметры, пришлось оставить так, как есть, задублированными… )
Поэтому всякие объяснения можно найти в коде!
Сразу скажу, что настройки размера поля, отступов клеточек друг от друга, другие отступы, настройки анимации и т.д. можно задавать тоже в коде, эти константы вынесены специально для этих целей )

Настало время показать, как это дело выглядит! А вот так:


Игра 2048. Окно программы в самом разгаре игры!

Ничего особенного. Всё как обычно )

А в заголовке отображается ещё и количество очков. Управление то же самое, как и в классической реализации игры. Поведение тоже )
При появлении и сложении клеточек есть анимация небольшая, которая порой работает кривовато… Тут уж был задействован таймер, а также изменение размеров этих блоков. Иногда просто почему-то размер не доходит до начального состояния, и поэтому некоторые клеточки так и остаются немного больше или меньше, но это происходит редко )

Игра 2048. Вопрос о начале новой игры (при нажатии на Esc) Игра 2048. Конец игры. Лол!

Про модальные диалоги я, конечно, загнул немножко )
Вся модальность работает вот так:


Обрабатываются нажатия в главном окне программы, а там уже идёт проверка, если открыто какое-то диалоговое окно, то нужно обрабатывать нажатия несколько иначе, а если же нет никаких окон, то там уж управлять игрой нужно )
При нажатии мышкой на кнопку ОК или Enter на клавиатуре срабатывает уже определённое заданное событие, которое передаётся как callback (типа того) при вызове функции dialogs.showConfirm. Как-то так оно и работает… )

Прикольно, в общем. Остальное можно найти в коде и в комментариях, которых там, как уже было сказано выше, предостаточно.

Были некоторые идеи, типа сохранения состояния игры при закрытии и восстановление при открытии, но как-то не было в этом необходимости, да и интерес через некоторое время пропал, поэтому всё осталось на таком уровне, на котором есть сейчас. К тому же, для курсовой тому человеку всех этих окошек диалоговых не нужно, поэтому на каком-то этапе он просто оставил старую версию и стал дорабатывать её по-своему )

Сделано это всё было ещё осенью, но сейчас стало можно это опубликовать, может, ещё кому-то пригодится или же просто интересно будет 🙂

Читайте также: