plazma - amatör bilgisayar kültürü

Atari 800 XL/XE - Bölüm 2

Emir 'Skate' Akaydın

1. Giriş

Atari, evlerimize giren 8 bit ailesi bilgisayarların en eskilerinden biri olmasına rağmen, bazı açılardan çok şanslı bir bilgisayardır. Çünkü günümüz PC'lerinde bile donanımsal olarak yer almayan ve yine dönemin bilgisayarlarının bir kısmında da bulunmayan bir özelliğe sahiptir. Bu özelliğe genel olarak yaratıklar (sprites) diyoruz. Ancak Atari fazlasıyla oyun odaklı tasarlanmış olacak ki, bu yaratıkları iki başlık altında toplamıştır. Oyucular ve füzeler (players & missiles). İlk başta bir donanım özelliği olarak kulağa komik gelse de işin içine girince gerçekten de ismini hak eder bir tasarıma sahip olduğunu göreceksiniz.

Bu sayımızda, bu muhteşem donanım özelliğini çeşitli yönleriyle inceleyeceğiz. Öncelikle genel tanımıyla yaratıklara bir göz atalım.

Not: Bu yazıda verilen kaynak kodlar, ACME ile derlenebilirler. Detaylı bilgi için yazı dizisinin birinci bölümüne göz atınız.

Şekil 1.

2. Yaratık Nedir?

Günümüz bilgisayarları hiper süper hızlarda çalıştıkları için bu tür bir donanım özelliğine ihtiyaç duymamaktadırlar. Kaldı ki 2 boyutlu donanım destekleri 3 boyutun bize yetmediği (!) günümüzde biraz arkaplanda kalmaktadır.

70'lerin sonlarında, 80'lerin başlarında piyasaya sürülmüş 8 bit bilgisayarlar en fazla birkaç Mhz hızındaydı. Atari'nin 1-2 Mhz aralığındaki hızı da diğer benzerleri gibi bazı grafik fonksiyonlarını yerine getirebilmek için yetersizdi. Bu bilgisayarların önemli ölçüde oyun odaklı tasarlandıklarını düşünecek olursanız, karşımıza ilk çıkacak problem ekranda hareket eden "yaratıklar" oluyor. Yaratık demek öcü demek değil elbette ki. Bu yaratıklar kah hoplayıp zıplayan bir Mario, kah cıv cıv ateş eden bir uzay gemisi, kah namludan fırlamış akıbeti kötü bir kurşun olabilir.

Ekranda hareket eden her yaratık donanım destekli olmak zorunda mı? Bunun başka bir yolu yok mudur? Elbette ki var. Zaten o dönemdeki hemen hiçbir donanım, ekrandaki yaratık sayısı arttıkça yeterli desteği verememekte ve başka yollara başvurulması gerekmektedir. Bunun en bariz örneklerinden biri 1978 yılında yayınlanan Space Invaders oyunudur. Ekranda 50'den fazla hareketli yaratık ve bunlara ek olarak yaratıkların attıkları kurşunlar yer almaktadır. Hele ki bu yaratıklardan 10-11 tanesinin yan yana durduğunu düşünecek olursak o günün standartlarında her biri bağımsız, donanım destekli birer yaratık olarak gösterilmeleri mümkün değildir. Ancak kolaylıkla grafik ekranına çizdirilebilir ya da karakter ekranında karakter seti değiştirilerek elde edilebilirler.

Şekil 2.

Buradaki asıl problem 50'den fazla yaratığın ekrana basılmasının ve yaratıkların hareket etmelerinden önce ekranın temizlenmesi işlemlerinin alacağı zamandır. Bu zaman şu ana kadar bu konu üzerine çok düşünmemiş bir insanın tahmin edebileceğinden daha büyük bir sıkıntıdır. Zaman yetmemesinden kasıt şudur. Atari, Commodore ve benzeri bilgisayarların PAL (Örnek: Avrupa Ülkeleri) standartlarında 50, NTSC (Örnek: Amerika) standartlarında 60 saniyede gösterebileceği belli bir kare (frame) sayısı vardır. Yani bir ekran karesi saniyede 50 ya da 60 kere oluşabilir. Bir kareyi oluşturmak için bilgisayarın belirli bir zamanı vardır. Bu zaman içersinde işleyebileceği komut sayısı da elbette ki sınırlıdır. Komutların çalışmasında geçen süre cycle ile ifade edilir. Farklı komutlar farklı cyclelarda zaman yiyebilirler. Ekranın tamamının ya da tamamına yakın bir kısmının byte byte silinmesi ve yeni yaratıkların ekrana yine byte byte basılması işlemi, söz konusu yaratık sayısı 50'nin üzerindeyse tek bir karede mümkün olmayacaktır. Bu durumda birkaç karede bir ekran güncellenecek ve bu da gözle görülür bir yavaşlamaya neden olacaktır. Gel gelelim Space Invaders'da yaşanan sorun da budur. Oyun ilk başladığında yaratıklar oldukça yavaş hareket etmektedirler. Yaratık sayısı azaldıkça yaratıkların hareket hızları artar. Son yaratık tek başına kaldığında süpersonik bir hıza ulaşır. Bu oyunun bir özelliği olmasının yanı sıra aynı zamanda teknik bir sorundur.

