Bastilude by Marco's Retrobits
Бастилия
БАЗОВАЯ 10-строчная видеоигра для Sinclair ZX Spectrum
Марко Варезио (Marco’s Retrobits) https://retrobits.itch.io/
Блог на английском языке: https://retrobits.altervista.org/
Блог на итальянском языке: https://somebitsofme.altervista.org/
Канал YouTube: https://www.youtube.com/channel/UCWTxG8paNsOUEU5mPcNklXA
Играть онлайн/ссылка для скачивания: https://retrobits.itch.io/bastilude
Видео игрового процесса:
Bastilude (Basic Hastilude) — видеоигра в жанре экшн, написанная всего из 10 строк на языке программирования BASIC для домашнего компьютера Sinclair ZX Spectrum.
Это мое участие в конкурсе BASIC 10 Liner Contest 2022 года, категория PUR-80 (максимум 80 символов в логической строке, разрешены сокращения).
Вдохновением для Bastilude послужила аркадная игра Joust, разработанная Williams и впервые выпущенная в 1982 году.
Игровой процесс
========
Игрок управляет (с большим воображением) рыцарем верхом на зеленом драконе. Цель состоит в том, чтобы сбросить рыцарей противника верхом на пурпурных драконах в рыцарском поединке или спешке. Победителем поединка становится всадник, чья верховая лошадь в момент контакта выше. Столкновение равной высоты отталкивает персонажей друг от друга. Уровень сложности постепенно увеличивается по мере того, как противники побеждаются и становятся быстрее.
При запуске программы отображается титульный экран.
Вы можете начать игру, нажав любую клавишу. Клавиши «o» и «p» управляют горизонтальным направлением дракона.и скорость, а клавиша «z» заставляет дракона летать. Одновременно принимается только одна команда, так что вы можете либо управлять горизонтальной скоростью и направлением, либо взмахивать крыльями дракона.
В нижней части экрана программа отслеживает количество оставшихся жизней и счет игрока, а также высокий балл. Также отображается краткое напоминание об элементах управления.
Описание программы
===================
Переменные
---------
C Позиция игрока X
Позиция R-игрока Y
X Позиция игрока X на экране (целая часть C)
Y Позиция игрока Y на экране (целая часть R)
Горизонтальная скорость игрока V
Вертикальная скорость игрока W
B Позиция оппонента X
Позиция оппонента Y
H Позиция соперника X на экране (целая часть B)
G Позиция соперника Y на экране (целая часть A)
F Горизонтальная скорость противника
E Вертикальная скорость противника
L Осталось жизней
S Текущий счет
Высокий балл
Z Случайное число 0<=Z<1
Итератор цикла
Список программ
---------------
1 ЯРКО 1: ГРАНИЦА 6: БУМАГА 0: CLS: ДЛЯ i=1 ДО 7: ПЕЧАТЬ В i+6,i+6;ЧЕРНИЛА i;"БАСТИЛУДА": СЛЕДУЮЩИЙ i: ПУСТЬ r=21: ПУСТЬ c= 15: ЕСЛИ PEEK 25102=128, ТО ПУСТЬ t=0
2 INK 4: LET v=0: LET w=1: LET a=10: LET b=15: LET e=.2: LET f=-.2: LET g=0: LET h=0: LET l=2: LET s=0: ПЕРЕЙТИ SUB 10: ПАУЗА 0: ГРАНИЦА 6: CLS: ПЕРЕЙТИ SUB 10
3 LET x=INT c: LET y=INT r: LET g=INT a: LET h=INT b: НАПЕЧАТАТЬ y,x;CHR$(61+SGN v+(v=0));INK 3;AT g,h;CHR$(61+SGN f+(f=0)): ЕСЛИ h<>x ТО ПЕРЕХОДИМ К 6
4 ЕСЛИ g=y-1, ТО ГРАНИЦА 3: СЛУЧАЙНО ВЫБЕРИТЕ: ПУСТЬ l=l-1: ПУСТЬ r=21: ПУСТЬ c=8+16*(h<15): ПУСТЬ v=0: BEEP .5, -23: НАПЕЧАТАТЬ y,x;" ": ПЕРЕЙТИ SUB 10: ПЕРЕЙТИ К 1+2*(l>-1)
5 ЕСЛИ y=g-1, ТО ГРАНИЦА 4: РАНДОМИЗАЦИЯ: ПУСТЬ s=s+1: ПУСТЬ a=RND*22: ПУСТЬ b=RND*32: ПУСТЬ e=ABS e+.05: ПУСТЬ f=ABS f+ .05: СИГНАЛ .1,12: ПЕЧАТЬ В g,h;" ":ПЕРЕД SUB 10: ПЕРЕЙТИ К 3
6 ПУСТЬ k$=INKEY$: ПУСТЬ v=v+.2*(k$="p")*(v<1)-.2*(k$="o")*(v>-. 8): ЕСЛИ e>.95, ТО ПУСТЬ e=.95
7 ПУСТЬ w=-1*(k$="z")*(y>0) +(k$<>"z")*(y<21)+(y=0): ПУСТЬ z= RND: ЕСЛИ y=g И h=x, ТО ПУСТЬ f=-f: ПУСТЬ v=-SGN f*ABS v
8 ПУСТЬ c=c+v: ПУСТЬ c=c-32*(c>=32)+32*(c<0): ПУСТЬ b=b+f: ПУСТЬ b=b-32*(b> =32)+32*(b<0): ПУСТЬ r=r+w
9 ПУСТЬ a=a+e*SGN(y-1-g)*(g>0)+(g=0): НАПЕЧАТАТЬ AT y,x;" ";AT g,h;" ": LET f=-f*(z<.05)+f*(z>=.05): ПЕРЕЙТИ К 3
10 LET t=t*(t>s)+s*(t<=s): ПЕЧАТЬ #1;БУМАГА 6;ЧЕРНИЛА 1;AT 0,0;"Sc:";s,"Hi:" ;t,"Жизни:";l,"
Объяснение исходного кода
---------------------
Инициализация
Строки 1 и 2 отображают титульный экран и выполняют инициализацию переменных.
1 ЯРКО 1: ГРАНИЦА 6: БУМАГА 0: CLS: ДЛЯ i=1 ДО 7: ПЕЧАТЬ В i+6,i+6;ЧЕРНИЛА i;"БАСТИЛУДА": СЛЕДУЮЩИЙ i: ПУСТЬ r=21: ПУСТЬ c= 15: ЕСЛИ PEEK 25102=128, ТО ПУСТЬ t=0
2 INK 4: LET v=0: LET w=1: LET a=10: LET b=15: LET e=.2: LET f=-.2: LET g=0: LET h=0: LET l=2: LET s=0: ПЕРЕЙТИ SUB 10: ПАУЗА 0: ГРАНИЦА 6: CLS: ПЕРЕЙТИ SUB 10
Первые две строки исполняютсякаждый раз, когда начинается новая игра, но максимальный счет T должен быть определен и инициализирован нулем только один раз. Это делается путем проверки области переменных в памяти с помощью оператора PEEK в строке 1; 25102 (0x620E) — это, по сути, адрес, по которому ожидается идентификатор переменной высокой оценки (этот адрес был определен эмпирически, исходя из длины программы). При первом выполнении оператора PEEK 25102 были определены только переменная цикла I и переменные R и C, и это местоположение будет содержать значение терминатора 128 (0x80), поэтому переменная T определена и инициализирована до 0. При последующих выполнениях, ячейка будет содержать значение 116 (0x74), соответствующее коду символа «t», поэтому сравнение со 128 не удастся, и значение переменной T больше не будет установлено равным 0.
Игровой цикл
Настоящий игровой цикл начинается со строки 3.
3 LET x=INT c: LET y=INT r: LET g=INT a: LET h=INT b: PRINT AT y,x;CHR$(61+SGN v+(v=0));INK 3 ;AT g,h;CHR$(61+SGN f+(f=0)): ЕСЛИ h<>x, ТО ПЕРЕЙТИ К 6
Целая часть координат игрока и противника вычисляется и используется для ПЕЧАТИ их на экране. И игрок, и противники изображаются с помощью символов «<» (код 60) или «>» (код 62) в зависимости от их горизонтального направления (лицом влево или вправо).
Если X-координаты игрока и противника различаются, столкновения быть не может, и программа переходит к строке 6.
В противном случае, если противник находится вышеplayer (строка 4), игрок теряет одну жизнь и статус игры обновляется. Если жизней больше не осталось, программа переходит к строке 1, в противном случае игрок располагается в нижней строке экрана, и игровой цикл продолжается со строки 3.
4 ЕСЛИ g=y-1, ТО ГРАНИЦА 3: СЛУЧАЙНО ВЫБЕРИТЕ: ПУСТЬ l=l-1: ПУСТЬ r=21: ПУСТЬ c=8+16*(h<15): ПУСТЬ v=0: BEEP .5, -23: НАПЕЧАТАТЬ y,x;" ": ПЕРЕЙТИ SUB 10: ПЕРЕЙТИ К 1+2*(l>-1)
Если игрок находится выше противника (строка 5), игрок получает одно очко, в случайном месте появляется новый противник, а его горизонтальная и вертикальная скорости увеличиваются. Статус игры обновляется, и игровой цикл продолжается на строке 3.
5 ЕСЛИ y=g-1, ТО ГРАНИЦА 4: РАНДОМИЗАЦИЯ: ПУСТЬ s=s+1: ПУСТЬ a=RND*22: ПУСТЬ b=RND*32: ПУСТЬ e=ABS e+.05: ПУСТЬ f=ABS f+ .05: СИГНАЛ .1,12: ПЕЧАТЬ В g,h;" ":ПЕРЕД SUB 10: ПЕРЕЙТИ К 3
Строка 6 считывает состояние клавиатуры, и если нажата клавиша «o» (левая) или «p» (правая), соответственно обновляется горизонтальная скорость игрока V. Вертикальная скорость противника E ограничена таким образом, что она не может стать больше 0,95, иначе игрок не сможет выиграть поединок.
6 ПУСТЬ k$=INKEY$: ПУСТЬ v=v+.2*(k$="p")*(v<1)-.2*(k$="o")*(v>-. 8): ЕСЛИ e>.95, ТО ПУСТЬ e=.95
Строка 7 проверяет, нажата ли клавиша «z», и соответствующим образом обновляет вертикальную скорость игрока W. Если игрок поднимается и попадает в верхнюю часть экрана (Y=0), он «отскакивает» вниз.
Проверка коллизий завершена во второй части строки7: если игрок и противник занимают одну и ту же позицию, поединок считается ничьей, а горизонтальные скорости персонажей обновляются так, чтобы они двигались в противоположных направлениях.
7 ПУСТЬ w=-1*(k$="z")*(y>0) +(k$<>"z")*(y<21)+(y=0): ПУСТЬ z= RND: ЕСЛИ y=g И h=x, ТО ПУСТЬ f=-f: ПУСТЬ v=-SGN f*ABS v
Строка 8 обновляет позиции X игрока и противника (C и B) на основе горизонтальных скоростей V и F. Позиция игрока Y R обновляется на основе вертикальной скорости W.
8 ПУСТЬ c=c+v: ПУСТЬ c=c-32*(c>=32)+32*(c<0): ПУСТЬ b=b+f: ПУСТЬ b=b-32*(b> =32)+32*(b<0): ПУСТЬ r=r+w
В строке 9 координата Y противника A обновляется на основе вертикальной скорости E и положения игрока по Y; на самом деле противник пытается пролететь на одну позицию выше игрока, чтобы выиграть поединок. Затем оба персонажа стираются с экрана; они будут отображаться в обновленных координатах в следующей итерации игрового цикла. Чтобы добавить в игру некоторой непредсказуемости, с вероятностью 5% горизонтальное направление соперника инвертируется. Наконец, программа возвращается к началу игрового цикла в строке 3.
9 ПУСТЬ a=a+e*SGN(y-1-g)*(g>0)+(g=0): НАПЕЧАТАТЬ AT y,x;" ";AT g,h;" ": LET f=-f*(z<.05)+f*(z>=.05): ПЕРЕЙТИ К 3
Подпрограмма печати статуса игры
Подпрограмма в строке 10 сначала проверяет, превышает ли текущая оценка S максимальную оценку T, и соответствующим образом обновляет T. Затем он печатает текущий счет, высокий балл, количество оставшихся жизней игрока и напоминание об управлении игрой в момент времени t.он внизу экрана. Перед возвратом вызывающей стороне цвет границы восстанавливается до синего.
10 LET t=t*(t>s)+s*(t<=s): ПЕЧАТЬ #1;БУМАГА 6;ЧЕРНИЛА 1;AT 0,0;"Sc:";s,"Hi:" ;t,"Жизни:";l,"
Подтверждение длины строк программы
---------------------------
Заменив каждый BASIC-токен одним символом и удалив лишние пробелы, каждая строка в итоговом исходном коде не превысит ограничение в 80 символов:
1B1:b6:C0:v:fi=1 F7:pIi+6,i+6;Xi;"БАСТИЛУДА":ni:lr=21:lc=15:uO25102=128 Glt=0
2X4:lv=0:lw=1:la=10:lb=15:le=.2:lf=-.2:lg=0:lh=0:ll=2:ls=0:h10: m0:b6:v:h10
3lx=Rc:ly=Rr:lg=Ra:lh=Rb:pIy,x;U(61+Fv+(v=0));X3;Ig,h;U(61+Ff+(f=0) ))):э<>x Gg6
4ug=y-1 Gb3:t:ll=l-1:lr=21:lc=8+16*(h<15):lv=0:Z.5,-23:pIy,x;" ":h10:g1+2*(l>-1)
5uy=g-1 Gb4:t:ls=s+1:la=T*22:lb=T*32:le=Ge+.05:lf=Gf+.05:Z.1,12:pIg, ч;" ":h10:g3
6lk$=XEY$:lv=v+.2*(k$="p")*(v<1)-.2*(k$="o")*(v>-.8): ue>.95 Gle=.95
7lw=-1*(k$="z")*(y>0) +(k$<>"z")*(y<21)+(y=0):lz=T:uy =g Yh=x Glf=-f:lv=-Ff*Gv
8lc=c+v:lc=c-32*(c>=32)+32*(c<0):lb=b+f:lb=b-32*(b>=32)+32 *(b<0):lr=r+w
9la=a+e*F(y-1-g)*(g>0)+(g=0):pIy,x;" ";Ig,h;" ":lf=-f*( z<.05)+f*(z>=.05):g3
10lt=t*(t>s)+s*(t<=s):p#1;C6;X1;I0,0;"Sc:";s,"Hi:";t,"Жизни :";l,"
Поэтому Bastilude подходит для участия в конкурсе BASIC 10 Liner Contest в категории PUR-80.
Ссылки
Статья в Википедии о Joust: https://en.wikipedia.org/wiki/Joust_(video_game)
Руководство по Joust Atari 2600: https://archive.org/details/Joust_1982_Atari/
Как скачать Bastilude by Marco's Retrobits через торрент
Всего несколько простых шагов:
- Устанавливаем программу μTorrent, через которую мы будем скачивать торренты
- Выбираем и скачиваем подходящий торрент-файл репака Bastilude by Marco's Retrobits
- Двойным кликом открываем скаченный файл, программа μTorrent запустится автоматически и предложит выбрать место для сохранения дистрибутива.
- После того как репак скачается, запускайте его. Начнется установка и... это все, приятной игры!