20. Bölüm
Cenker Özkurt
Amiga C'de bu ayki konumuz Sprite'lar. Geçen ay Amiga'da IFF yükleme'den bahsetmiştim. Bu ay da geçen ay olduğu gibi örnekler üzerinde çalışarak Sprite'ları inceleyeceğiz.
İlk olarak Sprite'ın tanımı üzerinde biraz duralım. Sprite, Amiga'nızdaki hareket edebilen şekilleri oluşturuyor. Mesela oyunlardaki birçok şekil, genelde sprite olarak tanımlanıyor.
Amiga'nızda toplam sekiz adet sprite mevcut. Bu sprite'lar hardware olarak hazırlanmış. Dolayısıyla sprite sayısını arttırmamız mümkün değil. Fakat software olarak da blitter yardımıyla sprite benzeri şekiller oluşturabiliyoruz. Bunlara kısaca BOB (Blitter Object) adı veriliyor. Bob'ların sayısı sınırsız olabiliyor. Fakat gene de bazen sekiz adet sprite yetiyor. Aynı zamanda sprite'ların kullanımı da oldukça kolay.
Sprite'ların ekran üzerinde hiçbir etkisi yoktur. Mesela bir resmin üzerine yerleştirmiş olduğunuz sprite alttaki, resmi etkilemez. Çünkü daha önce de söylediğim gibi, sprite'lar hardware olarak ekrana getirilmektedir.
Sprite'ların getirmiş olduğu bazı kısıtlamalar var. Birincisi, sprite'ın eni maksimum 16 piksel (1 WORD) uzunlukta olabilmesi. Ancak boyu sınırsız olabiliyor. İkincisi, bir sprite'ın renk sayısı, maksimum 4 adet olabiliyor. Fakat sprite'ları birleştirerek daha fazla renk ve genişlik elde etmek mümkün.
Sprite'lar toplam 16 renk kullanabiliyorlar. Bu 16 rengi ikişer ikişer paylaşmaktalar. Sprite'ların kullandıkları palet numaraları ve sayıları ise şöyle:
Sprite Numarası Palet Numaraları
0 ve 1 16-17-18-19
2 ve 3 20-21-22-23
4 ve 5 24-25-26-27
6 ve 7 28-29-30-31
Ayrıca kullanmış olduğunuz mouse. 0 numaralı sprite'ı oluşturuyor. Sprite'ların bir de öncelik sırası mevcut. İlk sprite en önde olacak şekilde, sprite'lar 0'dan 7'ye kadar dizilmiştir. 0 ve 1'inci sprite'lar birbirleri üzerinden geçişirken, 1 numaralı sprite 0 numaralı sprite'ın arkasında görülmektedir.
Yukarıda vermiş olduğumuz listeye göre herhangi bir sprite'ın renginin ayarlanması ise şöyle yapılıyor:
Rengini değiştirmek istediğimiz sprite numarası 2 olsun. Buna göre 2 numaralı sprite için paletle oynayarak,
SetRGB4(vp,20,15,0,0); SetRGB4(vp,21,0,15,0); SetRGB4(vp,22,0,0,15); SetRGB4(vp,23,15,15,15);her paleti istediğimiz gibi ayarlamamız mümkün. Burada vp, ekranın ViewPort structure yapısını; 20-21-22 ve 23 sayılan palet numaralarını ve diğer sayılar da sırasıyle RGB (kırmızı, yeşil, mavi) değerleri oluşturuyor. Eğer 4 numaralı spriıe'm rengini ayarlamak isteseydik. 24-25-26 ve 27 numaralı paletleri ayarlamamız yeterli olacaktı.
Şimdi gelelim C'de sprite structure yapılarının kullanımına.
Sprite'lar için iki tane yapı değişkenimiz bulunuyor. Bu değişkenlerden birincisine, oluşturduğumuz, sprite'ın şeklini ve ilk koordinatını saklıyoruz. Yalnız bu yapı değişkenini ya kendimiz hazırlamalıyız, ya da aşağıda vereceğim örnekte olduğu gibi kullanmalıyız:
struct SpriteImage
{
UWORD posctldata[2];
UWORD sprdata[2][height];
UWORD reserved[2];
};
Görüldüğü gibi, yapı değişken ismimiz SpriteImage. Kapsadığı diğer değişkenler ise,
posctldata[2] (Position Control Data): Sprite'ın ilk andaki konumunu gösteriyor.
sprdata[2](height) (Sprite data): Sprite'ın yüksekliğini gösteriyor. Sprite'ın yüksekliğini istediğimiz gibi ayarlayabiliriz. Vermiş olduğumuz kadar yükseklik verisi girmeyi de unutmamalıyız. Dikkat ettiyseniz, sprdata için iki adet data girişi sağlanıyor. Bunun sebebi, daha önce de söylediğim gibi, sprite'ların 4 renk kullanmasından kaynaklanıyor. 4 renk için 2 bitmap gerektiğini unutmayalım.
reserved[2]: Bu değişkeni de, ileride sprite'ın kullanımı için boş olarak ayırıyoruz.
Sprite hazırlarken kullanacağımız ikinci yapı değişkenimiz ise SimpleSprite. Bu değişken vasıtasıyla sprite'ı istediğimiz gibi ayarlayarak kontrol ediyoruz. Bu değişken include dosyaları içinde sprite.h dosyasında tanımlanıyor.
struct SimpleSprite
{
UWORD *posctldata;
UWORD height;
UWORD x,y;
UWORD num;
};
posctldata: SpriteImage değişkeninin adresini göstermek için kullanıyoruz.
Şu ana kadar, sprite hazırlarken kullanacağımız kontrol yapı değişkenlerini gördük. Şimdi de bir sprite'ın şeklinin nasıl hazırlandığını görelim.
İlk olarak sprite'ımızın şeklini ikilik (binary) sistemde bir kağıt üzerinde hazırlayalım. Fakat şeklimizi hazırlarken 4 renk kullanacağımızı unutmayalım. Bu nedenle sprite'ın ilk satırını çizerken iki ayrı datayı arka arkaya vermeliyiz. Bunlardan birincisi ilk bitmap'i, ikincisi ise ikinci bitmap'i oluşturuyor. Bunu bir örnekle inceleyelim:
1111000000000000 =0xf000 0000000000001111 =0x000filk satır datalarımız bunlar olsun. Dikkat ettiyseniz, binary olarak şeklimizi sağdan sola 16 pixel (16 bitlik = 1WORD) olarak hazırladık, 0xf000 ilk satır bitmap'imizi, 0x000f ise ikinci satır bitmap'imizi hex olarak gösteriyor. Buna göre sağdaki ilk pixel'in renk numarası 3 oluyor. Hesabını şöyle yapabilirsiniz:
2^1 * 0 + 2^0 * 0 = 0 -> birinci renk, 2^1 * 0 + 2^0 * 1 = 1 -> ikinci renk, 2^1 * 1 + 2^0 * 0 = 2 -> üçüncü renk, 2^1 * 1 + 2^0 * 1 = 3 -> dördüncü renk için.Daha sonra tablosunu hazırladığımız şeklin verilerini hex olarak SpriteImage yapı değişkenine şöyle tanıtabilirsiniz:
struct SpriteImage *SprIm =
{
0,0,
0xf000, 0x000f,
...
...
0,0
};
Sıra geldi, C'de kullanacağımız sprite komutlarına. İlk olarak ChangeSprite() fonksiyonu üzerinde inceleme yapalım.
Kullanımı: ChangeSprite(ViewPort,SpritePtr,SpriteImPtr);
Fonksiyonu: SimpleSprite yapı değişkeni üzerinde yapmış olduğumuz değişiklikleri SpriteImage yapı değişkenine aktarır.
Parametreleri:
ViewPort -> ViewPort structure yapısı.
SpritePtr -> SimpleSprite structure yapısı.
SpriteImPtr -> SpriteImage structure yapısı.
GetSprite() fonksiyonu ise şöyle çalışıyor:
Kullanımı: SpriteNr1 = GetSprite(SpritePtr,SpriteNr2);
Fonksiyonu: SimpleSprite structure yapısına bağlı olarak o sprite'ı hazırlar.
Parametreleri:
SpriteNr1 -> Integer olarak, hazırlanan sprite numarasını verir. SpriteNr2 olarak verdiğimiz sprite doluysa, bu değerden farklı bir numara ile geri döner.
SpriteNr2 -> Kullanmak istediğimiz sprite numarasını belirtir.
SpritePtr -> SimpleSprite structure yapısını belirtir.
GetSprite() ile açmış olduğumuz sprite'ı ise FreeSprite() ile şöyle kapatıyoruz:
Kullanımı: FreeSprite(SprileNr):
Fonksiyonu: SpriteNr ile verilen numaradaki sprite'ı kapar.
Parametreleri:
SpriteNr -> Kapanmasını istediğimiz, sprite numarası.
MoveSprite()'ın kullanımı ise şöyledir:
MoveSprite(ViewPort,SpritePtr, x, y);
Fonksiyonu: Sprite'ın pozisyonunu değiştirir.
Parametreleri:
ViewPort -> ViewPort yapı değişkeni.
SpritePtr -> SimpleSprite yapı değişkeni.
x, y -> yeni pozisyon değerleri.
Sprite'lar için kullandığımız fonksiyonlar bunlardan ibaret. Artık program örneğimize bir göz atabiliriz.
Bu örneğimizde ilk olarak WorkBench ekranımız sağdan sola kayarak temizleniyor. Daha sonra ekrana sprite'ımız geliyor. Sol tuşa basarak programdan çıkıyoruz.
/* Programming by CENKER OZKURT */
#include <stdio.h>
#include <exec/types.h>
#include <graphics/gfxbase.h>
#include <graphics/sprite.h>
#include <intuition/intuitionbase.h>
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct RastPort *rp;
struct ViewPort *vp;
struct Screen *screen;
#define PI 3.14
int a;
float x,y;
/* SpriteImage yapısında hazırlanıyor.*/
USHORT sprite[] =
{
0,0,
0x0000,0xffff,
0xffff,0x0000,
0xffff,0x0000,
0xf000,0x0000,
0xf000,0x0000,
0xf000,0x0000,
0xf000,0x0000,
0xf000,0x0000,
0xf000,0x0000,
0xf000,0x0000,
0xf000,0x0000,
0xf000,0x0000,
0xffff,0x0000,
0xffff,0x0000,
0x0000,0xffff,
0,0
};
struct SimpleSprite sp =
{
&sprite[0],
16,0,0,3
};
float sin(),cos();
UBYTE *m=0xbfe001;
main()
{
IntuitionBase=OpenLibrary("intuition.library",0);
if (IntuitionBase==NULL) {
printf("intuition ?\n");
return(0);
}
GfxBase=OpenLibrary("graphics.library",0);
if(GfxBase=NULL) {
printf("graphics ?\n");
CloseLibrary(IntuitionBase);
return(0);
}
screen=IntuitionBase->ActiveScreen;
rp=&screen->RastPort;
vp=&screen->ViewPort;
SetRGB4 (vp,20,9,9,9);
SetRGB4 (vp,21,11,11,11);
SetRGB4 (vp,22,13,13,13);
SetRGB4 (vp,23,15,15,15);
for(a=0;a<640;a+=5) {
ScrollRaster(rp,5,0,0,0,640,256);
}
Move(rp,10,30);
Text(rp,"Sprite!",7);
GetSprite(&sp,3);
while(1) {
for(a=0;a<360;a++) {
x=320+100*sin(a*PI/180);
y=100+50*cos(a*PI/180);
MoveSprite(vp,&sp,(int)x,(int)y);
WaitTOF();
if((*m&64)==0) goto son; /* Mouse kontrol */
}
}
son:
FreeSprite(3);
CloseLibrary(GfxBase);
CloseLibrary(IntuitionBase);
}
/* Program Sonu */
Şimdi programımızı kısaca açıklayalım. Programımızda ilk olarak #include önişlem komutları ile gerekli olan macrolar ve kullanılacak olan structure yapıları tanımlanıyor. Daha sonra library ve diğer değişkenler hazırlanıyor.
#define PI 3.14, satırı ile pi sayısını bir macro olarak hazırlıyoruz.
USHORT sprite[] satırında ise sprite'ımızın şeklini SpriteImage structure yapısına göre hazırlıyoruz.
sp değişkeni ise, SimpleSprite yapısını oluşturuyor. Burada posctldata yerine sprite'ımızın adresini vermeyi unutmuyoruz. Diğer sayılar ise sırasıyla yükseklik, başlangıç x-y koordinatları ve sprite numarasını belirtiyor.
Programımızda sin() ve cos() fonksiyonları kullandığımızdan dolayı, float olarak tanımlamamız gerekiyor. Aksi takdirde sin() ve cos() fonksiyonları doğru çalışmaz.
Programın devamında library'ler açılıyor ve sprite renkleri belirleniyor. Bu işlemlerden sonra ScrollRaster() fonksiyonu vasıtasıyla WorkBench ekranımız temizleniyor.
GetSprite(&sp,3); satırı ile de, sprite'ımız kullanıma hazır hale geliyor.
while döngüsü içinde, sprite ekranda mouse tuşuna basılana kadar daire çizmeye devam ediyor. Sol tuşa basılmışsa, library'leri kapayarak programdan çıkıyoruz.
Böylece, bu ayki yazımızın da sonuna gelmiş bulunuyoruz. Gelecek ay, WorkBench ekranı üzerinde çalışmamızı sağlayan screen komutları ve diğer pratik örnekler üzerinde duracağız.
Gelecek ay buluşmak üzere şimdilik hepinize iyi çalışmalar dilerim...