Space Invaders oyununun bir diğer özelliği ise siyah arkaplana sahip olmasıdır. Yani yaratıklar bir arkaplanın üzerine basılmazlar. Peki ya arkaplanda bir resim olacak olsaydı ne olacaktı? Sil-çiz kadar basit bir yöntem kullanmamız mümkün olmayacaktı. Şimdi bu duruma bir göz atalım.

Şekil 3.

Öncelikle yaratığın üzerine çizileceği arkaplanın hafızada bir kopyasının durması gerekir. Bir diğer seçenek ise yaratığın basılacağı alan bir dikdörtgen şeklinde düşünülerek sadece bu kısmın bir kopyası alınabilir. Daha sonra yaratık bu alana yine dikdörtgen biçiminde basılabilir. Ancak arkaplanın silinmemesi için matematikteki VEYA (OR) işleminin kullanılması gerekir. Bir sonraki karede, arkaplan yaratığın bulunduğu alana yeniden kopyalanarak yaratık silindikten sonra, yaratığın yeni pozisyonuna uygun bir biçimde arkaplan hafızaya alınır ve yaratık yeni pozisyonuna yerleştirilir. Bu işlem her harekette tekrarlanmak zorundadır. Grafik moduna ve yaratığın çizimine bağlı olarak yaratık basılmadan önce VE (AND) işlemi ile yaratığın basılacağı alanı arkaplan üzerinde maskelemek de gerekebilir. Bütün bu işlemler ciddi zaman alan işlemlerdir ve oyunun akıcılığını önemli ölçüde etkilerler.

Arkaplan üzerine hareketli grafik basma işinin çözümü donanımsal yaratık desteğinde gizlidir. Konumuz olan Atari 800 XL/XE bilgisayarlarında grafik işlemlerinden sorumlu çip olan Antic çipi yaratıklardan sorumlu değildir. Bu işi GTIA çipi yani Antic'deki görüntüyü TV ya da monitöre aktarma işinden sorumlu olan çip üstlenir. Kısacası Antic çipi ekrandaki görüntüyü oluşturduktan sonra GTIA çipi bu görüntünün üzerine dilediği gibi yaratık basabilir. Hatta bu yaratıkları şeffaf bile basması mümkündür. Atari'deki yaratık desteğini televizyonunuzun sesini açtığınızda ekrana çıkan volume seviye grafiği gibi düşünebilirsiniz.

3. Oyuncular ve Füzeler

Her donanımsal yaratık desteği olan bilgisayarda kendisine özel sınırlamalar vardır. Aynı anda kaç yaratık gösterilebileceği, bunların ekranda hareket ettirilme kuralları, çözünürlükleri, renk sayıları, çarpışmaları gibi birçok kriter ve sınırlama mevcuttur.

Atari'de 4 oyuncu ve 4 füze şeklinde toplamda 8 yaratık bulunmaktadır. Bu 8 yaratık birbirinden bağımsız hareket edebilirler ve arkaplanı etkilemezler. Yani çok az bir zaman harcayarak ekranda 8 yaratık göstermek mümkündür. Ancak oyuncular ve füzeler aynı özelliklerde değillerdir. 4 füze bir arada kullanıldığında fazladan 1 oyuncu elde edilebilir. Bunun nedenlerini birazdan göreceğiz.

4. Atari'de Yaratıkların Hareket Etme Prensibi

Yaratıklar iki boyutlu oldukları için iki eksende hareketleri söz konusudur; X ve Y eksenleri. Genellikle her iki eksen için birer hafıza adresi kullanılarak yaratık pozisyonlarını değiştirmek mümkündür. Ancak Atari'de yaratıklar yalnızca X ekseninde bu şekilde hareket ettirilebilirler. Dikeyde ise hareket biraz farklı bir biçimde gerçekleşmektedir. Çünkü Atari'de yaratıklar dikeyde tüm ekran yüksekliğini kaplamaktadırlar.

Şekil 4.

Resimde görülen kırmızı, yeşil, mavi ve sarı bloklar her bir yaratığın çizilebileceği alanları sembolize etmektedirler (normalde ekranda böyle barlar görmeyeceksiniz). Yaratıkların çizim genişlikleri sabitken, yükseklik olarak bir sınırlama yoktur. Bir yaratık tüm ekran boyunda olabilir. Örnek olarak resimdeki uzay gemisi, çarpı sembolü, iki yönlü ok birer yaratık olduğu gibi PLAZMA #6 yazısı da tek bir yaratıktır.

Bu yaratıklar hafızanın çeşitli bölümlerinden grafik verisi okuyabilirler. Ancak hafıza adresleri belirlendikten sonra hep sabit bir adresden veri okudukları için grafik verilerini hafıza üzerinde kaydırarak yaratıkları Y yönünde hareket ettirmiş oluruz. Bu işlem uzay gemisi için oldukça hızlı yapılabilirken, PLAZMA #6 yazısının bulunduğu yaratıkta daha uzun süren bir işlemdir. Kısacası yaratık grafiğinin yüksekliği arttıkça Y eksenindeki hareket de orantılı bir biçimde daha çok zaman almaktadır. Fakat X eksenindeki hareket yaratığın grafik verisinden kesinlikle etkilenmez ve yalnızca bir hafıza adresini değiştirerek yaratık hızlıca yeniden pozisyonlandırılabilir.

