ГЛАВА 14 Действующий пример видеоигры
В этой главе мы изучаем возможности бейсика для программирования видеоигр. Мы приходим к выводу, что программы на бейсике дороги; если учесть, что, как правило, игроки довольно быстро теряют интерес к программам, то естественно, что лица, имеющие навыки программирования на бейсике, предпочитают не писать программы небольших игр самостоятельно, а покупать только программы сложных игр, написанные на машинном коде. На листинге 14.1 приведена программа, не использующая подпрограмм написанных на машинном коде. Для создания таких программ от программиста требуется довольно высокая квалификация. Игра называется ISLAND DEFENCE ("оборона острова") и относится к разряду игр "перестреляй их", однако методы, использованные при составлении программы, пригодны для создания игр типа "мяч-бита" (таких, как теннис), или тактических игр (таких, как PACMAN).
Описание игры
На экране изображен зелёный остров с небольшим холмом, тёмно-синее море и голубое небо с жёлтым солнцем и белой тучкой. На острове имеются три дерева и участок светло-голубого бетона, на котором нарисована палатка. Из палатки выходит человек, подходит к стрелку, отдаёт ему 20 снарядов и возвращается в палатку.
Вражеские аэропланы появляются в небе, перелетают через холм и бомбят лагерь, который защищает стрелок, пытаясь выстрелами сбить аэропланы. Во время атаки аэроплан либо сбивают, либо он бомбит лагерь.
После каждого попадания бомбы размер тента уменьшается. После 14 попаданий тент исчезает, и самолеты бомбят огневую точку, после уничтожения которой рамка графического поля становится жёлтой, и на экране появляется та же сцена. В конце каждого рейда самолёт пролетает через тучу над орудием и покидает экран. Боевые запасы пополняются после 20-ти налётов. Если орудие разбомблено третий раз, то экран становится красным, и игра начинается снова.
Нажатием клавиш от "1" до "7" орудие устанавливается в одно из семи положений; после нажатия клавиши X происходит выстрел. Из-за ограничений, накладываемых медленной работой программы, на экране могут одновременно находиться только один самолёт и снаряд.
Для лучшего понимания материала этой главы мы рекомендуем вам загрузить программу на листинге 14.1 и запустить её. Программа попросит вас сначала загрузить набор специальных символов, затем подпрограмму "GAMESET" (эта подпрограмма должна рисовать тент, человека и т.д.), подпрограмму "BACKGROUND" (должна рисовать пейзаж), после чего можно начать игру.
Текст программы хорошо прокомментирован, так что нет необходимости объяснять принцип работы программы. Мы ограничимся изложением общего подхода к созданию таких игр.
ВНИМАНИЕ! Листинги с программами "GAMESET" и "BACKGROUND" в настоящем издании не приведены по не зависящим от издательства причинам.
Передний план
Перед написанием программы следует тщательно продумать схему игры. Сначала набросайте грубый эскиз на клетчатой бумаге, на котором должны быть обозначены неподвижные объекты и области, которые будут пересекаться подвижными объектами (например, те символьные блоки, которые в какой-нибудь момент будут включены в число блоков, из которых состоит изображение самолёта). Вы должны убедиться, что игровое поле полностью умещается на экране и что ни при каких обстоятельствах в символьном блоке не используются одновременно более двух цветов. После того, как вы будете четко представлять, как выглядит игровое поле, вам следует приступить к созданию объектов на переднем плане (в нашем случае - взрывы, самолёты, люди), т.е. движущихся объектов. Самая быстрая из команд бейсика, с помощью которой можно разместить на экране большой объект - это команда PRINT, поэтому мы создаем изображение объектов с помощью программы "CHARACTER GENERATOR" из определенного нами набора символов, для того, чтобы получить в точности то изображение необходимой величины и повторно отредактировать не удовлетворяющие вас символы. Возможно, что вам придется добавить куски вашей программы к концу программы CHARACTER GENERATOR (опция 7, глава 5), что позволит вам увидеть объекты в действии до того, как найдена их окончательная форма.
Упражнение 14.1
Добавьте опцию к программе CHARACTER GENERATOR с тем, чтобы стало возможным редактировать один символ из набора символов. Эта опция должна помещать восемь двоичных значений редактируемого символа в заданные ячейки дисплейного файла; например, два блока, из которых состоит самолёт, когда он летит горизонтально и направо.
LISTING 14.1
9 REM INITIALISE ROUTINES TO ALLOW USE OF ALTERNATE CHARACTER SET.
10 CLEAR 62294: INK 0: PAPER 7: BORDER 7: FLASH 0
20 DIM S(6): FOR I=1 TO 6: READ S(I): NEXT I
30 DATA 15360,62039,62807,63575,64343,64848
40 LET SET=50: LET S=1: GO SUB SET: GO TO 200
50 REM SET/CHANGE TO SET S
51 REM IN : S
60 LET HI=INT(S(S)/256): LET LO=S(S)-HI*256
70 POKE 23606,LO: POKE 23607,HI: RETURN
79 REM LOAD IN GAME CHARACTERS FOR SET 2.
80 REM CHARLOAD 90 LET N$="GAMESET"
100 LET S=2
110 INPUT ("LOADING"+N$+CHR$ 6+"START TAPE, THEN PRESS ENTER.")
120 LOAD N$ CODE (S(S)+256),768: RETURN
200 REM MAIN PROGRAMM
209 REM INITIALISE VARIABLES POINTING TO ROUTINES.
210 LET CHARLOAD=80: LET LOAD=4600: LET CREATE=5000: LET CREDIT=5500: LET CHAR=5600
220 LET KEYBOARD=500: LET CAMP=700: LET STATUS=800: LET PLANE=980
230 LET RELOAD=1500: LET AMMO=1900: LET MISSILE=2000: LET EXPLODE=2500
240 LET BOMBSAMP=3500: LET BOMBGUN=3000: LET HISCORE=5700: LET HSC=0
249 REM IF CHARACTER SET IS NOT IN PLASE LOAD IT.
250 IF PEEK 62303<>110 THEN GO SUB CHARLOAD 258 REM PRINT NAMES ON BOTTOW TWO LINES.
260 GO SUB LOAD: GO SUB CREATE: GO SUB CREDIT
269 REM MAKE A COPY OF COLOUR ATTRIBUTES FOR SCREEN.
270 DIM A(704): FOR I=1 TO 704: LET A(I)=PEEK(22527+I): NEXT I
279 REM PREPARE STRINGS FOR USE BY DISPLAY ROUTINES.
280 LET S$="SCORE": LET B$="BASE"
290 FOR I=1 TO 4: LET S$=S$+CHR$ 8: LET B$=B$+CHR$ 8: NEXT I
300 DIM N$(9): LET N$="ABCDEFGH"
309 REM START/RESTART FOR GAME.
310 BRIGHT 1: PAPER 8: INK 8: OVER 0
319 REM RESET SCORE AND NO. OF BASES, PRINT OUT SCORE LINE
320 LET SC=0: LET BS=3: GO SUB STATUS
329 REM REMOVE REMAINING AMMUNITION AND REMOVE FLASH FROM GUNNERS SGUARE.
330 PRINT AT 17,5;" ": PRINT AT 18,5;" ": PRINT AT 16,3;" "
339 REM RESTORE COLOUR ATTRIBUTES FROM COPY.
340 FOR I=1 TO 704: POKE 22527,A(I): NEXT I
349 REM POINT NEW TENT AND PUNNER UPDATE SCORE LINE, RELOAD, AMMUNITION.
350 GO SUB CAMP: GO SUB STATUS: GO SUB RELOAD
358 REM PREPARE FOR MAIN LOOP OF PROGRAM SET "P" TO TOP OF "PLANE" CASCADE.
359 REM SET "M" TO "MISSILE" READY STATE, SET "K" TO KEYBOARD ROUTINE.
360 LET P=PLANE: LET M=MISSILE: LET K=KEYBOARD
369 REM START A NEW WAVE OF 20 AIRPLANES.
370 LET AR=20
379 REM START OF MAIN LOOP
380 GO SUB P: OVER 1: GO SUB M: OVER 0: GO SUB K
389 REM JUMP OUT OF LOOP.
390 IF DEAD THEN GO TO 420
399 REM IF MORE AIRPLANES TO COME KEEP LOOPING.
400 IF AR>0 THEN GO TO 380
409 REM IF END OF PLANES THEN RELOAD AND START NEW WAVE, CONTINUE LOOPING.
410 GO SUB RELOAD: GO TO 370
419 REM MAKE SURE PLANE IS GONE, IF YOU HAVE ANY BASES LEFT USE THE NEXT ONE.
420 INK 0: PRINT AT 12,0;" ": IF BS>1 THEN LET BS=BS-1: GO TO 350
429 REM GAME OVER SO FLASH BORDER AND TURN SCREEN BLOOD RED.
430 OVER 1: FOR I=1 TO 22: BEEP 0.005,RND*30-15: BORDER RND*7
440 FOR J=1 TO 2: PLOT 0,(22-I)*8: DRAW BRIGHT 1;PAPER 2;INK 2;255,0
450 NEXT J: NEXT I: BORDER 7
460 OVER 0
469 REM CHECK WHETHER YOU BEAT THE HISCORE THEN RESTART GAME.
470 IF SC>HSC THEN GO SUB HISCORE 480 PAUSE 200: GO TO 310
500 REM KEYBOARD
509 REM IF NO KEY PRESSED WHEN ROUTINE CHECKS THEN YOU MISSED YOUR CHANCE.
510 LET A$=INKEY$: IF A$="" THEN RETURN
518 REM THE FIRE KEY IS PRESSED
519 REM IF YOU'RE NOT OUT OF MISSILES AND A MISSILE IS READY THEN FIRE.
520 IF A$="X" OR A$="X" THEN IF M=MISSILE AND NOT OUT THEN LET M=F: LET M$=F$: GO SUB AMMO: OVER 1: GO SUB M: OVER 0: GO TO 550
529 REM IF THE KEY IS NOT "I" TO "7" THEN WRONG KEY PRESS, IGNORE IT.
530 IF A$>"7" OR A$<"1" THEN RETURN
538 REM CALCULATE WHICH ROUTINE IS USED IF MISSILE IS FIRED IN THIS DIRECTION.
539 REM SET STRING WHICH IS USED FOR MISSILE AND CHANGE GUN DIRECTION.
540 LET F=2000+10*VAL A$: LET F$=CHR$(83+VAL A$) 550 PRINT AT 16,3;F$ 560 RETURN 700 REM CAMP
709 REM PRINT NEW GUNNER AND TENT, RESET BORDER TO WRITE.
710 PRINT AT 17,3;"Z": BRIGHT 0: BORDER 7: PRINT AT 16,23;"VW": PRINT AT 17,23;"X,Y": BRIGHT 1
718 REM SET HEIGHT OF TENT TO 14, RESET TRUTH-FLAGS,
719 REM USE KEYBOARD ROTUINE TO INITIALISE GUN POSITION.
720 LET YT=14: LET NIT=0: LET DEAD=0: LET A$="3": GO TO 540 800 REM STATUS
809 REM USE SET 1 TO PRINT OUT SCORE AND NO, OF BASES LEFT THEN BACK TO SET 2.
810 LET S=1: GO SUB SET
820 PRINT AT 21,0;S$;SC,B$;BS 830 LET S=2: GO SUB SET 840 RETURN 980 REM PLANE
989 REM ENSURE THAT "BOMBGUN" POINTER ALWAYS STARTS AT TOP OF CASCADE.
990 PRINT AT 15,5;" ": PRINT AT 15,4;" ": PRINT AT 17,3;"Z": LET BOMBGUN=3000
999 REM CHANGE POINTER, IF RESULT IS OVER 1000 THEN PLANE WILL BE LAUNCHE1.
1000 LET P=991+INT(RND*11): RETURN
1009 REM LAUNCH AIRCRAFT, START POINTER GOING DOWN CASCADE, LOAD BOMB.
1010 LET AR=AR-1: LET P=1020: LET BOMB=1: RETURN
1019 REM MOVE PLANE ONE PLACE TO RIGHT.
1020 PRINT AT R,C;" IJ": LET C=C+1: IF C<10 THEN RETURN
1029 REM IF PLANE IS OVER 10 COLUMNS ONTO SCREEN MOVE POINTER DOWN.
1030 LET P=1040
1039 REM DIAGONAL DIVE.
1040 PRINT AT R-1,C;" ": PRINT AT R,C;" N": LET R=R+1: LET C=C+1: PRINT AT R,C;"N": IF C<20 THEN RETURN
1049 REM IF OVER 20 COLUMNS ACROSS THEN MOVE POINTER, REMOVE LEFT OVER PLANE.
1050 LET P=1060: PRINT AT R-1,C;" "
1059 REM CALL THE "BOMBCAMP" CASCADE EACH OF THE FIVE TIMES THIS SECTION IS
USED.
1060 GO SUB BOMBCAMP: PRINT AT R,C;" IJ": LET C=C+1: IF C<25 THEN RETURN
1069 REM MOVE POINTER DOWN AND START CURVE UP TOWARDS CLOUD.
1070 LET P=1080
1080 PRINT AT R,C;" ": LET R=R-1: LET C=C+1: PRINT AT R,C;"KL": IF C<28 THEN
RETURN
1090 LET P=1100: PRINT AT R,C;" ": LET C=C+1
1100 PRINT AT R+1,C;" ": PRINT AT R,C,"O": LET R=R-1: PRINT AT R,C;"O": IF R>7 THEN RETURN
1110 LET P=1120: PRINT AT R+1,C;" "
1120 PRINT AT R,C;" ": LET R=R-1: LET C=C-1: PRINT AT R,C;"KL": IF R>3 THEN
RETURN
1130 LET P=1140
1139 REM FLY INTO CLOUD, PLANE STILL MOVES NORMALLY BUT YOU CAN'T SEE IT.
1140 PRINT AT R,C;"IJ ": LET C=C-1: IF C>11 THEN RETURN 1150 LET P=1160: PRINT AT R,C;" "
1159 REM START DIVE TO WARDS GUNNER.
1160 PRINT AT R,C;" ": LET R=R+1: LET C=C-1: PRINT AT R,C;"M": PRINT AT R+1,C;"M": IF R<6 THEN RETURN
1170 LET P=1180
1180 PRINT AT R,C;" ": LET R=R+1: PRINT AT R,C;"P": PRINT AT R+1,C;"P": IF R<8 THEN RETURN
1189 REM THIRD SECTION OF DIVE CHECK AND ERASE POSSIBLE LEFT OVER MISSILE.
1190 LET P=1200: IF X<>9 AND Y<>7 THEN PRINT AT 7,9;" "
1200 PRINT AT R,C;" ": LET R=R+1: LET C=C-1: PRINT AT R,C;"M": PRINT AT R+1,C;"M": IF R<11 THEN RETURN
1210 LET P=1220: PRINT AT R,C;" ": LET R=R+1
1219 REM LAST SECTION OF FLIGHT, CALL BOMBGUN CASCADE EACH TIME.
1220 GO SUB BOMBGUN: LET C=C-1: PRINT AT R,C;"IJ ": IF C>0 THEN RETURN
1229 REM LAST TWO PARTS OF CASCADE DEAL WITH PLANE GOING OF SCREEN.
1230 LET P=1240: PRINT AT R,C;"J ": RETURN
1239 REM RESET PLANE'S ROW TO 2 AND SET POINTER BACK TO TOP OF CASCADE.
1240 PRINT AT R,C;" ": LET R=2: LET P=PLANE
1250 RETURN 1500 REM RELOAD
1509 REM IT THE CAMP IS DESTROYED THEN DONT RELOAD AMMUNITION IF NIT THEN
RETURN
1519 REM EXPLICIT INSTRUCTIONS FOR ANTIMATION OF FIGURE.
1520 BRIGHT 0: LET R=18
1529 REM WALK FROM TENT TO TREES
1530 FOR C=24 TO 19 STEP -1: PRINT AT R,C;"S": PRINT AT R+1, C;"S": BEEP 0.01,15: PAUSE 5
1540 PRINT AT R,C;"R":PRINT AT R+1,C;" ": PAUSE 3 1550 PRINT AT R,C;" ":PRINT AT R+1,C;" ": NEXT C
1559 REM USE OVERPRINTING SO THAT TREES AREN'T DAMAGED AS FIGURE GETS CLOSE.
1560 OVER 1: PRINT AT R,18;"S": PRINT AT R+1,18;"S": BEEP 0.01,-15: PAUSE 5: PRINT AT R,18;"S": PRINT AT R+1,18;"S"
1570 PRINT AT R,18;"R": PRINT AT R+1,18;" ": PAUSE 3: PRINT AT R,18;"R": PRINT AT R+1,18;"R"
1579 REM MIKE NOISES AS THOGH FIGURE GOES BEHIND TREE.
1580 FOR J=1 TO 2: BEEP 0.01,-15: PAUSE 11: NEXT J
1589 REM SHOW TEET VWERGING FROM BEHIND TREE.
1590 PRINT AT R+1,15;"S": BEEP 0.01,15
1600 PRINT AT R+1,15;"R": PAUSE 3: PRINT AT R+1,15;"R"
1609 REM SHOW WHOLE FIGURE COMING OUT OF TREE.
1610 PRINT AT R,14;"S": PRINT AT R+1,14;"S":BEEP 0.01,-15: PAUSE 5: PRINT AT R,14;"S": PRINT AT R+1,14;"S"
1620 PRINT AT R,14;"R": PRINT AT R+1,14;"R": PAUSE 3: PRINT AT R,14;"R": PRINT AT R+1,14;"R"
1629 REM WALK FROM TREE TO END OF STRIP.ONTO GRASS AT SOLUMN 8 WITH BRIGHT ON.
1630 OVER 0: FOR C=13 TO 8 STEP -1: BRIGHT (C=8)
1640 PRINT AT R,C;"S": PRINT AT R+1,C;"S": BEEP 0.01,-15: PAUSE 5 1650 PRINT AT R,C;"R": PRINT AT R+1,C;"R": PAUSE 3 1660 PRINT AT R,C;" ": PRINT AT R+1,C;" ": NEXT C
1669 REM PRINT FIGURE AT COLUMN 7 READY TO REFILL AMMO DUMP.
1670 PRINT AT R,C;"R": PRINT AT R+1 ,C;"R"
1679 REM REFILL AMMO DUMP, WITH SOUND EFFECTS.
1680 FOR G=6 TO 5 STEP -1: FOR H=18 TO 17 STEP -1: FOR N=2 TO 9 1690 PRINT AT H,G;INK 3;N$(N): BEEP 0.02,H+G-N
1700 NEXT N: NEXT H: NEXT G
1709 REM REMOVE FIGURE FROM COLUMN 7.
1710 PRINT AT R,C;" ": PRINT AT R+1,C;" "
1719 REM RESET AMMUNITION PRINT AND TRUTH FLAGS.
1720 LET N=8: LET OUT=0: LET H=17: LET G=6
1729 REM WALK FROM EN D OF STRIP TO TREE.BRIGH OFF AFTER COLUMN 8.
1730 FOR C=8 TO 13: BRIGHT (C=8)
1740 PRINT AT R,C;")": PRINT AT R+1,C;"+": BEEP 0.01,-15: PAUSE 5 1750 PRINT AT R,C;"(": PRINT AT R+1,C;"*": PAUSE 3 1760 PRINT AT R,C;" ": PRINT AT R+1,C;" ": NEXT C
1769 REM OVER-PRINT AS FIGURE REACHES TREE.
1770 OVER 1: PRINT AT R,14;")": PRINT AT R+1,14;"+": BEEP 0.01,-15: PAUSE 5: PRINT AT R,14;")": PRINT AT R+1,14;"+"
1780 PRINT AT R,14;"(": PRINT AT R+1,14;"*": PAUSE 3: PRINT AT R,14;"(": PRINT AT R+1,14;"*"
1789 REM OVERPRINT LEGS AS THEY GO INTO TREE.
1790 PRINT AT R+1,15;"+": BEEP 0.01,-15
1800 PRINT AT R+1,15;"*": PAUSE 3: PRINT AT R+1,15;"*"
1809 REM MAKE NOISES AS THOUGH IS BEHING TREE.
1810 FOR J=1 TO 2: BEEP 0.01,-15: PAUSE 11: NEXT J
1819 REM OVERPRINT AS FIGURE EMERGES FROM TREE.
1820 PRINT AT R,18;")": PRINT AT R+1,18;"+":BEEP 0.01,-15: PAUSE 5: PRINT AT R,18;")": PRINT AT R+1,18;"+"
1830 PRINT AT R,18;"(": PRINT AT R+1,18;"*": PAUSE 3: PRINT AT R,18;"(":PRINT AT R+1,18;"*"
1839 REM WALK FROM TREE TO TENT.
1840 OVER 0: FOR C=19 TO 24: PRINT AT R,C;")": PRINT AT R+1,C;"+": BEEP 0.01,15: PAUSE 5
1850 PRINT AT R,C;"(": PRINT AT R+1,C;"*": PAUSE 3 1860 PRINT AT R,C;" ": PRINT AT R+1,C;" ": NEXT C
1869 REM RESET ROM AND COLUMN FOR USE BY PLANE ROUTINE.
1870 LET C=0: LET R=2: BRIGHT 1 1880 RETURN
1900 REM AMMO PRINT MISSILE DUMP
1902 REM OUT: OUT
1909 REM TAKE ONE OF AMUNITION DUMP AND CHEK WHETHER OUT OF AMMO.
1910 PRINT AT H,G;N$(N): LET H=N-1
1920 IF N=0 THEN LET N=8: LET H=H+1: IF H=19 THEN LET H=17: LET G=G-1: IF G=4 THEN LET OUT=1
1930 |
RETURN |
|
|
|
|
|
|
|
2000 |
REM MISSILE DIRECTIONS |
|
|
|
|
2009 |
REM REMOVE OLD MISSILE BY OVERPRINTING |
ANDCALCULATE |
2010 |
PRINT |
AT |
Y,X;M$ |
LET |
Y=Y-3 |
LET X=X-2: |
GO |
TO |
2100 |
2020 |
PRINT |
AT |
Y,X;M$ |
LET |
Y=Y-3 |
LET X=X-1: |
GO |
TO |
2100 |
2030 |
PRINT |
AT |
Y,X;M$ |
LET |
Y=Y-3 |
GO TO 2100 |
|
|
|
2040 |
PRINT |
AT |
Y,X;M$ |
LET |
Y=Y-3 |
LET X=X+1: |
GO |
TO |
2100 |
2050 |
PRINT |
AT |
Y,X;M$ |
LET |
Y=Y-3 |
LET X=X+2: |
GO |
TO |
2100 |
2060 |
PRINT |
AT |
Y,X;M$ |
LET |
Y=Y-2 |
LET X=X+2: |
GO |
TO |
2100 |
2070 |
PRINT |
AT |
Y,X;M$ |
LET |
Y=Y-2 |
LET X=X+3: |
GO |
TO |
2100 |
2098 |
REM IF MISSILE IS ON |
SAME COLUMN AS PLANE |
CHECK FOR |
PLANE.
2099 REM IF MISSILE IS CLOSE ENDUNG EXPLODE AND RESET MISSILE TO READY.
2100 IF X=0 THEN IF ABS(Y-R)<2 THEN GO SUB EXPLODE: LET M=MISSILE: GO TO M
2109 REM IF MISSILE IS OFF SCREEN THEN RESET POINTER "M" TO READY
2110 IF X<0 OR Y<0 THEN LET M=MISSILE: GO TO M
2119 REM PRINT MISSILE AT NEW POSITION.
2120 PRINT AT Y,X;M$: RETURN 2200 REM MISSILE/READY TO FIRE 2210 LET X=3: LET Y=16
2220 RETURN 2500 REM EXPLOCE
2508 REM MISSILE HAS HIT PLANE SO BLOW UP PLANE AND ADD TO SCORE.
2509 REM CHECKWHETHER EXPLOSION HAS TAKEN PLACE IN CLOUD OR IN SKY.
2510 OVER 0: LET SKY=(R<>3 OR C<16): IF NOT SKY THEN PRINT AT R,C-1;" "
2519 REM CENTRAL FLASH AND LOW BUZZ, ADD TO SCORE FOR NITTING PLANE.
2520 INK 2: IF SKY THEN PRINT AT R,C;"T"
2530 FOR I=1 TO 5: BEEP 0.01,I-10: BEEP 0.01,-I-10: NEXT I: LET SC=SC+1
2539 REM IF EXPLOSION IS SEEN THEN PRINT CLOUD OF DEBRIS.
2540 IF SKY THEN PRINT AT R-1,C-1;"> <": PRINT AT R,C-1;"S!$": PRINT AT R+1,C-
1;":1
2549 REM NIGH PITCHED WHIZZ.
2550 FOR I=-4 TO 4: BEEP 0.002,(50+ABS I): NEXT I
2559 REM REMOVE ALL TRACE OF EXPLOSION.
2560 INK 0: IF SKY THEN PRINT AT R-1,C-1;" ": PRINT AT R,C-1;" ": PRINT AT R+1,C-1;" "
2569 REM PRINT OUT NEW SCORE LINE,RESET PLANE AND MISSILE POINTERS.
2570 INK 8: GO SUB STATUS: LET M=MISSILE: LET P=PLANE 2580 LET R=2: LET C=0
2590 RETURN 3000 REM BOMB GUN
3009 REM IF CAMP ISN'T DESTROYED OR PLANE HASN'T GOT A BOMB LEFT THEN DON'T
DROP.
3010 IF NOT HIT OR NOT BOMB THEN RETURN
3019 REM PLANE BOMB ON SCREEN AND START POINTER DOWN CASCADE.
3020 PRINT AT 13,5;"." 3030 PRINT AT 13,5;" " 3040 PRINT AT 13,4;" "
LET BOMBGUN=3030: RETURN
PRINT AT 15,4;".": LET BOMBGUN=3040: RETURN PRINT AT 17,3;".": LET BOMBGUN=3050: RETURN 3050 PRINT AT 17,3; FLASH 1;" ": LET BOMBGUN=3060: RETURN
3059 REM CLEAR PLANE AWSY, MAKE SURE ANY MISSILES SHOOT OFF THE SCREEN.
3060 PRINT AT 16,0;" ": OVER 1: FOR I=1 TO 7: GO SUB M: NEXT I
3069 REM FLASH BORDER AND MAKE EXPLODING NOISES.
3070 FOR I=1 TO 50: BORDER RND*7: BEEP 0.01,RND*30-15: NEXT I
3078 REM SET FLAG FOR END OF GUNNER.
3079 REM SET INK TO SKY-BLUE SUBSEQUENT MOVEMENT OF PLANE IS INVISIBLE.
3080 LET READ=1: OVER 0: INK 5 3089 REM RESET CASCADE.
3090 LET BOMBGUN=3000: RETURN 3500 REM BOMB CAMP
3509 REM IF THE CAMP HAS GONE SAVE BOMB FOR THE GUNNER.
3510 IF HIT THEN RETURN
3519 REM MARK BOMB AS DROPPED AND START CASCADE.
3520 LET BOMB=0: PRINT AT 14,21;".": LET BOMBCAMP=3530: RETURN
3530 PRINT AT 14,21;" ": PRINT AT 15,22;BRIGHT 0;".": LET BOMBCAMP=3540: RETURN 3540 BRIGHT 0: PRINT AT 15,22;" "
3549 REM EXPLODE TENT.
3550 PRINT AT 16,23;OVER 1;INK 2;"#S" 3560 PRINT AT 16,23;OVER 1;INK 2;"%$" 3570 LET BOMBCAMP=3580: BRIGHT 1: RETURN
3579 REM REMOVE EXPLOSION FROM TENT.
3580 BRIGHT 0: PRINT AT 16,23;OVER 1;INK 0;"#S" 3590 PRINT AT 17,23;OVER 1;INK 0;"%$"
3600 LET BOMBCAMP=3610: BRIGHT 1: RETURN
3609 REM REMOVE TOP REMAINING LINE OF TENT.
3610 PLOT INVERSE 1;184,33+YT: DRAW INVERSE 1;16,0
3619 REM CHECK WHETHER TENT IS GONE AND RESET BOMBCAMP CASCADE.
3620 LET BOMBCAMP=3500: LET YT=YT-1: LET HIT=(YT=0) 3630 RETURN
4600 REM LOAD
4609 REM LOAD PICTURE FROM TAPE.
4610 LET N$="BACKGROUND"
4620 INPUT (" LOADING"+N$+CHR$ 6+"START TAPE.THEN PRESS ENTER."); LINE X$ 4630 LOAD (N$)SCREEN$ 4640 RETURN
5000 REM CREATE/CHARACTERS
5009 REM MAKE CHARACTERS FOR AMMO DUMP IN USER DEFINED GRAPHICS SET.
5010 LET D=255
5020 FOR I=0 TO 6: FOR J=0 TO 7 5030 LET P=USR "G"-I*8+J 5040 IF J>I THEN POKE P,D 5070 NEXT J: NEXT I 5080 RETURN 5500 REM CREDIT
5509 REM POINT ON BOTTOW TWO LINES.
5510 DEF FN S(R,C)=16384+INT(R/8)*2048+(R-INT(R/8)*8)*32+C 5520 DEF FN C(A$)=15360+CODE A$*8
5530 LET R=22: LET A$="]/ISLAND DEFENCE/[ BY BJJ $ IOA" 5540 FOR J=1 TO LEN A$: LET C=J-1: GO SUB CHAR: NEXT J 5550 LET R=23: LET A$="HI-SCORE SCORED BY BJJ" 5560 FOR J=1 TO LEN A$: LET C=J-1: GO SUB CHAR: NEXT J 5570 RETURN 5600 REM CHAR
5609 REM PRINT J'TH CHARACTER OF A$ AT D,C, CHANGE ATTRIBUTE TO RED PAPER AND WHITE INK.BEEP.
5610 LET AT=FN S(R,C): LET FROM=FN C(A$(J))
5620 FOR I=0 TO 7: POKE AT+I*256, PEEK(FROM+I): NEXT I 5630 POKE 22528+C+R*32,87: BEEP 0.03,CODE A$(J)-50 5640 RETURN 5700 REM HISCORE
5709 REM CHANGN HI-SCORE AND PRINT IT ON BOTTOM OF SCRN.
5710 LET HSC=SC: LET A$=STR$ HSC
5720 LET R=23: FOR J=1 TO LEN A$: LET C=10+J: GO SUB CHAR: NEXT J
5729 REM CHANGE NAME TO FLASHING LETTERS.
5730 FOR I=23291 TO 23293: POKE I,PEEK I+128: NEXT I
5739 REM GET THREE INITIALS FOR HISCORE FROM KEYBOARD.
5740 LET J=1: FOR C=27 TO 29
5750 IF INKEY$<>"" THEN GO TO 5750 5760 IF INKEY$="" THEN GO TO 5760 5770 LET A$=INKEY$: GO SUB CHAR: NEXT C 5780 RETURN
Фон
Фон создается с помощью программы CHARACTER GENERATOR и программы для создания диаграмм. Сначала с помощью подпрограммы "PAPER" наносятся прямоугольные области, аппроксимирующие большие
участки игрового поля (например, трава, небо, солнце, и т.д.). На это изображение накладываются более мелкие детали (например, деревья, мешки с песком, края травы, солнца, облаков и т.д.). Эта работа может быть выполнена с помощью программ для построения диаграмм ("POINT", "LINE"). Например, добавляя к рисункам взрывов точки и прямые, можно получить изображение деревьев.
Цветовую гамму можно расширить, используя команду BRIGHT. Особое внимание следует уделять блокам, через которые будут проходить движущиеся объекты. Эти блоки должны содержать только один фоновый цвет, так как в противном случае при прохождении через этот блок объекта может возникнуть недопустимая ситуация -наличие в одном символьном блоке более двух цветов. На нашем игровом поле есть два таких участка.
1. Во время полёта самолёты проходят поверх облака и за ним, так что граница между небом и белым облаком не должна проходить внутри символьных блоков, через которые проходят самолёты. Во время полёта самолёт исчезает за облаком, так что некоторые блоки должны иметь фон белого цвета и белый INK цвет. Когда самолёт пересекает этот блок, рисующий цвет INK становится тоже белого цвета, что и фон, и самолёт невозможно отличить от облака.
2. Хотя, на первый взгляд, кажется, что солнце имеет форму круга с гладкими краями, при более внимательном рассмотрении видно, что края зубчатые, проходящие по границам блоков. Те блоки, которые во время игры не меняются, могут содержать два цвета.
Каскадная мультипликация
После загрузки изображения игрового поля на ленту мы перейдём к созданию программ, помещающих и передвигающих объекты на переднем плане. Так как от этих программ требуется высокая скорость исполнения, то мы должны позаботиться об эффективности их алгоритмов с тем, чтобы минимизировать количество вычислений во время игры.
Здесь мы приводим описание одного такого метода - каскадного мультиплицирования, или метод подвижной входной точки. К подпрограммам, быстродействие которых особенно важно, можно обращаться с помощью переменного указателя (идентификатора в нижнем регистре). Эти подпрограммы оформлены в виде последовательности (каскада) подзадач, из которых при каждом входе выполняется только одна. Решение каждой подзадачи записывается в виде последовательности строк, после чего указатель обращения к этой программе изменяется и мы возвращаемся в исходную программу. При повторном входе в подпрограмму обычно выполняются действия по другому алгоритму, так как указатель, как правило, указывает на начало следующей в списке подзадачи, и так процесс повторяется до тех пор, пока мы не достигаем конца списка (в этом случае, как правило, указатель устанавливается на начало списка).
Вся игра состоит из фазы инициализации и последующих обращений к подпрограммам, каждая из которых представляет из себя каскад, выполняющий ту или иную задачу (например, передвигает самолёт, производит бомбежку цели, и т.д.).
Каскадные подпрограммы могут обращаться и к другим каскадам, что производит эффект действий, происходящих одновременно. Это делается для того, чтобы игроку казалось, что на экране происходит ряд независимых событий. В нашей игре мы стараемся создать у играющего впечатление, что самолёт, орудие и снаряд движутся независимо друг от друга.
В силу своей сложности, наша программа не может служить наглядным примером применения этой техники, поэтому мы приведём другую программу, значительно более простую (которая пригодна для компьютеров с объёмом памяти 16К).
Следующие две программы действуют независимо друг от друга. Программа на листинге 14.2 после нажатия клавиши стреляет точкой, а программа на листинге 14.3 передвигает по экрану по зигзагообразной траектории знак "+". Обе программы используют технику быстрой мультипликации, примененной в игре ISLAND DEFENCE, однако они настолько малы, что для замедления движения на экране приходится пользоваться командой PAUSE (такие проблемы возникают только с очень простыми и короткими программами). Из этих подпрограмм мы составляем две каскадные программы (листинг 14.4), так что кажется, что точка и крестик движутся одновременно.
Каскад, передвигающий точку, состоит из трёх частей:
A. Точка помещается в 10-ую строку, нулевой столбец;
Б. Если игрок нажал клавишу, то точка начинает свое движение;
B. Точка двигается на одну позицию, пока не достигнет правого края экрана.
Как только какой-либо из этих процессов завершен, то значение идентификатора DOT устанавливается на следующий раздел. После того, как точка достигает границы экрана, указатель DOT устанавливается на первый раздел.
Каскад, управляющий движением крестика, также состоит из трех частей:
A. Крестик помещается в 22-ой строке, 8-ом столбце;
Б. В нижней половине экрана крестик перемещается на одну строку вверх и один столбец вправо;
B. В верхней половине экрана крестик перемещается на одну строку вверх и один столбец влево, и если точка и крестик находятся в одном блоке, то выполняется команда SPLAT.
При помощи основной программы из этих программ составляется игра. Основная подпрограмма вызывает попеременно то программу "DOT", то "CROSS", а значения идентификаторов изменяются так, что они указывают на правильную точку входа.
LISTING 14.2
200 REM DOT
210 PRINT AT 11,0;"."
220 IF INKEY$="" THEN GO TO 220
230 LET D=0
240 PRINT AT 11,D;" ": LET D=D+1
250 IF D=32 THEN GO TO 210
260 PRINT AT 11,D;"."
270 PAUSE 1: GO TO 240
LISTING 14.3
300 REM CROSS
310 LET R=21: LET C=8
320 PRINT AT R,C;"+"
330 PRINT AT R,C;" ": LET R=R-1
340 IF R<0 THEN GO TO 310
350 IF R>11 THEN LET C=C+1
360 IF R<=11 THEN LET C=C-1
370 PRINT AT R,C;"+"
380 PAUSE 1: GO TO 330
LISTING 14.4
100 REM MAIN LOOP
110 LET DOT=220: LET CROSS=300
120 GO SUB DOT: GO SUB CROSS
130 GO TO 120
200 REM DOT CASCADE
210 PRINT AT 11,0;".": LET DOT=220: RETURN
220 IF INKEY$="" THEN RETURN
230 LET D=0: LET DOT=240: RETURN
240 PRINT AT 11,D;" ": LET D=D+1
250 IF D=32 THEN LET DOT=210: RETURN
260 PRINT AT 11,D;"."
270 RETURN
300 REM CROSS CASCADE 310 LET R=21: LET C=8
320 PRINT AT R,C;"+": LET CROSS=330: RETURN
330 PRINT AT R,C;" ": LET R=R-1
340 LET C=C+1
350 PRINT AT R,C;"+"
360 IF R>11 THEN RETURN
370 LET CROSS=388: RETURN
380 IF R=11 AND C=D THEN PRINT AT R,C;"SPLAT": STOP
390 PRINT AT R,C;" ": LET R=R-1
400 IF R<0 THEN LET CROSS=310: RETURN
410 LET C=C-1
420 PRINT AT R,C;"+"
430 RETURN
Упражнение 14.2
Добавьте к вызывающей программе одну строчку, чтобы после выполнения команды SPLAT указатели устанавливались на начало каскада, и на экране появлялся счёт (количество попаданий).
Напишите программу "стрельба по летящей мишени", в которой охотник, движением которого можно управлять с клавиатуры, перемещается слева направо. Он стреляет по мишени, которая может летать слева направо, сверху вниз по диагонали.
Другие методы мультипликации На примере такой простой игры мы не можем показать насколько эффективны каскадные программы. Это становится ощутимым для больших игр, таких, как ISLAND DEFENCE. Заметьте, что для создания изображения самолёта используется восемь наборов символов.
Каскад, рисующий изображение самолёта, состоит из различных секций, каждая из которых помещает один тип самолёта в определенное место на экране. Перемещение самолёта происходит в два этапа: сначала он рисуется невидимыми чернилами на новом месте, а затем забивается старое изображение. Снаряды наносятся невидимыми чернилами поверх уже существующего изображения, а затем стираются со старой позиции повторным выводом. У этих методов есть свои достоинства и недостатки. Когда есть возможность одновременно удалять изображение в старом положении и рисовать объект в новом положении (см. раздел программы, в котором самолёт летит горизонтально), то зачастую на создание изображения тратится меньше времени; но при этом исчезают некоторые детали фона.
При одновременном использовании двух техник могут возникать дополнительные сложности: если некоторый символьный блок пересекут два движущихся объекта: например, что произойдет, если занятый снарядом блок пересечет самолёт? В игре это может произойти в седьмой строке, девятом ряду. В результате после повторной печати участок ракеты, подлежащий уничтожению, остается висеть в воздухе. Для исправления этой ошибки лучше дописать программу самым простым способом, чем усложнять алгоритм, так как это может привести к появлению других ошибок. Каскад, управляющий полётом самолёта, содержит лишний оператор (на 1990 строке), который
обеспечивает быструю ликвидацию ошибок.
В двух местах в программе самолёт исчезает за предметами фона. Для того, чтобы самолёт мог исчезнуть за облаком, мы просто сделали в тех блоках, где он должен исчезнуть, рисующий цвет белым. Что касается человека, проходящего за деревом, то здесь проблема сложнее. Мы хотим видеть дерево двухцветным, когда за ним проходит человек.
Используемый нами приём состоит в следующем: человек подходит к дереву, и надпечатывается, если при этом попадает в блоки, содержащие листву, а затем и вовсе перестает печататься, но звук шагов продолжает воспроизводиться, и через соответствующий интервал времени человек выходит из-за дерева: сначала появляется нога человека, на один блок раньше головы, причём это должно происходить как при движении человека вправо, так и при движении влево. Все детали следует тщательно рассчитать перед тем, как программировать алгоритм на бейсике.
Комбинация этих техник для перемещения объектов по экрану и приёмы, позволяющие этим объектам проходить друг через друга, позволит вам создавать высококачественные программы. Если вы хотите создавать сложные игры с быстроменяющейся обстановкой, то вам придётся программировать в машинных кодах. Даже в этом случае некоторые из подпрограмм могут быть написаны на бейсике. Подпрограммы пишутся целиком в машинном коде, только когда они предназначены для продажи.
По мере того, как программируемые вами игры будут более сложными, вам придется прикладывать все больше усилий для того, чтобы они имели простую структуру, для этого программируйте методом сверху-вниз, используйте осмысленные имена для переменных и комментируйте программы, начиная со стадии разработки.
Теперь мы оставляем вас наедине со SPECTRUMом, который показал себя надежным устройством, простым в общении. Мы уверены, что у вас впереди много приятных часов, проведенных с этим компьютером. Для того чтобы помочь вам начать, мы приводим в следующей главе несколько идей проектов. Всего вам хорошего и хороших программ.
Список программ
1. Листинг 14.1: игра ISLAND DEFENCE. Мы рекомендуем вам приобрести кассету, так как для создания набора специальных символов требуется довольно много времени. Однако рано или поздно вам придется создавать наборы символов и фон.
2. Листинг 14.2 (программа "DOT"). Нажмите любую клавишу.
3. Листинг 14.3 (программа "CROSS"): входных данных нет.
4. Листинг 14.4 (основная программа, "DOT CASCADE" и "CROSS CASCADE"). Впечатайте любой ключ.