)lye 7
Bu ay da buna benzer bir yardımcı prog- Tam üzerinde çalışacağız. Geçen ayki program sayesinde menü elemanlarını kolaylıkla seçebiliyorduk, ama seçici elemanımız sadece yukarı ve aşağı hareket edebiliyordu. Bu yüzden biraz daha kullanışlı bir şeyler tasarlamaya karar verdim. Ekranda duran bir şeyleri seçmek için yardımcı bir eleman düşündüğümüzde aklımıza ilk gelen şey, GEOS'ta veya AMIGA'da bulunan ok işareti oldu. Eğer yeterince &snek programlanırsa, makine diliyle ilgilene-'
memiş programcılar bile bu okun getireceği kolaylıktan faydalanabilecekti. Ama ilk olarak, istediğiniz anda gerekli bilgiyi sunan bir program yaratmamız gerekiyordu. Bu yüzden bir programcının ne gibi şeyler kullanmak di dük ve aklımıza ilk olarak şunlar geli 1) BASIC kullanıcıları genelde karakter ekranında çalışacağı için okun bulunduğu karakter pozisyonu her an ulaşılabilecek bir yerde durmalıydı. 2) Grafik ekranında çalışan kişileri için de
0-0 o...
bulunulan koordinat nokta olarak da elde edilebilmeliydi. 3) Her an, “Ateşe basılmış mı, basılmamış mi?” diye kontrol etmemek için ateşe basıldığında, okun bulunduğu koordinat kullanıcının her an erişebileceği bir yer olmalıydı. Ama her şeyden önemlisi, bu bilgiler otomatik olarak ayarlanmalı ve kullanıcıya sunulmalıydı. Yani program kendi başına joystick port-2'yi okuyup oku hareket ettirmeli, bu bilgileri hesaplamalı ve gerekli yerlere yazmalıydı. İlk olarak kağıt kalemi alip programı bloklar halinde tasarlamamız gerekiyor. Biliyorum, hepiniz programı doğrudan doğruya bilgisayar üstünde tasarlamak istiyorsunuz, Bir zamanlar ben de öyle düşünürdüm. Ama unutmayın, iyi bir programcının progher şeyi iyice planlayıp kağıda dökmekten daha iyi bir yol düşünemiyorum. Hem ka- Bit üzerinde proje bloklarını gösterebildiğiniz andan itibaren tüm programı aynı anda kafanızda gerek kalmaz. Belli bloklara konsantre olarak çok daha etkin programlar yazabilirsiniz.
TABLO I
Her neyse, konuyu fazla dağıtmayalım. “İlk olarak kağıt üzerinde programı tasarlamalıyız” diyordum en son. Programa giriş kismi, yalnızca sistemi rahatsız etmeyen bir interrupt kurmalı, okun grafik dataları için gerekli yerleri ayarlamalı (o anda kullanılıyor olabilecek yerleri rahatsız etmeden tabii ki) ve BASIC'e dönmeli. Tabii ki bu aşamada ne tür bir interrupt kullanmamız gerektiğine de karar vermemiz gerekiyor. Bize göre, ekranın her taranışından sonra portlar okunup gerekli ayarlamalar yapılırsa yeterince hassas bir hareket elde ede- Tiz. Hem de sprite'ın pozisyonu, elektron ekranın dışındayken değiştirileceği için türeme gibi sorunlarla karşılaşmayız. Bu yüzden $0100 raster satırında oluşturulacak bir RASTER interrupt'ın amaçlarımıza hizmet edebileceğini düşündük. Daha sonra, okun grafik özelliklerine ka- Tar vermemiz gerekiyordu. Tabii ki serbestçe dolaşabilmesi için bir sprite olmalıydı okumuz, Sprite 1'i bu işe ayırmaya karar verdik. Sprite Vin seçilmesi için belli bir şeyi göz önüne almadık. Yani ilk sprite'ın ya da sprite'in kullanılması o kadar da önemli de- Bil. ama tutup da beşinci sprite'ı ok için ayırmanın hiç alemi yok açıkçası. Her neyse, şimdi de sprite'ın özelliklerini tartışmamız gerekiyor: 1) Multi-color (çok renkli) olmamalı, çünkü çok kötü görünür. 2) Ekranda rahatça seçilebilecek, parlak bir renk olmalı. 3) Karakterlerin altından değil, üzerinden geçmeli, 4) X ve Y'de büyütülmemiz olmalı (gene görüntü yüzünden), Sprite'ı tanımlarken tüm bu değerlerin bizâm ayarlamamızda yarar var. Çünkü bizim programdan önce birileri çok renkli, X ve Y'de büyütülmüş ve karakterlerin arkasın-
VE da dolaşan bir sprite kullanmış olabilir (Her zaman en kötüyü düşünün). Bu durumda istediğimiz şartların hemen hemen hiçbiri sağ- Tanmamiş olur. Sprite ayarlamalarını yaparken dikkat etmemiz gereken ön önemli şey, diğer sprite'- lara elimizden geldiğince az dokunmak olmalı. Yani birinci sprite'ı açmak için: LDA e $01 STA $DO15 değil de;
LDA $DO15
ORA e $01
STA $DO15
kullanmalıyız. Bu sayede yalnızca birinci sprite'ın açılacağını garanti ederiz ve diğer sprite'ları ne açarız ne de kaparız. Oldukları gibi kalırlar. Aynı şekilde Sprite'ın çok renkli modda olmamasını sağlamak için:
LDA 1 $00
STA $DOIC
yerine
STA $DO1C
kullanmamız gerekir. Bu komutla sadece sıfırıncı bitin değerini sıfırlarız ve diğerlerine dokunmamış oluruz. Bütün gerekli VIC adreslerini ayarladıktan sonra, okun grafik datalarını boş bir bölgeye taşıyıp, burayı birinci sprite olarak ekrana çıkartmalıyız. Biliyorsunuz ki, BASIC kullanıldığında $0801-$9FEF arasındaki bölgeye güvenemezsiniz. VİC'in birinci sayfasını kullanmak istediğiniz için (ekranın tüm elemanlarını $CO00'dan kontrol etmek istemezsiniz sanırım) $0400'ün altında bir boş yer bulmalısınız. En uygun yerlerden biri $0380 olduğu için bu bölgeyi ok datamız için seçtik ve buraya grafik datalarını taşıdık. $07F8'i de“$0380'i gösterecek şekilde ayarladıktan sonra grafikle ilgili tüm işimiz bitmiş oldu. Artık gönül rahatlığıyla interrupt'- lara izin verip, BASIC'e dönebeliriz. Dikkat ettiyseniz, şimdiye kadar programın diğer kısımları bizi hiç ilgilendirmedi. Bu kısımların kendi görevini kusursuz olarak yaptığını varsayarak programın birinci kısmını tamamladık. Kağıt üstünde çalışmanin en iyi yanı işte. Eğer interrupt'ı açarak işe başlasaydık, sonrasına bir sürü ekleme yapmamız gerekecekti ve programımız gittikçe kontrolden çıkacaktı. Gelelim programın ikinci kısmına, Buradan okun hareketleri kontrol edilecek ve gerekli adreslere okun durumuyla ilgili bilgiler yazılacak. İlk olarak kendimize beş tane değişken tanımlayalım. Bu değişkenler belli adreslerde bulunsun ve daha sonra tasarlayacağımız bir rutin bu adreslerin değerlerini, joystick'in yönüne ve ateşin konumuna göre ayarlansın. Bu beş adresten başta, BA-SIC'ten kontrol edilecek olan değişkenlerimiz de hazır dursun. Bu değişkenler tasarımımıza göre şöyle olmalı: 1. Okun X, Y koordinatı (nokta olarak). 2. Okun X, Y karakter pozisyonu. 3. Ateşe basıldığında okun bulunduğu X, Y karakter pozisyonu. Toplam sekiz adet değişkene ihtiyaç var. Fakat değişkenleri daha dikkati incelerseniz, değişkenlerden ikisinin iki bayttan oluşması gerektiğini anlarsınız. Bunlar X koordinatı 0-320 arasında değerler alabildiği için bu koordinatı saklayan değişkenler ikişer bayt olmalı, Bu 10 baytlık değişken sürüsünün de hazır bulunduğunu varsayalım. Şu anda yalnızca bu adreslerin içeriğine göre yapacağımız işlerle ilgilenmemiz yeter- Hi olur. Onları ayarlamaya da sıra gelecek. İlk olarak yukarı, aşağı, sol ve sağa gidilmesi için emir geldiyse ne yapacağımızı Söyleyen tabloyu hazırlayalım.
Tabloda da gördüğünüz gibi hesaplarla şu anda ilgilenmiyoruz, sadece neler yapmamız gerektiği hakkında genel bir fikir oluşturduk şu anda. Şimdi tek tek bloklarla ilgilenelim:
1) Oku yukarı atmak için:
İlk olarak okun bağıl (relatif) koordinatını (ekranın en üstü ve en solu O değerini almalı, sprite koordinatları için ise O değildir) kontrol edelim. Eğer Y değeri 0'dan büyükse © zaman değerini azaltabileceğimizi anlarız ve bu adreste bulunan değeri bir azaltırız. Y tek bir baytta saklandığı için tek bir CMP komutuyla bu karşılaştırma işini hallederiz. Ve DEC komutuyla da Y koordinatını azaltırız (unutmayın ekranın en üstü 0). 2) Oku aşağı almak: Yapılacak işler deminkinin hemen hemen aynısı. Yalnızca bu sefer y koordinatının 199'dan büyük olmamasına dikkat etmeliyiz. Oku aşağı olmak için y koordinatını bir artırmamız gerekir. 3) Oku bir sola almak: Eğer ekranın genişliği 255'ten küçük olsaydı bunu yapmak da yukarı ve aşağı oynamak kadar kolay olabilirdi. Ama 320 nokta genişliğinde bir ekranı iki baytla temsil ettiğimiz için bu iki baytın ortak değerinin O'dan büyük olmasını kontrol etmeliyiz. Bunun için ilk olarak yüksek bayta bakarız. Bu değer Vse “Zaten 256'dan büyük bir
Joystick'i oku ve Gerekli Değişkenleri Ayarla
Karakter Pozisyonunu Hesapla
Sprite Pozisyonunu Ayarla
TABLO 2
Y Pozisyonunu
TABLO 3 Oku aşağı al
<199?
Y Pozisyonunu bir artır
TABLO 4 Oku bir sola al
X'i bir azalt yerdeyiz” diyerek X koordinatını bir azaltırız. Eğer bu değer sıfırsa o zaman alçak değerli bayta bakarak X koordinatının O'dan büyük olup olmadığına karar veririz. Eğer büyükse X'i azaltmaya izin var demektir. X'in değerini azaltmak da ufak bir sorun yaratabilir. İlk olarak alçak değerli baytı azaltırız. Eğer bu baytın değeri 255 olmuşsa, yüksek değerli baytı bir azaltmamız ge-
TABLO 5
- tektiğini anlarız. Değilse zaten diğer kısımlara geçebiliriz. 4) Oku bir sağa almak:
Oku bir sağa al
TABLO 6
Burada yapılacak işler de neredeyse demin ki basamakla aynı. İlk olarak yüksek değerli bayta bakarız. Eğer bu baytın değeri sıfırsa hemen X koordinatını artırmaya girişiriz. Eğer baytın değeri 1'se o zaman alçak değerli baytın 63'ten küçük olup olmadığını kontrol ederiz ($0140 olduğu için, 255 üstündeki değerlerde alçak bayt ancak 64'e yani $40'a kadar çıkabilmeli). Eğer şartlar uygunsa X'i bir artırabiliriz. X'i artırabilmek için, gene ilk olarak alçak baytı artırmalıyız. Eğer alçak bayt sıfır değerini almışsa, yüksek baytı da artırırız ($00FF'den $0100'a gelindiği için). 5) Koordinatı gerekli yere kaydet:
Koordinatı gerekli yere kaydet
TABLO 7
Buradaki işimiz oldukça kolay. İlk olarak X koordinatını olduğu gibi Ateş X koordinatına taşımalıyız (iki baytın da). Daha sonra da X koordinatının karakter pozisyonunu hesaplamalıyız (Bunu yapmak göründüğü kadar da zor değil). İlk olarak alçak baytı üç adet LSR kullanarak sekize böleriz ve bu değeri Ateş X karakter pozisyonu değişkenine yazarız. Daha sonra yüksek baytın değerine bakarız. Eğer 0 ise işimiz kolaydır: Hiçbir şey yapmayız! Ama bu adreste 1 varsa o zaman 256/8'in değerine bakarız. 32 sayısı tam bir bit olduğu için bu değeri doğrudan doğruya Ateş X karakter değeriyle ORA'layarak toplama işlemini gerçekleştirebiliriz. Böyle bir CLC'den kâr ederiz. Daha sonra Y koordinatını Ateş Y koordinatına taşırız. Üç LSR'de burada kullanarak Y'nin karakter pozisyonunu hesaplarız ve Ateş Y karakter pozisyonuna bu değeri yazarız. Böylece ateşe basıldığında yapılacak işleri de bitirmiş oluruz. 6) Karakter pozisyonunu hesapla:
Demin yaptığımız işlemler yalnızca ateşe basıldığında yapılacağı için, şimdi bir kez daha bu işlemleri yapmalıyız. Daha sonra $0-
Karakter Pozisyonunu hesapla nucu okun o anda bulunduğu yerin karakter pozisyonunu yazabiliriz. 7) Sprite pozisyonuna ayarla:
TABLO 8
Sprite Pozisyonunuayarla
TABLO 9
Demin de söylediğim gibi, X ve Y koordinatları ekrana göre relatif. Bir sprite için ekranın en tepesinin Y koordinatı 50'dir. Oysa biz bu değeri 0 olarak saklıyorduk. Öyleyse ilk olarak Y koordinatı değerimize 50 eklemeliyiz. Sonucu da sprite 1'in Y pozisyonuna yazabiliriz. Tabii ki X koordinatı işleri gene karıştıracak. Çünkü iki bayt. Ekranın en solunun koordinatı 24 olduğuna göre X koordinatı işleri gene karıştıracak. Çünkü iki bayt. Ekranın en solunun koordinatı 24 olduğuna göre X'e de 24 eklemeliyiz. Ama orijinal değerleri bozmamak için geçici bir değişken üzerinden toplamayı yapıyoruz. İlk olarak geçici değişkenin yüksek baytına X'in yüksek baytının değerini yazıyoruz. Daha sonra X'in alçak baytına 24 ekliyoruz. Bu değeri geçici değişkenin alçak baytına yazdıktan sonra CARRY'nin durumundan yüksek bayta ne yapacağımıza karar veriyoruz. Eğer Carry 1'se, yüksek baytın da bir olmasını sağlıyoruz. Daha sonra alçak baytı X koordinatına yazıyoruz ve yüksek baytın durumuna göre MSB'nin ilk bitinin değerini ayarlıyoruz.
Her şeyi ayarladığımıza göre artık BASIC'e de çalışmak için bir şans tanıyabiliriz. Yani $EA31'e sıçrama zamanı geldi. Tabii ki önce $D019'a kendisinden haberdar olduğumuzu söylemeliyiz. Artık yapacak tek şey kaldı: Joystick'i okumak. En başta iki portu da okumak istiyorduk, fakat bunu yaptığımızda 1 ve 2 tuşlarına her basıldığında okun hareket ettiğini gördük ve hareketi yalnızca Port 2'nin kontrol etmesini sağladık. Aslında uzun uzun kontrollerle gelen sinyalin klavyeden mi yoksa Joystick'ten mi geldiğini anlayabiliriz, ama amacımız olabildiğince kısa programlar yapmak olduğu için bunu yapmayacağız. Port 2'nin değerini kontrol etmek düşündüğümüzden de kolay oldu: İlk olarak yukarı, aşağı, sol, sağ ve ateş değişkenlerini sıfırlamalıyız. Böylece hiçbir değişiklik yapmadan geri dönmemiz joystick'de hareket olmadığı anlamına gelir. Joystick'in pozisyonunu okumak için PORT 2'nin durumunu gösteren $DC00'ı okumalıyız. Bu baytın ilk dört bitinde Joystick'in o anda bulunduğu konum gösteriliyor. Ama ters olarak. Yani yukarı itildiyse sıfırıncı bitin değeri 0 oluyor. 5. bit de ters olarak ateşin durumunu gösteriyor. Joystick'de hareket olup olmadığını anlamak amacıyla ilk olarak $DC00'ı okuyoruz ve & $1F ile AND'liyoruz. Eğer sonuç #$1F'se joystick kıpırdatılmamıştır ve geri dönebiliriz. Ama bitlerden biri bile sıfırsa hangi bitin sıfır olduğunu bulmamız gerekir. Bit tarama kısmında bol bol AND kullanacağımızdan ve bu komut A'nın diğer bitlerini yok edeceğinden, en iyisi PHA'yı kullanıp baytı yığına atmak olacaktır. Daha sonra sırasıyla gerekli biti AND'leyerek, o yöne bir hareket olup olmadığını anlayabi-
Bütün bitler için bu işlem aynen uygulandığı için sadece biri için nasıl yapıldığını anlamamız yeterli olacaktır sanırım. Mesela ateş tuşunu kontrol edelim: Her işlemden önce bir kez PLA ve hemen arkasından PHA kullanışımız dikkatinizi çekmiş olabilir. Biliyorsunuz yığından değeri aldığımızdan bu değeri kaybederiz. Oysa, bir sonraki kontrol için aynı değere ihtiyacımız vardır. Bu yüzden kullandığımız PHA komutuyla değeri yığına geri atarız. Daha sonra baytı $10 (ateş tuşunun 5. bit olduğunu unutmayın) ile AND'leriz. Eğer sonuçta akümülatörde yani A'da 00 olursa ateşe basılmış demektir. Değer sıfırdan farklıysa ateşe basılmamıştır, öyleyse yolumuza devam edebiliriz. Bu kontrol için CMP kullanmaya gerek yoktur. BNE'yi doğrudan kullanırsanız, değer sıfırdan farklı olduğunda sıçrama yapılacaktır. Tüm yönler için gerekli kontrol yapıldığında ana rutine dönerek döngüyü tamamlarız. Programın makine dili çıktısını PROGRAM 1 tablosunda görebilirsiniz. Eğer makine diliyle ilgileniyorsanız programı incelemenizi öneririm. Hatta programı incelerken ara sıra yazıya da göz atarsanız oldukça yararlı olacağına inanıyorum. Tüm BASIC kullanıcılarından özür dilerim, bu ay makine dilini biraz fazla kaçırdım. Bu yüzden gelecek sayının ATÖLYE'sinde sadece bu okun BASIC'ten kullanımı konusundan bahsedeceğim. Şimdilik incelemeniz için basit bir BASIC programını PROGRAM 2 tablosunda yayınlıyorum. Hatırlarsanız geçen ayın atölyesinde, ekranda duran renkli şeritleri açıp kapatmak için ne yapmamız gerektiğini sormuştum. Sorunun doğru cevabını yollayan iki arka-
Yön baytlarını sıfırla
Joystick'i Port 2'yetak
Yön ya da ateş şımız oldu: Nuri Özhendekçi ve Caner Şimşir. Caner Şimşir'in cevabı rutine girişteki BMI komutunu doğrudan $EA31'e sıçrayacak şekilde değiştirmekti (POKE 49204,0 ile renkler kapanır). Görünüşte doğru olsa da ufak bir hata bulunuyor bu çözümde: Raster interrupt'ından çıkmış olmamıza rağmen $D019'un değerini düzeltmediğimiz için, interrupt'ı terk eder terketmez yeni bir interrupt daha oluşturuyor ve bu yüzden bilgisayar BASIC'le ilgilenecek zaman bulamıyor. Kısaca bilgisayar kilitleniyor. Nuri Özhendekçi'nin çözümü ise tamamen doğru:
TABLO 10
POKE 49204,30: kapalı
POKE 49203,3: açık
49204'e 39 verdiğimiz zaman, Raster interrupt yapılmış bile olsa $D019 artırılıyor ve $EA31'e öyle sıçranıyor. Bu yüzden bilgisayar her şeyi normal şekilde devam ettirebiliyor. Bu adrese 3 verdiğinizde her şey eskisi gibi çalışmaya devam ediyor. Her iki arkadaşımıza da gösterdikleri ilgiden dolayı teşekkür ediyorum. Nuri arkadaşımızın önerdiği ROM dökümünü ise ne yazık ki yayınlamamız mümkün değil, çünkü bu iş tek başına oldukça kalın bir kitabı dolduruyor.
Bu arada, Abur-Cubur köşesinin tekrar açılması için program gönderebileceklerini belirten oldukça mektup aldık. Eğer gerçekten bu köşenin tekrar açılmasını istiyorsanız programlarınızı yollayın (Abur-cuburlukları tabii ki). Eğer yeterince program birikirse köşeyi tekrar açabiliriz.
Gelecek ay görüşmek üzere hepiniz hoşçakalın,
NOT: Atölyeyle ilgili mouse programlarını Döküm Eki'nde bulabilirsiniz.