5. Oyuncular

Önceki bölümde gördüğümüz 4 yaratık aslında oyunculara tekabül etmektedir. Oyuncuların yatay çözünürlükleri 8 pixeldir. Bu aslında oldukça düşük bir çözünürlüktür. Ancak elbette ki birden fazla yaratık yan yana getirilerek 16, 24, 32 hatta füzeler de kullanılarak 40 pixel genişliğe ulaşmak mümkündür. Yaratıklar ekranda gösterilirken her bir pixel 2 pixel genişliğinde gösterilmektedir. Yani 8 pixel genişliğindeki bir yaratık ekranda 16 pixellik bir alan kaplayacaktır.

Şekil 5.

Yaratıklar yatay eksende 2 ya da 4 kat, dikey eksende ise 2 kat genişletilebilirler. Yatayda 2 kat genişletilen bir yaratık 16 yerine 32 pixel, 4 kat genişletilen ise 64 pixel kaplayacak şeklinde görüntülenir. Yani yaratık haritasında yer alan her bir bit normalde 2, 2 kat genişletildiğinde 4, 4 kat genişletildiğinde 8 pixel genişliğinde ekrana çizilir.

Oyuncuların her biri hafızada 256 bytelık alanlardan veri okurlar. Aslında bu 256 byte'ın tamamı ekran alanına sığmamaktadır. İlk 8 byte ekranın üstünden dışarıda kalmaktadır. Ekranın görüntülenebilen alanı 240 byte kabul edilebilir. Bu durumda alanın sonunda yer alan yine 8 bytelık bir bölge daha görüntülenemez. Eğer yaratıklar Y ekseninde iki kat genişletilecek olursa bu durumda 256 bytelık alanın ilk 128 byte'ı grafik verisi olarak kullanılır ve her satır 2 kez tekrar eder. Ancak bu durum tüm yaratıkların hafıza yerleşimlerini değiştiren bir durumdur. Bunu ilerde göreceğiz.

6. Füzeler

Füzeler, oyucularla büyük oranda benzerlikler içerirler. En temel farklılığı genişliklerinin 8 pixel yerine 2 (yazıyla "iki" :)) pixel olmasıdır. Elbette ki bu hayalinizdeki füzeyi çizebilmek için yeterli bir genişlik değildir. Ancak yine de füzeler mini kurşunlar atmak için kullanışlı bir yöntemdir. Peki niye 2 pixel ile sınırlıyız? Aslında bu sınır hakkında net bir görüş ortaya koymak zor da olsa benim söyleyebileceğim Atari donanımının maksimum 5 oyuncu niteliğinde yaratık destekleyebildiğidir. Bu oyunculardan 4'ü olduğu gibi kullanılırken 1 oyuncu dikey olarak 4'e bölünmüş ve 4 farklı füze olarak kullanılmış varsayılabilir. Füzeler de aynı oyuncular gibi tüm ekran yüksekliğinde basılabilir ve farklı farklı pozisyonlandırılabilirler. Ancak bu defa tek bir byte 4 farklı füzeyi ifade eder. Bu da demektir ki füzeleri dikey olarak hareket ettirirken bit bazlı ek hesaplamalar yapmamız gerekir. Şimdilik bu kadar detaya girmeden füzelerin yapısını incelemeye devam edelim.

Şekil 6.

Görüldüğü gibi birkaç farklı model füze elde edebiliyoruz. Dikeyde füze verilerini uzatarak daha farklı füzeler modellememiz de mümkün. Ancak bunların yerine birden fazla füzeyi yan yana kullanarak daha büyük füzeler elde etmemiz de bir başka kullanışlı yöntem olabilir. Ayrıca istersek 4 füzeyi birlikte 5. bir oyuncu olarak kullanabiliriz. Unutmamamız gereken şey her bir füzenin bağımsız bir X koordinatının olduğudur. Yani 4 füzeyi yan yana getirmek istediğimizde aşağıdaki gibi bir yöntem izlememiz gerekir.

clc ;elde bayrağını (carry flag) temizle
lda #X_Koordinati
sta FUZE3_X
adc #2
sta FUZE2_X
adc #2
sta FUZE1_X
adc #2
sta FUZE0_X

Burada FUZE(n)_X şeklinde geçen tanımlar henüz hafıza adreslerinden bahsetmemiş olduğumuz için yapılmış geçici tanımlardır.

7. Oyuncular ve Füzeler'in Hafıza Haritası

Oyuncu ve füzelerin dikey genişleme özelliğine göre iki farklı hafıza yerleşimleri vardır. Eğer dikey olarak genişlemişlerse hafızada 1 kilobyte, normalde ise 2 kilobyte yer kaplarlar. Bunun nedeni ise iki kat genişlemiş yaratıkların dikeyde her iki satırda bir yeni grafik verisi okumasından dolayı yarı yarıya az veriye ihtiyaç duymasıdır. Şimdi sırayla hafıza haritalarını verelim.

7.1. 1) Tek Satır Çözünürlüğü

Şekil 7.

7.2. 2) Çift Satır Çözünürlüğü

Şekil 8.

