Эволюция ПО в разработке игр на практике: 1981 — IBM PC, Софт и игра
Конфигурация
Несмотря на то, что IBM PC можно было приобрести в одном из двух вариантов, более дешевый не имеет смысла из-за серьезных ограничений по носителям(только кассеты) и возможностям BASIC (только текстовый режим без возможности работы с цветом). Для работы же с версией BASIC на дискете требовалась конфигурация на 48КБ из которых 32КБ забирала система при загрузке PC DOS с дискеты. Также ревизия 1981 года была ограничена 64кб памяти, а вариант на 256кб появился только в следующем году. Это, к слову, в некоторой мере объясняет большую редкость софта под IBM PC на кассетах будь то любительский или коммерческий (строго говоря, он редок и для TRS-80 c Apple II, но хотя бы для последнего известно некоторое количество игр в таком формате). Потому практически все ранние игры для IBM PC рассчитаны под конфиг с 48КБ базовой памяти. Дополнительные 16КБ кажутся относительно дешевыми при таких условиях, мышей еще не было (первая для IBM PC будет только в 1983 году), а джойстик можно будет приобрести потом (к этому времени оные формата Atari VCS/2600 - стик с одной кнопкой - стали стандартом и был доступен вариант известных под термином пэдл (paddle) для подобий Pong и Breakout).
Документация
За годы с момента выхода IBM PC полный комплект документации за 1981 год до сих не оцифрован. Из нее наиболее интересным является руководство по BASIC, включающее в том числе раздел с описанием команд.
Однако, оцифровано руководство в ревизии за май 1982 года (BASIC_1.1_May82), которое допустимо использовать, так как правки не значительны и со связанными с ними ситуациями вряд ли придётся столкнуться в ходе использования. Источником примеров программ и игр могут быть книги-сборники 101 BASIC Computer Games (первое издание - 07.1973, издание за март 1975 года) и BASIC Computer Games с More BASIC Computer Games (1978 и 1979 годы соответственно).
Софт
В сущности, в комплекте PC DOS из коробки был доступен только BASIC, а VisiCalc нужно было приобретать отдельно. Рассматривать последний смысла нет, так как оный к моменту выпуска IBM PC был доступен и на TRS-80 и смысла приобретать ту же программу для другой системы смысла не имело. Также самая ранняя версия VisiCalc для IBM PC доступна на Winworld, но не эмулируется ни в одном эмуляторе из-за специфической защиты от копирования , которая работает на секторно-байтовом уровне и ни одна реализация чтения образов дискет не учитывает такие особенности (в отличие от самих форматов, из которых можно произвести физическую запись на дискету, работоспособную на реальном железе). Чуть более поздняя версия заработала в Dosbox-X, а в PCBox происходит зависание (возможно, нужно больше 64КБ). Таким образом, последующая информация будет про BASIC.
Особенности и использование BASIC
Некоторые нюансы работы:
-
Произвольно редактировать нельзя: только последовательная построчная запись (компенсация — группировать строки особым образом и оставлять место для новых, так как BASIC умеет их подставлять последовательно: если добавить LINE 881 <Код>, то она встанет между 880 и 882 без участия пользователя).
-
Сохранение на кассету происходит только один раз, перезапись изменения не учитывает (компенсация — сделать новый образ кассеты и делать новое сохранение на неё).
-
Подставить уже готовый к загрузке.BAS файл (блокнот→ dosbox‑x → PCBox) нельзя: либо портятся или неверно интерпретируются строки в файле или обрабатывается только часть строк. Потому вводить только самостоятельно в эмуляторе (с другой стороны плюс — вникаешь в ход работы строк по ходу перепечатывания).
-
Использовать EDLIN для редактирования.BAS файла нельзя: он неправильно читает данные.
-
Нельзя произвольно редактировать строку: если в строке есть ошибка, то заменять нужно всю строку от её места (хинт — для замены одного символа на другой достаточно дойти до оного и сразу нажать на одну из нужных клавиш клавиатуры — старый символ заменится на новый).
-
Нельзя после загрузки.BAS файла с дискеты пересохранить на другую, только на ту же (компенсация — заранее сделать новую чистую дискету и отформатировать её; скопировать файл образа чистой дискеты переименовав её).
-
Нельзя залупить музыку (команды SOUND, PLAY).
-
Реализовать 160×100×16 возможно только через ассемблер (BASIC 1.x не поддерживает DATA).
-
Сохранение лучше делать в формате 'SAVE«TEST.BAS»,A'. без A будет сохранение в бинарном формате.
Приятный бонус - можно использовать BASIC в качестве простейшего псевдо-текстовика.
Нюансом в написании кода является использование нейросетей с последующей правкой в случае необходимости.
Программы
CP437 Draw (CP437DRW)
Простая рисовалка в текстовом режиме 80х25 с поддержкой цвета. Запросы (Qwen3-Max) - 1, 2.
10 REM CP437 Draw Tool
20 SCREEN 0,1:WIDTH 80:KEY OFF:CLS
30 COLOR 15,0
40 CX=2:CY=2:CC=15:CH=32
50 GOSUB 500
60 REM Main Loop
70 LOCATE CY,CX
80 A$=INKEY$:IF A$="" THEN 80
90 IF A$=CHR$(27) THEN CLS:COLOR 7,0:END
100 REM Char navi
110 IF A$="C" OR A$="c" THEN CH=(CH+1) MOD 255
120 IF CH=12 THEN CH=13:REM Skip char
130 IF A$="+" THEN CH=(CH+16) MOD 255
140 IF A$="=" THEN CH=127
150 IF A$="-" THEN CH=0
160 REM Color change
170 IF A$="Z" OR A$="z" THEN CC=(CC+1) MOD 16
180 REM Char place
190 IF A$=" " AND CH<>12 THEN COLOR CC,0:LOCATE CY,CX:PRINT CHR$(CH);
200 REM Arrow keys
210 IF A$=CHR$(0)+"H" THEN CY=CY-1:IF CY<2 THEN CY=2
220 IF A$=CHR$(0)+"P" THEN CY=CY+1:IF CY>24 THEN CY=24
230 IF A$=CHR$(0)+"K" THEN CX=CX-1:IF CX<2 THEN CX=2
240 IF A$=CHR$(0)+"M" THEN CX=CX+1:IF CX>78 THEN CX=78
250 REM Save/Load
260 IF A$="P" OR A$="p" THEN GOSUB 700
270 IF A$="S" OR A$="s" THEN GOSUB 700
280 IF A$="R" OR A$="r" THEN GOSUB 800
290 GOTO 70
500 REM Draw border
510 COLOR 7,0
520 LOCATE 1,1:PRINT CHR$(201);
530 LOCATE 1,79:PRINT CHR$(187);
540 LOCATE 25,1:PRINT CHR$(200);
550 LOCATE 25,79:PRINT CHR$(188);
560 FOR Y=2 TO 24
570 LOCATE Y,1:PRINT CHR$(186);
580 LOCATE Y,79:PRINT CHR$(186);
590 NEXT Y
600 FOR X=2 TO 78
610 LOCATE 1,X:PRINT CHR$(205);
620 LOCATE 25,X:PRINT CHR$(205);
630 NEXT X
640 RETURN
700 REM Save
710 DEF SEG=&HB800
720 BSAVE "IMG.SAV",0,&HFA0
730 DEF SEG
740 OPEN "IMG.VAR" FOR OUTPUT AS #1
750 PRINT #1,CX,CY,CC,CH
760 CLOSE #1
770 PRINT"SAVED!"
780 RETURN
800 REM Load
810 ON ERROR GOTO 900
820 DEF SEG=&HB800
830 BLOAD "IMG.SAV",0
840 DEF SEG
850 OPEN "IMG.VAR" FOR INPUT AS #1
860 INPUT #1,CX,CY,CC,CH
870 CLOSE #1
880 GOSUB 500
890 RETURN
900 PRINT"No save found!":FOR T=1 TO 1000:NEXT T:RESUME NEXT
Примеры рисунков:
Music Maker (MUSMAKE)
Простая программа для набора нот для PLAY и SOUND. Запрос.
10 REM PLAY/SOUND Command Explorer
20 DEFINT F,D
30 ON ERROR GOTO 400
40 CLS 50 PRINT"IBM PC BASIC PLAY/SOUND TESTER"
60 PRINT"------------------------------"
70 PRINT"Avaliable PLAY commands:"
80 PRINT" A-G[#|+|-] : Notes (e.g., C+, D#)"
90 PRINT" O<n> : Octave (0-6, default=4)"
100 PRINT" N<n> : Note number (0-84, 0=rest)"
110 PRINT" L<n> : Length (1-64, e.g., L4=quarter note)"
120 PRINT" P<n> : Pause (rest) of length n"
130 PRINT" T<n> : Tempo (32-255 BPM, default=120)"
140 PRINT" . : Dotted note (e.g., C.)"
150 PRINT" MF/MB : Music Foreground/Background"
160 PRINT" MN/ML/MS : Normal/Legato/Staccato"
170 PRINT" X<var> : Execute string variable (e.g., XMYTUNE$)"
180 PRINT
190 PRINT"SOUND: freq (37-32767), duration (0-65535 ticks; 18.2/sec)"
200 PRINT
210 GOSUB 300
220 PRINT
230 PRINT"Press M=PLAY, S=SOUND, E=EDIT, ESC=QUIT"
240 K$=INKEY$:IF K$="" THEN 240
250 IF K$="M" OR K$="m" THEN PLAY PLAYSTR$
260 IF K$="S" OR K$="s" THEN SOUND FREQ%,DUR%
270 IF K$="E" OR K$="e" THEN GOSUB 300
280 IF ASC(K$)=27 THEN SYSTEM
290 GOTO 240
300 REM Input
310 INPUT"Enter PLAY string";PLAYSTR$
320 INPUT"Enter SOUND freq,dur (e.g., 440,18)";FREQ%,DUR%
330 RETURN
400 REM Error Handler
410 PRINT"ERROR";ERR;"LINE";ERL
420 PRINT"Press any key to continue..."
430 WHILE INKEY$="":WEND
440 RESUME 40
Игра
В качестве теста попробовал сделать простенькую реализацию Space Invaders. Для этого документ по BASIC 1.10 перевел через Abbyy FineReader в текстовый формат (размер - 445КБ), а также сохранил вариант в RTF. После этого полученный текстовый файл с примерами на .BAS (Donkey.BAS, Sample.BAS) был загружен в Google Gemini 3 (Pro-версия, доступна минимум 1 раз в сутки).
Запрос (английский): "Lets write simple Space Invaders clone game under BASIC for IBM PC which will work on the earliest one models with 16-48-64 kbytes.I've provide BASIC documentation and sample game in BASIC code.Take a note - .BAS file size limit must be not exceed 16000 bytes. "
Ссылки - Google Gemini 3, Qwen3-Max (правки).
Итоговый код после ряда правок:
10 REM IBM Invaders
20 DEFINT A-Z:KEY OFF:CLS
30 SCREEN 1,0:COLOR 3,1
40 DIM SHIP%(50), ALIEN%(50), MISSILE%(10)
50 PX=150:PY=180:BX=0:BY=0:BF=0
60 AD=2:AC=5:SC=0
70 DIM AX(5),AY(5),AS(5)
80 CLS:PRINT""
90 LINE(0,8)-(8,0),1:LINE-(16,8),1:LINE-(0,8),1:PAINT(8,4),1,1
100 GET(0,0)-(16,8),SHIP%:CLS
110 DRAW"BM0,0 D8 R12 U8 L12 M+6,6 M+6,-6":PAINT(2,2),2,3
120 GET(0,0)-(12,8),ALIEN%:CLS
130 LINE(0,0)-(2,6),3,BF:GET(2,0)-(0,6),MISSILE%:CLS
140 WIDTH 40:CLS:LOCATE 8,10:PRINT"IBM INVADERS"
150 LOCATE 10,8:PRINT"Arrows to Move":LOCATE 11,8:PRINT"Space to Fire"
160 LOCATE 15,8:PRINT"Press SPACE to Start"
170 I$=INKEY$:IF I$="" GOTO 170
180 IF I$<>" " GOTO 170
190 CLS
200 FOR I=0 TO AC-1:AX(I)=40+I*50:AY(I)=10:AS(I)=1:NEXT
210 PUT(PX,PY),SHIP%,PSET
220 REM Main Loop
230 K$=INKEY$
240 IF K$=CHR$(27) GOTO 900
250 IF LEN(K$)=2 THEN K$=RIGHT$(K$,1)
260 IF K$="K" THEN PX=PX-5:IF PX<0 THEN PX=0
270 IF K$="M" THEN PX=PX+5:IF PX>300 THEN PX=300
280 IF K$=" " AND BF=0 THEN BF=1:BX=PX+7:BY=PY-5:SOUND 1000,1
290 PUT(PX,PY),SHIP%,PRESET
300 IF BF=0 GOTO 350
310 PUT(BX,BY),MISSILE%,PRESET
320 BY=BY-32
330 IF BY<0 THEN BF=0:GOTO 350
340 PUT(BX,BY),MISSILE%,PSET
350 M=0
360 FOR I=0 TO AC-1
370 IF AS(I)=0 GOTO 430
380 PUT(AX(I),AY(I)),ALIEN%,PRESET
390 AX(I)=AX(I)+AD
400 REM Collision: bullet vs alien
410 IF BF=1 AND BX+2>=AX(I) AND BX<=AX(I)+12 AND BY+6>=AY(I) AND BY<=AY(I)+8 THEN AS(I)=0:BF=0:PUT(BX,BY),MISSILE%,PRESET:SC=SC+10:SOUND 37+RND*200,2:GOTO 430
420 PUT(AX(I),AY(I)),ALIEN%,PSET
430 IF AS(I)=1 AND (AX(I)>300 OR AX(I)<5) THEN M=1
440 NEXT I
450 IF M=1 THEN AD=-AD
460 FOR J=0 TO AC-1
470 IF AS(J)=1 THEN PUT(AX(J),AY(J)),ALIEN%,PRESET
480 AY(J)=AY(J)+1:PUT(AX(J),AY(J)),ALIEN%,PSET
490 NEXT J
500 LOCATE 1,1:PRINT"SCORE:";SC
510 IF AY(0)>160 THEN GOTO 950
520 IF SC=50 THEN CLS:PRINT"YOU WIN!":GOTO 990
530 FOR D=1 TO 50:NEXT D
540 GOTO 220
900 CLS:SCREEN 0:WIDTH 80:SYSTEM
950 CLS:LOCATE 10,15:PRINT"GAME OVER":SOUND 100,10
960 FOR I=1 TO 2000:NEXT:GOTO 140
990 END
Скриншот:
Баги:
- Противники спускаются на один пиксель сразу по осям X и Y.
- Не очищается предыдущая позиция при перемещении на новое место (касается всех объектов - корабля игрока, ракеты и противников).
- Противники при спуске оставляют шлейф.
- Ракета может пролететь мимо противника несмотря на то, что визуально она проходит через его спрайт.
- От ракеты остается полоска после прохождения позиции.
- После попадания противник не стирается полностью: его рамка продолжает падать, но прямо вниз (хотя может выглядеть как визуализация обломков после взрыва).
Костыли:
- Фон в цвете шлейфа.
Что можно было бы исправить:
- Спуск противников по X до конца линии, а потом спуск по Y до достижения конца линии по X.
- Коррекция скорости ракеты, чтобы её линии попадания совпадали с линиями движения противников.
Что можно было бы добавить:
- Жизни.
- Отстрел противниками.
- После первого попадания от противников остаются обломки, которые нужно уничтожать отдельно.
На мой взгляд, исправить баги и получится вполне себе donationware за $4.99, который мог распространяться через BBS или быть опубликован в каком-нибудь журнале в виде листинга.
Скачать - github
Возможные выводы
В целом, несмотря на некоторые неудобства, опыт написания под BASIC на оригинальном конфиге IBM PC образца 1981 года интересный. Сделать нечто динамичное теоретически возможно, особенно если разобраться с нюансами рисования и отображения графики (Donkey хороший пример такого). Понятно, что для чего-то более комплексного потребуется использовать MASM (для сегментов кода, которые нужно обрабатывать быстро, BASIC такое допускает через CALL), а в идеале вовсе писать на C. Однако в 1981 году реализации C под IBM PC еще не было - самые ранние вышли уже в 1982 году, но доступны те, что датируются 1983 годом.
Также, по моим впечатлениям, BASIC похож на Python (построчный синтаксис исполняющийся последовательно, но при этом предусматривающий некоторое распараллеливание операций через GOSUB и GOTO), только проще и по функционалу, и по возможностям.