Nie tylko Święci garnki lepią i nie tylko programiści gry piszą. Programista ze mnie żaden, a kilka gier na „małe” Atari już stworzyłem. Dziś pokażę Wam jak taką małą prostą grę można stworzyć sobie samemu, nawet nie posiadając komputera Atari (wystarczy PC).
Jeśli nie dysponujemy komputerem Atari ze stacją dysków (a najlepiej z jakimś jej emulatorem – np. SIO2SD) pobieramy ->LINK<- program Atirra, który będzie dość dobrze udawał wymagany komputer, całkiem dobrze sprawując się w roli dev-kit’u. 8bitowe komputery Atari posiadają wbudowany interpreter języka BASIC, który przy użyciu komend znanych z języka angielskiego umożliwia tworzenie różnego rodzaju programów. Na potrzeby naszej gry użyjemy jednak bardziej rozbudowanej wersji interpretera pod nazwą Turbo Basic XL 1.5, która jest około 3 razy szybsza od podstawowej wersji, a dołączony kompilator potrafi przyspieszyć wykonywany program o dodatkowe 10-15 razy. Ponadto TBXL zawiera zestaw dodatkowych instrukcji ułatwiających tworzenie bardziej zaawansowanych programów. Obraz dyskietki z językiem możemy pobrać tu ->link<-
Podstawowa konfiguracja „Altirra”
- W menu górnym:
System -> Configure system…
Z listy wybieramy „System”, a następnie ustawiamy „Hardware type” na „65XE/130X”
Następnie z listy wybieramy „Devices”, klikamy na „Add” i z listy na samym dole wybieramy „Printer”
- W menu górnym:
View->Printer Output (wyświetli nam okienko wirtualnej drukarki Atari) - W menu górnym
File->Attach Disk->Drive 1
Gdzie wybieramy plik z obrazem dyskietki Turbo Basic XL.
- Wciskamy Shift+F5 (reset) i czekamy na załadowanie się TBXL (niebieski ekran z napisem „READY”)
Zaczynamy programować
Na początku wypada się przywitać:
PRINT „HELLO WORLD”
Niektóre komendy języka BASIC posiadają także skróty, które warto opanować, dlatego też taki sam efekt osiągniemy pisząc:
PR. „HELLO WORLD”
Lub jeszcze krócej:
?”HELLO WORD”
Na raz możemy wprowadzić 3 linie instrukcji rozdzielanych dwukropkiem:
?”HELLO WORLD”:?”ALA MA KOTA”:?”JESTEM TBXX”
Przy użyciu komendy PRINT bardzo ważne jest używanie cudzysłowów. Pomijając ten ważny znak:
? HELLO WORD
Zostaniemy poinformowani o błędzie w programie.
Inaczej będzie się miała sprawa w przypadku jednego wyrazu:
? HELLO
Gdzie zostanie wyświetlone „0” (zero), gdyż dany wyraz zostanie potraktowany, jako zmienna liczbowa. Zmienne liczbowe możemy porównać do ogólnodostępnych pojemników, w których możemy przechowywać pojedyncze liczby. Zmiennych możemy używać między innymi, jako różnego rodzaju liczników (liczba żyć, punkty, energia wykonywać na nich operacje matematyczne (dodawanie, odejmowanie, mnożenie, dzielenie, potęgowanie…)
PUNKTY=10:? PUNKTY: PUNKTY=PUNKTY+10:?PUNKTY
Możemy także mieszać wyświetlany tekst z wartością zmiennej:
? „PUNKTY:”;PUNKTY:? „PUNKTY:”,PUNKTY
W przypadku dołączania zmiennej za pomocą średnika wartość zostanie wyświetlona zaraz za tekstem, natomiast używając przecinka wartość zostanie wyświetlona 8 pozycji dalej.
Jak zapewne zauważyliście, wszystkie wpisywane komendy wykonywane są natychmiast po zatwierdzeniu ich klawiszem „Return” na Atari lub „Enter” na PC. Do tworzenia dłuższych programów Atari BASIC używa numeracji linii. Polecam zaczynać numerację od 10 z krokiem co 10 – ułatwia to późniejszą rozbudowę programów poprzez dopisywanie linii pomiędzy „dziesiątkami”
10 ? „HELLO WORLD”
Tym razem program nie został wykonany, możemy dopisać kolejną linię:
20 ?”TO JA TBXX”
Aby uruchomić program używamy komendy
RUN
Trochę już naśmieciliśmy na ekranie, aby wyczyścić ekran używamy komendy:
CLS
Aby wyświetlić wcześniej napisany program (ten z numerowanymi liniami) używamy komendy:
LIST
Komendy tej możemy użyć również z parametrami:
LIST 10
Wyświetli nam tylko linię 10 programu
LIST 10,20
Wyświetli nam linie od 10 do 20
LIST „P:
„wydrukuje” nam program na (wirtualnej) drukarce
Stworzony przez nas program możemy zapisać na dyskietce za pomocą komendy:
SAVE „D1:nazwapliku.rozszerzenie
Przy czym nazwa pliku może mieć maksymalnie 8 znaków a rozszerzenie 3
Zapisany program wczytujemy za pomocą:
LOAD „D1:nazwapliku.rozszerzenie
Komendą DIR wyświetlamy zawartość dyskietki, polecenie to jest skróconą formą DIR „D1:*.*” gdzie „gwiazdek” oraz „pytajników” możemy używać na podobnej zasadzie jak na PC
DIR „D1:A*.BAS”
Wyświetli nam wszystkie pliki zaczynające się na „A” z rozszerzeniem „BAS”
Pozostałe składniki zupy zwanej „grą”
DIM – polecenie tworzące jedno lub dwu wymiarowe tablice zmiennych liczbowych, oraz zmienne tekstowe. Przykładowo:
DIM A(9)
utworzy nam tablicę zmiennej A o pojemności 10 liczb (0-9). Taką tablicę możemy porównać do wiersza o długości 10 pól w arkuszu kalkulacyjnym.
DIM B(9,9)
Utworzy nam tablicę zmiennej B o pojemności 100 liczby. Taką tablicę możemy porównać do obszaru 10 wierszy na 10 kolumn w arkuszu kalkulacyjnym.
DIM A$(9)
Utworzy nam zmienną tekstową o długości 9 znaków. Nazwy zmiennych tekstowych zawsze kończymy znakiem $. W przeciwieństwie do zmiennych liczbowych wszystkie zmienne tekstowe musimy wcześniej utworzyć instrukcją DIM.
FOR, TO, STEP, NEXT – polecenia tworzące pętle o określonej liczbie powtórzeń.
FOR A=0 TO 9:?A:NEXT A
Wyświetli nam cyfry 0-9, pomiędzy „FOR/TO” a „NEXT” możemy wstawić różne instrukcje, które chcemy, aby zostały powtórzone. Wewnątrz pętli możemy używać zwiększającej się z każdym powtórzeniem o 1 zmiennej A. Dodając instrukcję STEP możemy regulować zmianę wartości zmiennej:
FOR A=0 TO 9 STEP 0.5:? A:NEXT A
Z każdym powtórzeniem wartość A będzie rosła o 0.5 czyli do 9 otrzymamy 20 powtórzeń.
RND – Losuje liczbę z zakresu 0-0.999999999999
?RND: A=RND:?A
INT – zwraca liczbę całkowitą z danej liczby lub zmiennej:
?INT(0.5):?INT(1.5):A=10.7:?INT(A)
IF, THEN – operacje warunkowe IF (jeśli) warunek THEN (to) wykonaj daną operację:
IF A>B THEN B=B+1
Jeśli A jest większe od B to zwiększ wartość B o 1
POSITION x,y – wyznacza współrzędne miejsca na ekranie od którego zostanie wykonany kolejny rozkaz PRINT:
POSITION 10,10:PRINT „ALA”
Instrukcję możemy skrócić do postaci POS.
SETCOLOR a,b,c – instrukcja pozwalająca ustawić widoczne na ekranie barwy. W trybie tekstowym, w którym aktualnie pracujemy parametr „a” może przyjąć jedną z trzech wartości:
1 – odpowiada za kolor tekstu
2 – odpowiada za kolor tła
4 – odpowiada za kolor ramki
Parametr „b” odpowiada za wartość koloru (0-15), natomiast parametr „c” za jasność koloru (0-15): W trybie tekstowym tekst oraz tło zawsze będą miały ten sam kolor, różniąc się jedynie jasnością.
SETCOLOR 2,0,0:SETCOLOR 1,0,10
Instrukcję możemy skrócić do formy SET.
REPEAT, UNTIL – służą do tworzenia pętli kończących się spełnieniem danego warunku:
A=0:REPEAT :?A: A=A+1: UNTIL A=10
PAUSE x – funkcja służąca chwilowemu zatrzymaniu wykonywanego programu, na przykład w celu spowolnienia go. Dla wartości X=1 zatrzymanie trwa 1/50 sekundy. W celu wstrzymania programu na 1 sekundę wartość X ustalamy na 50
PAUSE 25
STICK, STRIG – zmienne systemowe zwracające parametry joysticka, odpowiednio wychylenia drążka i przycisku FIRE.
Wartości odczytywane poprzez STICK(0) oraz STRIG(0) odnoszą się do joysticka podpiętego do portu 1, a STICK(1) oraz STRIG(1) do joysticka podpiętego do portu 2.
REPEAT:?STICK(0),STRIG(0):UNTIL STRIG(0)=0
Powyższy kod będzie nam wyświetlał parametry wychyleń joysticka, oraz wartość „1” oznaczającą niewciśnięty FIRE. Pętla zostanie zakończona po wciśnięciu FIRE – STRIG(0)=0
NEW – instrukcja kasująca obecny w pamięci program w celu utworzenia nowego.
END – instrukcja kończąca wykonywany program.
PROC, ENDPRO, EXEC – instrukcje pozwalające na tworzenie procedur, czyli zestawów powtarzających się w programie instrukcji. Procedurę rozpoczynamy instrukcją
PROC nazwa
a kończymy instrukcją ENDPROC
Procedurę w programie wywołujemy instrukcją
EXEC nazwa
Po zakończeniu procedury program powróci do miejsca, z którego procedura została wywołana.
NEW
10 A=0:?A:EXEC DODAJ:EXEC DODAJ:?A:END
20 PROC DODAJ:A=A+1:ENDPROC
O pamięci słów kilka
Komputer, na który stworzymy naszą grę jest urządzeniem 8bitowym. Bity to takie przełączniki dwustanowe – mogące przyjmować wartości „0” lub „1” sterujące pracą komputera. Grupa 8 bitów tworzy bajt. Bajty mogą przyjmować jedną z 256 wartości (2 do potęgi 8) licząc od zera. Wartości poszczególnych bajtów możemy wyliczyć na podstawie tabelki:
Gdzie wartość liczbowa stanowi 2 do potęgi „numer bitu”, a wartość całego bajtu stanowi suma wyników mnożenia wartości liczbowej bitu oraz jego stanu. Na podanym przykładzie wartość bajtu wynosi, więc 170. Maksymalny rozmiar pamięci, jaki na raz jest wstanie obsłużyć procesor 8bitowy to 64kB czyli 65536 bajtów. Pamięć ta na Atari jest podzielona na 256 stron po 256 komórek, numerowanych kolejno 0-65535. Ilość dostępnej dla programu pamięci możemy sprawdzić za pomocą zmiennej systemowej FRE:
?FRE(0)
Jak widać do 65536 bajtów „trochę” brakuje – dość duża część pamięci zajmowana jest przez system oraz interpreter BASIC’a.
O rolah poszczególnych komórek „systemowych” możemy przeczytać w różnego rodzaju „mapach pamięci Atari”, a na potrzeby naszej gry poznamy kilka z nich.
Wartości poszczególnych komórek możemy zmieniać instrukcją POKE
POKE 710,0
Spowoduje wpisanie do komórki o numerze 710 wartości 0. Komórka ta odpowiada za kolor tła – możemy, więc instrukcji tej użyć zamiast SET.2,0,0
Zawartość każdej komórki możemy podglądnąć za pomocą instrukcji PEEK(nr. komórki)
?PEEK(710):A=PEEK(710):?A
Powyższy kod wyświetli nam zawartość komórki 710, następnie przypiszą tą wartość zmiennej A. Na końcu zaś wyświetli wartość zmiennej A.
Piszemy grę!
Uwaga! Przy tworzeniu nazw procedur oraz zmiennych warto zwrócić uwagę na ich długość – im dłuższa nazwa tym więcej zajmuje miejsca w pamięci. Z drugiej strony stosując zbyt krótkie nazwy, możemy się pogubić, która, za co odpowiada. Dlatego też polecam pisząc program, co jakiś czas drukować go na „wirtualnej drukarce”, a następnie wklejać go do edytora tekstowego dopisując komentarze, co dana zmienna oznacza, lub co wykonuje dana część programu.
Podobnie jak z długością nazw, warto uważać z ilością linii programu. Każda linia programu może mieć maksymalnie 3 wiersze, dlatego warto stosować skróty instrukcji. Jak można zauważyć na lewo od kursora znajduje się margines o szerokości 2 znaków. Za szerokość marginesu odpowiada komórka pamięci 82
?PEEK(82)
Jak widać znajduje się tam wartość „2”, dlatego też:
POKE 82,0
Likwiduje margines, przez co zyskujemy dodatkowe 6 znaków na linię programu.
Wpisujemy
NEW
I zaczynamy – nasza gra będzie prostą układanką z cyframi, które należy ułożyć w odpowiedniej kolejności na polu gry o rozmiarach 3×3
10 DIM A(2,2):DIM B(2,2):WYN=0
15 POKE 752,1
20 EXEC GENLVL:EXEC WYSPLA
25 POKE 18,0:POKE 19,0:POKE 20,0
30 REPEAT: EXEC JOY:EXEC ZEGAR:EXEC SPRWYN:UNTIL WYN=8:END
Deklarujemy tablice zmienny A oraz B 3×3 pola, zerujemy wartość zmiennej WYN. Komórka 752 odpowiada za widoczność kursora (wartość 0), każda inna wartość powoduje jego zniknięcie. Następnie wywołujemy 2 procedury, oraz kasujemy wartość zegara systemowego – komórki 18,19,20. Na końcu tworzymy pętlę wywołującą 3 procedury do czasu osiągnięcia przez zmienną WYN wartości 8, co zakończy nasz program.
1000 PROC GENLVL
1010 L=1:FOR Y=0 TO 2:FOR X=0 TO 2:B(X,Y)=L:L=L+1:NEXT X:NEXT Y
1020 FOR Y=0 TO 2:FOR X=0 TO 2
1030 REPEAT: XX=INT(RND(0)*3):YY=INT(RND(0)*3):UNTIL B(XX,YY)>0
1040 A(X,Y)=B(XX,YY):B(XX,YY)=0
1050 NEXT X:NEXT Y
1060 L=1:FOR Y=0 TO 2:FOR X=0 TO 2:B(X,Y)=L:L=L+1
1070 IF A(X,Y)=1 THEN A(X,Y)=0:XP=X:YP=Y
1080 NEXT X:NEXT Y
1090 ENDPROC
Procedura generująca układankę. Tablica zmiennej B zostaje zapisana cyframi 1-9. Następnie losujemy pola zmiennej B, których wartość przenosimy do kolejnych pól zmiennej A, zerując wartość pola w zmiennej B. Jeśli wylosowane pole B posiada wartość 0 losowanie zostaje powtórzone. Na końcu do tablicy B zostaje z powrotem wpisana poprawna kolejność cyfr, a w polu tabeli A, w którym znajdowała się cyfra 1 wstawiamy 0, które będzie oznaczało puste pole. Współrzędne pustego pola przepisujemy do zmiennych XP oraz YP.
1100 PROC WYSPLA
1110 CLS :SETCOLOR 2,0,0
1120 FOR X=0 TO 2:FOR Y=0 TO 2:POSITION X+19,Y+10:PRINT A(X,Y)
1130 IF A(X,Y)=0 THEN POSITION X+19,Y+10:? " "
1140 NEXT Y:NEXT X
1150 ENDPROC
Procedura wyświetlająca pole gry. Czyścimy ekran, ustawiamy kolor tła na „czarny”. Wyświetlamy wartości tabeli A w kwadracie 3×3. W miejscu wartości „1” wyświetlamy spację.
1200 PROC JOY
1210 IF STICK(0)=14 THEN EXEC DOL:ENDPROC
1220 IF STICK(0)=13 THEN EXEC GORA: ENDPROC
1230 IF STICK(0)=11 THEN EXEC PRAWO:ENDPROC
1240 IF STICK(0)=7 THEN EXEC LEWO:ENDPROC
1290 ENDPROC
Procedura badająca wychylenia joysticka oraz uruchamiająca procedury odpowiadające poszczególnym kierunkom.
1300 PROC GORA
1310 IF YP=0 ENDPROC
1320 A(XP,YP)=A(XP,YP-1):A(XP,YP-1)=0
1330 XM=0:YM=-1:EXEC RYSMOV
1340 ENDPROC
1350 PROC DOL
1360 IF YP=2 THEN ENDPROC
1370 A(XP,YP)=A(XP,YP+1):A(XP,YP+1)=0
1380 XM=0:YM=1:EXEC RYSMOV
1390 ENDPROC
1400 PROC LEWO
1410 IF XP=0 THEN ENDPROC
1420 A(XP,YP)=A(XP-1,YP):A(XP-1,YP)=0
1430 XM=-1:YM=0:EXEC RYSMOV
1440 ENDPROC
1450 PROC PRAWO
1460 IF XP=2 THEN ENDPROC
1470 A(XP,YP)=A(XP+1,YP):A(XP+1,YP)=0
1480 XM=1:YM=0:EXEC RYSMOV
1490 ENDPROC
Zestaw procedur odpowiadających za ruch „pustego pola”. Najpierw badamy czy w przypadku ruchu w danym kierunku zmienne XP oraz YP nie przekroczą dozwolonych wartości (0 i 2). Następnie zamieniamy miejscami wartość przesuwanego pola tabeli A oraz „pustego miejsca”. W parametrach XM oraz YM zapisujemy wartość zmiany współrzędnych pustego pola. Na końcu wywołujemy procedurę wyświetlająca dokonane zmiany na ekranie.
1500 PROC RYSMOV
1510 POSITION XP+19,YP+10:PRINT A(XP,YP)
1520 XP=XP+XM:YP=YP+YM
1530 POSITION XP+19,YP+10:PRINT " "
1540 PAUSE 25
1550 ENDPROC
Procedura wyświetla nowe położenia cyfry z tabeli A. Następnie zostają zmienione współrzędne pustego pola, oraz gra zostaje wstrzymana na pół sekundy.
1600 PROC SPRWYN
1610 WYN=0
1620 FOR X=0 TO 2:FOR Y=0 TO 2
1630 IF A(X,Y)=B(X,Y) THEN WYN=WYN+1
1640 NEXT Y:NEXT X
1650 IF WYN=8 THEN EXEC GRAT
1660 ENDPROC
Procedura sprawdzająca zgodność poszczególnych pól tabeli A z odpowiadającymi im polami tabeli B. W przypadku zgodności wartość WYN jest zwiększana o 1. Po osiągnięciu wartości 8 gra zostanie zakończona.
1700 PROC GRAT
1705 POSITION 19,10:? "1"
1710 POSITION 11,17:PRINT "GRATULACJE"
1715 POSITION 11,19:? "CZAS GRY:";G;":";M;":";S
1720 ENDPROC
Procedura kończąca grę – wyświetla brakującą cyfrę „1” w miejsce pustego pola, oraz aktualny czas gry.
1800 PROC ZEGAR
1810 T=256*PEEK(18)+PEEK(19):T=256*T+PEEK(20)
1820 S=INT(T/50):M=INT(S/60):S=S-60*M
1830 G=INT(M/60):M=M-60*G
1840 POSITION 11,19:? "CZAS GRY:";G;":";M;":";S
1850 ENDPROC
Procedura wyliczająca oraz wyświetlająca czas trwania gry na podstawie zegara systemowego. S – sekundy, M – minuty, G – godziny.
Dzięki nabytej wiedzy bez problemu powinniście również utworzyć stronę tytułową dla powyższej gry.
Cisza w komentarzach, pewnie wszyscy programują 🙂 Pamiętam jak za dzieciaka trochę grzebałem w Basicu na małym Atari, tutaj z tego co widzę Turbo Basic sporo ułatwia pracę nad kodem
Chyba dlatego, że mało kto tu zagląda, a informacji brak…
Artek fajny, ale ma kilka niedociągnięć – choć dla początkujących wystarczy. Skoro piszemy w TB XL – warto skorzystać z RAND(liczba) zamiast RND. Dodatkowo warto korzystać z instrukcji DPEEK(adres) zamiast 256*PEEk(adres)+PEEK(adres+1) – mnożenie w procesorze ośmiobitowym kosztuje cenne ułamki sekund, a tu gotowa konstrukcja… Oczywiście w pojedynczych przypadkach jest to pomijalne, ale jak musimy już odczytać wiele komórek… Wbrew pozorom – po kompilacji też to ma znaczenie.
Ogólnie – artek fajny, czekam na więcej 😉
Fajny poradnik dla początkujących
Idę pisać grę 😉