8. Oyuncu ve Füzeler'in Hafıza Adresleri

$02C0 : Oyuncu 0 ve Füze 0'ın rengi.

$02C1 : Oyuncu 1 ve Füze 1'in rengi.

$02C2 : Oyuncu 2 ve Füze 2'nin rengi.

$02C3 : Oyuncu 3 ve Füze 3'ün rengi.

$D000 : Yazarken; Oyuncu 0'ın X koordinatı. Okurken; Füze 0'ın oyun alanı çarpışma kontrolü.

$D001 : Yazarken; Oyuncu 1'in X koordinatı. Okurken; Füze 1'in oyun alanı çarpışma kontrolü.

$D002 : Yazarken; Oyuncu 2'nin X koordinatı. Okurken; Füze 2'nin oyun alanı çarpışma kontrolü.

$D003 : Yazarken; Oyuncu 3'ün X koordinatı. Okurken; Füze 3'ün oyun alanı çarpışma kontrolü.

$D004 : Yazarken; Füze 0'ın X koordinatı. Okurken; Oyuncu 0'ın oyun alanı çarpışma kontrolü.

$D005 : Yazarken; Füze 1'in X koordinatı. Okurken; Oyuncu 1'in oyun alanı çarpışma kontrolü.

$D006 : Yazarken; Füze 2'nin X koordinatı. Okurken; Oyuncu 2'nin oyun alanı çarpışma kontrolü.

$D007 : Yazarken; Füze 3'ün X koordinatı. Okurken; Oyuncu 3'ün oyun alanı çarpışma kontrolü.

$D008 : Yazarken; Oyuncu 0'ın yatay genişliği (0=normal, 1=iki kat, 3=dört kat). Okurken; Füze 0'ın oyuncu çarpışma kontrolü (1=Oyuncu 0, 2=Oyuncu 1, 4=Oyuncu 2, 8=Oyuncu 3).

$D009 : Yazarken; Oyuncu 1'in yatay genişliği (0=normal, 1=iki kat, 3=dört kat). Okurken; Füze 1'in oyuncu çarpışma kontrolü (1=Oyuncu 0, 2=Oyuncu 1, 4=Oyuncu 2, 8=Oyuncu 3).

$D00A : Yazarken; Oyuncu 2'nin yatay genişliği (0=normal, 1=iki kat, 3=dört kat). Okurken; Füze 2'nin oyuncu çarpışma kontrolü (1=Oyuncu 0, 2=Oyuncu 1, 4=Oyuncu 2, 8=Oyuncu 3).

$D00B : Yazarken; Oyuncu 3'ün yatay genişliği (0=normal, 1=iki kat, 3=dört kat). Okurken; Füze 3'ün oyuncu çarpışma kontrolü (1=Oyuncu 0, 2=Oyuncu 1, 4=Oyuncu 2, 8=Oyuncu 3).

$D00C : Yazarken; Füze 0'ın yatay genişliği (0=normal, 1=iki kat, 3=dört kat). Okurken; Oyuncu 0'ın oyuncu çarpışma kontrolü (2=Oyuncu 1, 8=Oyuncu 3).

$D00D : Yazarken; Füze 1'in yatay genişliği (8=normal, 4=iki kat, 12=dört kat). Okurken; Oyuncu 1'in oyuncu çarpışma kontrolü (1=Oyuncu 0, 8=Oyuncu 3).

$D00E : Yazarken; Füze 2'nin yatay genişliği (32=normal, 16=iki kat, 48=dört kat). Okurken; Oyuncu 2'nin oyuncu çarpışma kontrolü (1=Oyuncu 0, 2=Oyuncu 1, 8=Oyuncu 3).

$D00F : Yazarken; Füze 3'ün yatay genişliği (128=normal, 64=iki kat, 192=dört kat). Okurken; Oyuncu 3'ün oyuncu çarpışma kontrolü (1=Oyuncu 0, 2=Oyuncu 1).

Bu adres açıklamalarında bazı kurala ya da mantığa uymayan noktalar bulabilirsiniz. Örneğin oyuncuların diğer tüm oyuncularla çarpışma kontrollerinin olmaması gibi. Bunlar hata değil Atari'nin bazı kuralları ya da donanımsal sınırlandırmalar olarak değerlendirilmelidirler.

9. Oyuncu ve Füzeler'in Ekranda Gösterilmesi

Şu ana kadar öğrendiklerimizin bir işe yaraması için öncelikle bu yaratıkları ekranda nasıl göstereceğimizi bilmemiz gerekiyor. Aslında bu oldukça basit bir işlem. Bu işi gerçekleştirebilmemiz için yukarda öğrendiğimiz adreslere Antic ve GTIA çipleri arasında bir köprü gibi çalışan iki tane daha adres eklememiz gerekiyor.

