Bu sayfadaki yazılar
Sayfanın metni
Sayfa 32
Selam! İşte yine beraberiz. Eh, artık bu yılın sonuna kadar vereceğim bilgiler, sizi bir hayli ileriye götürecektir. Geçen aya kadar copper renk çubuklarını nasıl yaratabileceğimizi görmüştük. Bu ay ise bir adım daha ileri giderek sprite konusuna gireceğiz.
Herkesin bildiği gibi sprite'lar, bir oyunda bob'lardan sonra gelen en önemli grafik parçalarıdır. Bob kullanmadan sadece sprite'lar ile de oyun yapmak mümkün. Sprite'ların bob'lara karşı büyük bir avantajları vardır. Hardware kontrol elektroniğinde sprite'lar için ayrı bir kanal açılmıştır. Biz bu kanallara DMA (Direct Memory Access-hafızaya direkt erişim) adını veriyoruz. Bu, sprite'ların kullanımında hız farkının pek olmayacağı anlamına gelir. İster 1, isterseniz de tüm 8 sprite'ı da kullanın; hiçbiri yavaşlamaz. Bunun kazandırdığı dezavantajlardan biri (ve en önemlisi), sprite'ların adetlerinin 8 ile sınırlı olması.
Avantajlardan bir diğeri de, sprite'ların çarpışma dedektörünün bulunması. Bunun yardımıyla hangi sprite'ın bir diğer sprite ya da grafik ile çarpıştığını algılayabilir ve buna göre işlemlerde bulunabiliriz. Bob'larda bu işlemi yapmak için değişik teknikler kullanmamız gerekecek. Fakat bunu daha ilerde göreceğiz.
Diğer bir dezavantaj ise sprite genişliğinin ve renginin sınırlı olması. Sprite'lar, biri zemin rengi olmak üzere 4 renge sahip olabilirler. Genişlikleri de 16 pikselle sınırlıdır. Fakat buna karşı yükseklikleri ekran yüksekliği kadar olabilmekte. Değişik bir kullanım şekliyle sprite renklerini 16 renge kadar çıkarmak mümkün. Bu şekilde sprite genişliğimiz de 32 piksele yükselecektir. Bunun getirdiği dezavantaj ise sprite sayısının 4'e inmesi. Nedeni de, bu geliştirilmiş sprite'ların iki normal sprite'ın birleştirilmesiyle oluşturulduğundan olsa gerek.
Sprite'ların piksel boyutları ekran modunu değiştirdiğimizde değişmez. Interlace ya da Hi-res ekranda normal grafik pikselinin boyutu yarılanırken, sprite'ı oluşturan piksel boyutu aynı kalır.
Sprite'lar hafızada aynı ekranlarda olduğu gibi bitplane datası olarak saklıdır. Zaten sprite piksellerinin rengini de bu bitplane'lerdeki bitlerin durumları belirler. Bunun için Şekil 1'e bakınız. Burada bir uzay gemisinin renkler olarak görüntüsü yer almakta. Burada 0, 1, 2 ve 3 sayılarıyla renk pikselleri tanımlanmıştır. Bunu bitplane'lere çevirmemiz gerekmekte. Bildiğiniz gibi, her bir bitplane'deki tek bir pikselin değeri 0 ya da 1 olabilmekte. Eğer iki bitplane kullanırsak, 2^n formülüne göre 4 renk elde edebiliriz. Bu da bizim için yeterli olur. Şekil 2'de uzay gemimizin bitplane'lerini bulabiliriz. Bu bitplane'lerde bir pikselin renk değerini öğrenmek için her iki bitplane'deki pikselimize denk gelen biti yanyana getirmemiz yeterli olur. Bu şekilde elde edeceğimiz sayı, rengin binary olarak kodlanmış halidir. Bu binary sayıda soldaki hane ilk bitplane'deki bit, sağdaki hane de ikinci bitplane'de pikselimize denk gelen bitdir.
Sprite dizayn ederken zahmete katlanmak istemeyenler için ufak bir tiyo: Dilerseniz sprite'ınızı Deluxe Paint ile de hazırla-
6880888886888888 8888881111688888 6861111111111688 8822211111122286 8833333333333388 8822211111122288 8881111111111888 0000001111000000 0000000000000000
yabilirsiniz. Bunun için sprite'ı Deluxe Paint ile çizip resim olarak diskete kaydedin. Unutmayın; 2 bitplane kullanabilirsiniz. Şimdi Deluxe IFF Converter'in Save Sprite altmenüsünü kullanarak çizdiğiniz sprite görüntüsünü data tablosu şeklinde kaydedebilirsiniz. Bu altmenüde iki seçenek vardır: 4 ve 16. 4 ile normal sprite, 16 ile de genişletilmiş sprite olarak kayıt yapabilirsiniz. Artık yarattığınız sprite tablosunu text olarak Seka'dan okuyabilir ve programınızda kolaylıkla kullanabilirsiniz. Bu converter satırları da uygun olarak dizip az aşağıda göreceğimiz sprite koordinat bilgilerini de ekleyeceğinden kullanmanızı özellikle tavsiye ederim. Size kalan artık sadece koordinat bilgilerini uygun şekilde değiştirmek olacaktır.
Şimdiye kadar gayet iyi gittik; fakat hala sprite renklerini nasıl belirleyeceğimizi bilmiyoruz. Sprite'ın piksellerinin rengi copper'da renk register'lerinin üst 16'sı ile belirlenir. Bunun en büyük dezavantajı bazı renkleri sabitlememiz gerektiğidir. Bu yüzden yazdığınız programlarda sprite kullanıyorsanız, grafiğin paletini uygun olarak dizayn etmeniz gerekmekte. Ya grafiğinizi 16 renkle sınırlandıracaksınız, ya da grafikteki üst 16 rengin sprite renkleri olmalarına dikkat edeceksiniz. İkinci yöntemi kullandığınızda da çıkan tek sorun, sprite rengini program içinde değiştirmeye kalktığınızda (mesela cycle yapmak için) grafikte aynı renkte bir piksel varsa, bunun da renginin değişeceğidir. Şimdi dilerseniz Tablo I'e bir göz atalım. Burada, copper renk register'lerinin hangilerinin hangi sprite renkleri olarak kullanıldığını görebilirsiniz.
Sprite hazırlarken data olarak demin hazırladığımız bitplane'lerdeki bitleri kullanacağız. Her bir sprite satırı 16 bitten oluştuğundan, bunu word olarak yazabilmemiz mümkün. Burada dikkat edilecek tek konu satırların düzeni olacak. Data tablomuzda ilk satırda yer alan word sprite'ın ilk bitplane'inin ilk satırıdır. Ardından ikinci bitplane'deki ilk satırın karşılığı olan word gelmekte. Diğer sprite satırları da aynı şekilde sıralanarak data tablomuzu oluşturabiliriz. Data tablosunun sonuna word olarak iki adet 0 değeri eklemeyi unutmayın. Bu iki 0 sayesinde copper cipi sprite datalarının bittiğini anlar.
Fakat hala eksik olan bir şey var: Sprite'ın ekran koordinatlarını gösteren değerler. Bu değerleri nasıl kullanacağımızı görelim.
Sprite koordinatlarını oluşturmak için, sistem bize sadece iki byte ayırmış durumda. Fakat ekran boyutları birer byte'dan fazla yer kaplamakta. Bize, her iki koordinat için de fazladan birer bit daha gereklidir. Jay Miner, cipleri yaratırken bu iki bit yüzünden iki byte'ı fazladan harcamak istememiştir. Bu yüzden bu iki bit sprite koordinat taşma bitleri olarak başka bir byte içinde yer alırlar. Sprite koordinatı 256'yı geçmiyorsa, bu bitlerden uygun olanı 0 değerini alır. Fakat iki koordinattan biri 256 sınırını aşı-
8888888888888888 8000080808888888 8888888888800000 6000001111000000 8011188888611100 0806611111188868 0011111111111188 0011111111111100 0011100000011108 0000011111100000 0000000000000000 0000001111000000 0000000000000000 0000000000000000
Şekil 1 - Renk kodları olarak bir uzay gemisi Şekil 2 - Uzay gemisinin bitplane
olarak görüntüsü.
ASSEMBLER'da YENİ UFUKLAR
Klavyeyle gezinmek için ← ve → tuşları.
Sayfa 33
yorsa, uygun biti 1 yapmak ve koordinattan 256 değerini çıkararak kullanmak gerekmekte. Yükseklik koordinatı 256'yı geçmez diyenlerin yanıldığını hemen belirtmemde fayda var. Çünkü ekran koordinatları hemen ekranın sol üst köşesinde değil de, ekranın dışında bir yerlerdedir. Aynı şekilde ekranın bitişi de ekran
$dff1a0 - Sprite 0 ve 1 : renk 0 (zemin rengi) $dff1a2 - Sprite 0 ve 1 : renk 1 $dff1a4 - Sprite 0 ve 1 : renk 2 $dff1a6 - Sprite 0 ve 1 : renk 3 $dff1a8 - Sprite 2 ve 3 : renk 0 (zemin rengi) $dff1aa - Sprite 2 ve 3 : renk 1 $dff1ac - Sprite 2 ve 3 : renk 2 $dff1ae - Sprite 2 ve 3 : renk 3 $dff1b0 - Sprite 4 ve 5 : renk 0 (zemin rengi) $dff1b2 - Sprite 4 ve 5 : renk 1 $dff1b4 - Sprite 4 ve 5 : renk 2 $dff1b6 - Sprite 4 ve 5 : renk 3 $dff1b8 - Sprite 6 ve 7 : renk 0 (zemin rengi) $dff1ba - Sprite 6 ve 7 : renk 1 $dff1bc - Sprite 6 ve 7 : renk 2 $dff1be - Sprite 6 ve 7 : renk 3 dışında sağ alt taraflarda bir yerdedir. Bu şekilde, büyük ekran kullanmanın faydası Overscan modu kullanıldığında görülmekte. Kullanacağımız ekran koordinatları yatayda 0'dan 447'ye kadardır. Fakat görülür ekran yatayda 64 koordinatından başlar ve 383. yatay koordinata kadar devam eder (383-63=320 piksel genişlik). Aynı şekilde de dikey koordinatlar 0'dan 262'ye kadar uzanmakta. Fakat görülür ekran 44. dikey koordinattan başlar. Demek ki, sprite koordinatları x=64; y=44 koordinatlarından küçük olduğunda sprite kısmen ya da tümüyle ekran dışında kalabilir. DIWSTRT, DIWSTOP değerleriyle oynayarak ekran genişliğini artırdığınızda, bu koordinatlar da normal olarak azalacak ya da çoğalacaktır.
Tablo I - Sprite renk register'leri
Bu iki sprite koordinatı, sprite datasının başına eklenmeli. Fakat ilk önce dikey koordinat, ardından da yatay koordinat yazılmalı. Bundan sonra iki byte daha gelmeli. Bu iki byte'dan ilki yardımıyla sprite'ın yüksekliğini dolaylı olarak tanımlayabiliriz. Dikey sprite koordinatına sprite'ın yüksekliği-1 ilave ederek elde ettiğimiz değer ilk byte'ı oluşturur, ikinci byte ise demin de belirttiğim sprite koordinatı taşma bitleridir. Burada 0. bit, yatay taşma bitidir ve sprite koordinatı 255'ten fazlaysa 1 olmalıdır. 2. bit ise dikey taşma bitidir. Sprite'ın sadece alt kesimi 256 sınırını aşmışsa 1. bit 1 olmalı ve sprite koordinatı da uygun şekilde azaltılmalıdır. 3., 4., 5. ve 6. bit kullanılmadığından 0 değerini almalıdır. Son bit ise genişletilmiş sprite kullanıldığında 1 yapılmalı.
Sprite datalarının adresini SPRxPTH ve SPRxPTL copper register'leri yardımıyla sisteme bildiririz. Bitplane adreslerinde olduğu gibi, SPRxPTH register'i adresin üst word'ünü ($000x), SPRxPTL ise adresin alt word'ünü ($xxxx) tanımlamak için kullanılır. Sprite adres register'lerinin copper register'lerini Tablo III'te görebilirsiniz. Şimdilik sprite teorisi olarak bu kadar bilgi herhalde yeter. Daha ilerde sprite çarpışmalarına da detaylı olarak ineceğiz. Ama şimdi dilerseniz kalan yerde de programımızı kısaca açıklamak istiyorum.
Programı başından başlayarak takip edersek, ilk satırlarda
Bitplane 0 satır 0, bitplane 1 satır 0 Bitplane 0 satır 1, bitplane 1 satır 1 Bitplane 0 satır 2, bitplane 1 satır 2 Bitplane 0 satır 3, bitplane 1 satır 3 . . . Bitplane 0 satır n, bitplane 1 satır n
Tablo II - Sprite datalarında satırların dizilişi
CREATECOPPERS altrutinine gidildiğini görebiliriz. Bu altrutine bir göz atalım. İlk satırda, Copper listemizin 68 byte sonrasının adresinin a0'a yazıldığını görüyoruz. Copper listesine bakacak olursak, burada iki tane 136 byte'lık (4*17*2 byte!) boş bölge açıldığını görüyoruz. Bu bölgelerden ilkine basit bir loop yardımıyla ufak bir copper listesi yerleştiriyoruz. Aynı şekilde de ikinci bölgeye de az önce yarattığımız listenin tersini yerleştiriyoruz. Bu iki döngüyü inceleyerek öğrenmenizde fayda var. İleride bu tür rutinleri çok kullanacağız.
SPR0PTH - $dff120 - Sprite 0 data tablosu adresi üst word SPR0PTL - $dff122 - Sprite 0 data tablosu adresi alt word SPR1PTH - $dff124 - Sprite 1 data tablosu adresi üst word SPR1PTL - $dff126 - Sprite 1 data tablosu adresi alt word SPR2PTH - $dff128 - Sprite 2 data tablosu adresi üst word SPR2PTL - $dff12a - Sprite 2 data tablosu adresi alt word SPR3PTH - $dff12c - Sprite 3 data tablosu adresi üst word SPR3PTL - $dff12e - Sprite 3 data tablosu adresi alt word SPR4PTH - $dff130 - Sprite 4 data tablosu adresi üst word SPR4PTL - $dff132 - Sprite 4 data tablosu adresi alt word SPR5PTH - $dff134 - Sprite 5 data tablosu adresi üst word SPR5PTL - $dff136 - Sprite 5 data tablosu adresi alt word SPR6PTH - $dff138 - Sprite 6 data tablosu adresi üst word SPR6PTL - $dff13a - Sprite 6 data tablosu adresi alt word SPR7PTH - $dff13c - Sprite 7 data tablosu adresi üst word SPR7PTL - $dff13e - Sprite 7 data tablosu adresi alt word
TABLO III - Sprite adres register'leri __________________
Ana rutinimize dönüp baktığımızda, yeni copper listesinin aktif edilmesinden hemen sonra sprite datalarının adresinin copper listesine yazıldığını görüyoruz. Bu şekilde doğru sprite adreslerini copper cipine bildirmiş oluruz.
Programda açıklanacak başka yer kalmıyor. Herhalde gerisini siz de kolaylıkla anlayabilirsiniz. Eh, zaten bu aylık yerimiz de doldu. Artık gelecek ay tekrar görüşmek üzere hoşçakalın demekten başka bir şey kalmıyor bana da ...
; >» GELİŞMİŞ ASSEMBLER KURSU <« ; >» COPPER DEMONSTRASYON PROGRAMI 03 <« ; >» by Cem GENCER-1992 <«
Q: movem.l d0-d7/a0-a6,-(a7) move.l 4,a6 lea GFXNAME,al jsr -408(a6) move.l d0,GFXBASE bsr.L CREATECOPPERS move.l GFXBASE,a0 add.l #50,a0 move.l (a0),OLDCOPPER move.l #NEWCOPPER,(a0) lea NEWCOPPER,a1 lea SPRITE,a0 move.l a0,d0 move.l a0,d1 swap d 1 and.l #$ffff,d0 and.l #$ffff,d1 move, w dl,6(a1) move.w d0,10(a1) LOOP: cmpi.b #$ff,$dff006 bne.S LOOP MOUSE: btst #6,$bfe001 bne.s LOOP bra.s FIN FIN: move.l GFXBASE,a0 add.l #50,a0 move.l OLDCOPPER,(a0)