$022F (DMACTL): Bu adres oyuncu ve füzelerin haricinde diğer grafik ekranı ile ilgili bayrakları da taşıyan bir adrestir. Yazı dizimizin birinci sayısında (Plazma #5'de) grafik ekranı açma ve görüntü listeleri konularında da bu adresi görmüş ve kullanmıştık. Şimdi bu adresteki bitlerin anlamlarını inceleyelim.

Bit 0 (değer 1): Dar oyun alanını aç.

Bit 1 (değer 2): Normal oyun alanını aç.

Bit 2 (değer 4): Füzeleri aç.

Bit 3 (değer 8): Oyuncuları aç.

Bit 4 (değer 16): Yaratıklar için tek satır çözünürlüğünü aç.

Bit 5 (değer 32): DMA'yı aç.

Bit 0 + Bit 1 (değer 3): Geniş oyun alanını aç.

$022F adresine örnek olarak $1f değeri verdiğimiz durumda;

$1f = %00011111 = Geniş oyun alanı + füzeler + oyuncular + tek satır çözünürlüğü açık

anlamına gelecektir. Ancak bu işlem henüz yaratıkları görüntülememiz için yeterli değildir. Çünkü yaratıkların görüntülenmesini kontrol eden anahtarları içeren bir adres daha vardır.

$D01C (GRACTL) : Bu adres grafik kontrol adresidir. Oyuncular ve füzelerin ikisinden birinin ya da her ikisinin gösterilip gösterilmeyeceğine karar verir.

Bit 0 (değer 1): Füzeler görünür.

Bit 1 (değer 2): Oyuncular görünür.

Bit 0 + Bit 1 (değer 3): Hem füzeler hem oyuncular görünür.

Bu adresin değeri 0 olduğunda oyuncular ve füzeler görüntülenemezken, 3 değeri verildiğinde her ikisi de görüntülenebilir.

Oyuncu ve füzeleri görüntüleme örneği:

lda #$1f
sta $022f ; DMACTL
lda #$03
sta #d01c ; GRAGTL

Bu iki adrese doğru değerler verildiğinde oyuncular ve füzeler artık görüntülenebilirler. Ancak elbette ki grafik haritaları ve pozisyonlarının da düzgün bir biçimde ayarlanması gerekmektedir.

10. Her İki Düzlemde Hareket Eden Oyuncu Örneği

Şimdi ilk çalışan örneğimizde ekranda daire çizen bir X yaratığı görelim. Bu yaratık için 0 numaralı oyuncuyu kullanacağız.

Dairesel hareketi elde etmek için yatayda kosinüs, dikeyde sinüs fonksiyonu kullanmamız gerekir. Kosinüs tablosu sinüs tablosundan elde edilebildiği için yalnızca sinüs tablosu oluşturmamız yeterli olacaktır. Kosinüs tablosu sinüs tablosunun 90 derece, yani PI/2 ilersindeki değerleri okuyarak elde edilebilir. Ancak bu durumda sinüs tablosunun sonunu geçeceği için sinüs tablosu hafızada peş peşe iki kez tekrar ettirilerek bu problem çözülebilir.

Sinüs tablosunu hesaplatmanın birçok yolu vardır. Bunu doğrudan assemblerdan da hesaplatabiliriz. Ancak ben genellikle çapraz geliştirmenin gücüne olan inancımdan bu tür hesaplamaları PC'de yapmayı tercih ediyorum (Bkz: Test Platformu köşesi, Plazma #1, #2, #3, #4). Şimdi kısa bir JavaScript koduyla internet tarayıcı ekranımıza sinüs tablosunu yazdıralım.

sinus.htm

<script>
for(i = 0; i < 256; i++)
{
    a = 84 + Math.floor(83.9 * Math.sin(i / 128 * Math.PI));
    if(i != 0)
        document.write(",");
    document.write(a);
}
</script>

Bu programın çıktısını aşağıdaki kodun sonlarında [sinus_tablosu] şeklinde işaretlenmiş iki alana kopyalamamız gerekiyor. Kopyaladığımızda görüntü "!byte 84,86,88,90, .... , 75,77,79,81" şeklinde olmalı. Eğer bu işlem size zor geliyorsa Plazma #6'nın yanında gelen ek dosyalardan hazır kaynak koda erişebilirsiniz.

Şekil 9.

oyuncu_hareketi.a

        BASLANGIC_ADRESI = $0600
        !to "oyuncu_hareketi.xex",plain

        * = BASLANGIC_ADRESI-6
        !word $ffff, BASLANGIC_ADRESI, BITIS_ADRESI

        * = BASLANGIC_ADRESI
;yaratıkların bellek adreslerini belirle
        lda $6a
        sec
        sbc #$08
        sta $6a
        sta $d407 ; PMBASE_HI
        sta YaratikBellegi+1
        lda #$00
        sta YaratikBellegi

;yaratık ve fuzeleri ac
        lda #$03
        sta $d01d ; GRACTL

;grafik ekrani ac
        ldy #$1f
        sty $022f ; DMACTL

;oyuncu rengi
        lda #$aa
        sta $02c0 ; Oyuncu 0 rengi

;tüm yaratik bellegini temizle
        jsr YaratikBelleginiTemizle

;oyuncunun adresini belirle
        lda YaratikBellegi
        sta $f5
        lda YaratikBellegi+1
        clc
        adc #$04
        sta $f6

;kesme rutini ayarla
        ldy #<Rutin
        ldx #>Rutin
        lda #$07
        jsr $e45c ; SETVBV
        jmp *

;ana rutin
Rutin
;oyuncuyu temizle
        jsr OyuncuyuSil
;oyuncuyu yeni y koordinatinda olustur
        jsr OyuncuyuOlustur
;eski y pozisyonunu kaydet
        lda OyuncuY
        sta OyuncuYEski
;oyuncuyu yeni x koordinatina tasi
        lda OyuncuX
        sta $d000 ; Oyuncu 0 X pozisyonu
;sinus tablosuna gore oyuncuya
;dairesel hareket yaptır
        ldy SinusPozisyonu
        lda SinusTablosu+64,y
        clc
        adc #$28
        sta OyuncuX
        lda SinusTablosu,y
        clc
        adc #$20
        sta OyuncuY
;sinus tablosu uzerinde ilerle
        inc SinusPozisyonu
        jmp $e462 ; RETURN

;2kb'lik yaratik bellegini temizle
YaratikBelleginiTemizle
        lda YaratikBellegi
        sta $f7
        lda YaratikBellegi+1
        sta $f8
        clc
        adc #$08
        sta endOfBlock
        ldy #$00
        lda #$00
Dongu1  sta ($f7),y
        iny
        bne Dongu1
        inc $f8
        ldx $f8
        cpx #$ff : endOfBlock = *-1
        bne Dongu1
        rts

;oyuncunun bulundugu alani temizle
OyuncuyuSil
        ldy OyuncuYEski
        lda #$00
Dongu2  sta ($f5),y
        iny
        cpy #HaritaSonu-HaritaBasi
        bne Dongu2
        rts

;oyuncuyu olustur
OyuncuyuOlustur
        ldx #$00
        ldy OyuncuY
Dongu3  lda HaritaBasi,x
        sta ($f5),y
        iny
        inx
        cpx #HaritaSonu-HaritaBasi
        bne Dongu3
        rts

HaritaBasi      !byte %00000000
                !byte %10000001
                !byte %11000011
                !byte %01100110
                !byte %00111100
                !byte %00011000
                !byte %00111100
                !byte %01100110
                !byte %11000011
                !byte %10000001
                !byte %00000000
HaritaSonu      = *

OyuncuX         !byte 0
OyuncuY         !byte 0
OyuncuYEski     !byte 0
SinusPozisyonu  !byte 0
YaratikBellegi  !byte 0,0

SinusTablosu    !byte [sinus_tablosu]
                !byte [sinus_tablosu]

BITIS_ADRESI = *
        !word $02e0, $02e1, BASLANGIC_ADRESI

Bu örnekte henüz öğrenmediğimiz bazı kısımlar geçiyor. Bu kısımlara takılmadan yaratıklarla ilgili öğrendiğimiz bölümleri incelemenizi tavsiye ediyorum.

11. Füze Atan Oyuncu Örneği

Aşağıda ateş eden bir uzay gemisi örneği göreceğiz. Kullanılacak yaratıklar Oyuncu 0, Füze 0, Füze 1, Füze 2 ve Füze 3.

Şekil 10.

oyuncu_fuze.a

        BASLANGIC_ADRESI = $0600
        !to "oyuncu_fuze.xex",plain

        * = BASLANGIC_ADRESI-6
        !word $ffff, BASLANGIC_ADRESI, BITIS_ADRESI

        * = BASLANGIC_ADRESI
;yaratıkların bellek adreslerini belirle
        lda $6a
        sec
        sbc #$08
        sta $6a
        sta $d407 ; PMBASE_HI
        sta YaratikBellegi+1
        lda #$00
        sta YaratikBellegi

;yaratık ve fuzeleri ac
        lda #$03
        sta $d01d ; GRACTL

;grafik ekrani ac
        ldy #$1f
        sty $022f ; DMACTL

;oyuncu ve fuze rengi
        lda #$bb  ; Oyuncu 0 ve
        sta $02c0 ; Fuze 0 rengi
        lda #$99  ; Oyuncu 1 ve
        sta $02c1 ; Fuze 1 rengi
        lda #$cc  ; Oyuncu 2 ve
        sta $02c2 ; Fuze 2 rengi
        lda #$ee  ; Oyuncu 3 ve
        sta $02c3 ; Fuze 3 rengi

;tüm yaratik bellegini temizle
        jsr YaratikBelleginiTemizle

;oyuncunun adresini belirle
        lda YaratikBellegi
        sta $f5
        sta $f7
        lda YaratikBellegi+1
        clc
        adc #$03
        sta $f8
        clc
        adc #$01
        sta $f6

;oyuncu x pozisyonu
        lda OyuncuX
        sta $d000 ; Oyuncu 0 X pozisyonu

;oyuncuyu olustur
        jsr OyuncuyuOlustur

;fuzeleri olustur
        jsr FuzeleriOlustur

;kesme rutini ayarla
        ldy #<Rutin
        ldx #>Rutin
        lda #$07
        jsr $e45c ; SETVBV
        jmp *

;ana rutin
Rutin
        inc Fuze1X
        lda Fuze1X
        cmp #$e0
        bne Devam1
        lda #$48
        sta Fuze1X
Devam1  inc Fuze2X
        lda Fuze2X
        cmp #$e0
        bne Devam2
        lda #$48
        sta Fuze2X
Devam2  inc Fuze3X
        lda Fuze3X
        cmp #$e0
        bne Devam3
        lda #$48
        sta Fuze3X
Devam3  inc Fuze4X
        lda Fuze4X
        cmp #$e0
        bne Devam4
        lda #$48
        sta Fuze4X
Devam4  lda Fuze1X
        sta $d004 ; Fuze 0 X pozisyonu
        lda Fuze2X
        sta $d005 ; Fuze 1 X pozisyonu
        lda Fuze3X
        sta $d006 ; Fuze 2 X pozisyonu
        lda Fuze4X
        sta $d007 ; Fuze 3 X pozisyonu
        jmp $e462 ; RETURN

;2kb'lik yaratik bellegini temizle
YaratikBelleginiTemizle
        lda YaratikBellegi
        sta $f9
        lda YaratikBellegi+1
        sta $fa
        clc
        adc #$08
        sta endOfBlock
        ldy #$00
        lda #$00
Dongu1  sta ($f9),y
        iny
        bne Dongu1
        inc $fa
        ldx $fa
        cpx #$ff : endOfBlock = *-1
        bne Dongu1
        rts

;oyuncuyu olustur
OyuncuyuOlustur
        ldx #$00
        ldy OyuncuY
Dongu3  lda HaritaBasi1,x
        sta ($f5),y
        iny
        inx
        cpx #HaritaSonu1-HaritaBasi1
        bne Dongu3
        rts

;fuzeleri olustur
FuzeleriOlustur
        ldx #$00
        ldy FuzeY
Dongu4  lda HaritaBasi2,x
        sta ($f7),y
        iny
        inx
        cpx #HaritaSonu2-HaritaBasi2
        bne Dongu4
        rts

HaritaBasi1     !byte %11100000
                !byte %11000000
                !byte %11110000
                !byte %11001000
                !byte %11000100
                !byte %11111110
                !byte %11111111
                !byte %11111111
HaritaSonu1     = *

HaritaBasi2     !byte %10100000
                !byte %11010111
                !byte %10100000
HaritaSonu2     = *

OyuncuX         !byte $40
OyuncuY         !byte $7c

Fuze1X          !byte $48
Fuze2X          !byte $70
Fuze3X          !byte $98
Fuze4X          !byte $c0

FuzeY           !byte $81

YaratikBellegi  !byte 0,0

BITIS_ADRESI = *
        !word $02e0, $02e1, BASLANGIC_ADRESI

12. Çarpışma Örneği

Çarpışma örneğine biraz daha detay katarak ivmeli hareket eden yaratıkları da görmüş olacağız. Bu örnekte Oyuncu 0 ve Oyuncu 1 kullanılıyor. Her iki oyuncunun da durum, hız, ivme, x ve y koordinatlarından oluşan birer yapısı var. Ayrıca 16 bit toplama ve 8/16 bit yer değiştirme (swap) işlemleri için TOPLA16, DEGISTIR8, DEGISTIR16 isminde 3 adet makro kullanıldı. Bu sayede ACME'de makro kullanımını da görmüş oluyoruz.

Şekil 11.

oyuncu_carpismasi.a

        BASLANGIC_ADRESI = $0600
        !to "oyuncu_carpismasi.xex",plain

;16 bit toplama
!macro TOPLA16 .a, .b {
        lda .a+1
        clc
        adc .b+1
        sta .a+1
        lda .a
        clc
        adc .b
        sta .a
        bcc .out
        inc .a+1
.out
}

;8 bit yer degistirme
!macro DEGISTIR8 .a, .b {
        lda .a
        sta $f9
        lda .b
        sta .a
        lda $f9
        sta .b
}

;16 bit yer degistirme
!macro DEGISTIR16 .a, .b {
        +DEGISTIR8 .a, .b
        +DEGISTIR8 .a+1, .b+1
}

        * = BASLANGIC_ADRESI-6
        !word $ffff, BASLANGIC_ADRESI, BITIS_ADRESI

        * = BASLANGIC_ADRESI
;yaratıkların bellek adreslerini belirle
        lda $6a
        sec
        sbc #$08
        sta $6a
        sta $d407 ; PMBASE_HI
        sta YaratikBellegi+1
        lda #$00
        sta YaratikBellegi

;yaratık ve fuzeleri ac
        lda #$03
        sta $d01d ; GRACTL

;grafik ekrani ac
        ldy #$1f
        sty $022f ; DMACTL

;oyuncularin yatay pozisyonlari
        lda O1_X+1
        sta $d000 ; Oyuncu 0 X pozisyonu
        lda O2_X+1
        sta $d001 ; Oyuncu 1 X pozisyonu

;oyuncu renkleri
        lda #$aa
        sta $02c0 ; Oyuncu 0 rengi
        lda #$cc
        sta $02c1 ; Oyuncu 1 rengi

;tüm yaratik bellegini temizle
        jsr YaratikBelleginiTemizle

;yaratiklari olustur
        jsr OyunculariOlustur

;kesme rutini ayarla
        ldy #<Rutin
        ldx #>Rutin
        lda #$07
        jsr $e45c ; SETVBV
        jmp *

;ana rutin
Rutin
        lda O1_Durum
        beq Oyuncu2Hareketli
;eger oyuncu 1 hareket halindeyse
        +TOPLA16        O1_Hiz, O1_Ivme
        +TOPLA16        O1_X, O1_Hiz
        lda O1_X+1
        sta $d000 ; Oyuncu 0 X pozisyonu
        jmp CarpismaKontrolu
Oyuncu2Hareketli
;eger oyuncu 2 hareket halindeyse
        +TOPLA16        O2_Hiz, O2_Ivme
        +TOPLA16        O2_X, O2_Hiz
        lda O2_X+1
        sta $d001 ; Oyuncu 1 X pozisyonu
;carpisma kontrolu
CarpismaKontrolu
        lda $d00c ; Oyuncu 0 - Oyuncu 1
        cmp #$02  ; carpisma kontolu
        bne RutinSonu
;carpisma bayraklarini sifirla
        lda #$00
        sta $d01e ; Carpisma temizleme
;oyuncularin durum ve hizlarini degistir
        +DEGISTIR8      O1_Durum, O2_Durum
        +DEGISTIR16     O1_Hiz, O2_Hiz
;pes pese carpisma olusmamasi icin
;oyuncularin arasinda carpisma
;sonrasi belirli bir mesafe birak
        lda O1_X+1
        clc
        adc #$08
        sta O2_X+1
        sta $d001 ; Oyuncu 1 X pozisyonu
RutinSonu
        jmp $e462 ; RETURN

;2kb'lik yaratik bellegini temizle
YaratikBelleginiTemizle
        lda YaratikBellegi
        sta $f7
        lda YaratikBellegi+1
        sta $f8
        clc
        adc #$08
        sta endOfBlock
        ldy #$00
        lda #$00
Dongu1  sta ($f7),y
        iny
        bne Dongu1
        inc $f8
        ldx $f8
        cpx #$ff : endOfBlock = *-1
        bne Dongu1
        rts

;oyunculari y pozisyonlarina
;gore olustur
OyunculariOlustur
        lda YaratikBellegi
        sta $f5
        lda YaratikBellegi+1
        clc
        adc #$04
        sta $f6
;oyuncu 1
        ldx #$00
        ldy O1_Y
Dongu2  lda HaritaBasi,x
        sta ($f5),y
        iny
        inx
        cpx #HaritaSonu-HaritaBasi
        bne Dongu2

        inc $f6
;oyuncu 2
        ldx #$00
        ldy O2_Y
Dongu3  lda HaritaBasi,x
        sta ($f5),y
        iny
        inx
        cpx #HaritaSonu-HaritaBasi
        bne Dongu3
        rts

HaritaBasi      !byte %00011000
                !byte %00111100
                !byte %01111110
                !byte %01111110
                !byte %11111111
                !byte %11111111
                !byte %11111111
                !byte %11111111
                !byte %11111111
                !byte %11111111
                !byte %11111111
                !byte %01111110
                !byte %01111110
                !byte %00111100
                !byte %00011000
HaritaSonu      = *

O1_Durum        !byte $01
O1_Hiz          !byte $00,$00
O1_Ivme         !byte $08,$00
O1_X            !byte $00,$30
O1_Y            !byte $74

O2_Durum        !byte $00
O2_Hiz          !byte $00,$00
O2_Ivme         !byte $f8,$ff
O2_X            !byte $00,$7c
O2_Y            !byte $74

YaratikBellegi  !byte 0,0

BITIS_ADRESI = *
        !word $02e0, $02e1, BASLANGIC_ADRESI

13. Değerlendirme

Bu bölümde net bir biçimde "Oyuncular ve Füzeler", daha genel tanımıyla "Yaratıklar" konusunu Atari'ye özelleştirilmiş bir biçimde görmüş olduk. Ancak unutmayın ki donanım destekli yaratıklar her ne kadar bilgisayardan bilgisayara farklılıklar gösterse de, kullanım amacı olarak aynıdırlar. Bir bilgisayar üzerinde bu konuyu iyice anladıktan sonra diğer bilgisayarlarda bu konuya kolayca adapte olabilirsiniz. Genellikle;

- ...demek ki Atari'de 8 pixel genişliğinde olan yaratıklar Amiga'da 16, Commodore 64 ve 128'de 24 pixel genişliğindeymiş. Amiga'da da Atari'deki gibi istenilen yükseklikte gösterilebiliyormuş yaratıklar ancak Commodore'da 21 pixel yüksekliğindelermiş ve daha uzun bir yaratık göstermek istenilirse multiplexer isimli bir yöntem kullanılıyormuş."

gibi kıyaslamalarla birçok donanımı daha iyi anlamak ve birbirlerine göre avatajlarını / dezavantajlarını tartmak mümkündür.

İkinci bölümün sonunda henüz Atari'de çok temel kavramları öğrenmiş durumdayız. Aslında klavye, joystick kontolleri, kesme rutinleri gibi birkaç konuyu daha gördükten sonra basit bir oyun yazmanız için yeterli donanım bilgisine ve örnek kaynak kodlara sahipsiniz. Dilerseniz bir sonraki yazıyı beklemek yerine internet tarayıcınızın adres çubuğuna "http://www.atariarchives.org" yazın ve birşeyler yapabilmek için bilgi eksikliğiniz olan kısımları araştırmaya başlayın. Kolay gelsin.

emir (at) akaydin (nokta) com

plazma - (2006 - 2011)