SlideShare a Scribd company logo
1 of 29
Download to read offline
Lite-C SideScroller Workshop
                              by Quadraxas
                             www.tr3dgs.com




www.tr3dgs.com– quadraxas.         1
Giriş

        Sidescroller nedir?
        Sidescroller aslında hepinizin bildiği bir oyun türü. Karakteri ve dünyayı yandan
görürsünüz, sürekli sağa veya sola yürürsünüz, zıplar, platformlara tırmanırsınız. Herkesin bildiği
Nintendo nun Mario'su, MappleStory v.b. gibi. Bu tür oyunlar aşırı karmaşık özellikler içerebileceği
gibi, çok basit minik oyunlar şeklindede olabilir. Basit GameStudio mantığının daha rahat
anlaşılması açısından bu türde bir oyun yapacağız. Her oyunda gerekebilecek ve başlangıç seviyesi
için uygun bilgiler ele alınacak. Zıplamak, yürümek, altın toplamak, çok basit manada menü
yapımı, ses eklemek, giriş ve çıkış ekranları yapımı, basit partiküller, 2d grafiklerin ekranda
gösterilmesi vb..

         Dersi anlayabilmek için gerekli olan şeyler?
         Dersi anlayabilmek için önceki script derslerini iyice okumuş (en azından ilk 3 script dersi)
ve anlamış olmanız gerekmekte. Bu derste önceki bilgilerin üzerinden devam edilecek. O derslerin
yayınlanmasından bu yana meydana gelen değişikliklere bu derste değinilecek.
Ders için en az GameStudio A7 Extra veya Lite-c Free versiyonu gerekli. Trial versiyonuda
kullanabilirsiniz. Crack versiyonlar eski betaların sürüm numaralarının değiştirilmiş hali olduğu
için, bir çok hata meydana gelecektir. Bu tür durumlarda kimseye yardım edilmeyecektir. Bu ders
hazırlanırken kullanılan sürüm A7.07 commerical sürümüdür. Metin editörü(OpenOffice Writer,
tırnakları ve bazı noktalama işaretlerini değiştirdiğinden kopyala/yapıştır yapmak kodların
çalışmamasına neden olabilir.)




www.tr3dgs.com– quadraxas.                         2
Gerekli Harita Konsepti ve Tasarımı1
       Yapacağımız sidescroller türündeki platform oyununda, oyuncu haritayı ve modeli yandan
görecek ve sadece sağa,sola,yukarı ve aşağı haraket edebilecek, haritayıda buna göre yapacağız.




1 Bu derste anlatılan oyun için.

www.tr3dgs.com– quadraxas.                      3
Haritada görülen oklar oyuncunun haritayı geçebilmesi için izlemesi gereken yol, basit olarak önce
gidip anahtarı alması, ardından kilitli kapıyı açıp kolu çekmesi, kol çekildiği için yükselen platform
sayesinde yukarı zıplayarak, yeşil yolu izledikten sonra ikinci kolu çekmesi ve ardından 2. kolun
açtığı köprüye ulaşmak için pembe yolu izleyip bu haritanın sonuna gelmesi gerekiyor. Harita
tasarımı tabiki size kalmış bir şey. Harita oyunun az çok neye benzeyeceği hakkında bilgi veriyor
zaten.

                           Basit bir harita yaptım koda geçmek istiyorum!
      Evet eğer haritanız(haritanız yoksa sadece düz bir plaka koyun işinizi görecektir.) ve
modeliniz hazırsa(şu an için herhangi bir model, 3dgs ile gelen cbabe olabilir) oyunumuzu
kodlamaya başlayabiliriz.

       İlk olarak yeni bir sed sayfası açın ve kaydedin(kaydederken isim.c şeklinde kaydedin .c yi
unutmayın).
       Derleyici için bu dosyların normal bir text dosaysından farkı yoktur.
       İlk satırımız olarak yazdığımız motor fonksiyonlarının tanımlı olabilmesi için, bu
fonksionları kullanacağımızı belirten ve bu fonksiyonların oyunumuzun içine eklenmesini sağlayan
dosyayı eklemeliyiz.



www.tr3dgs.com– quadraxas.                        4
Bunun için önceki derslerde kullandığımız “include” deyimini kullanacağız. Lite-c de c-
scriptden farklı olarak “include”, “define” gibi derleyiciye komut veren deyimler artık normal c
dilindeki gibi başına # ekleyerek kullanılıyor. İlk satırımız:

           #include <acknex.h>

Ve motorda tanımlı tüm öğeleri ve fonksyionları kullanabiliriz artık. Peki motor kodları okumaya
başlayacağı yeri nereden bilecek? Yine normal c,c++,java dillerindeki gibi program “main” isimli
özel bir fonksiyondan işletilmeye başlar. Hemen ekleyelim:

           #include <acknex.h>

           function main()
           {

           }

Şu anda yazdığınız programı derleyip çalıştırırsanız, sadece siyah bir ekran görürsünüz. Zaten
olması gerektiği gibi, henüz bir şey yazmadık, o halde level ımızı yükleyelim.

           #include <acknex.h>

           function main()
           {
               level_load(“platform.wmb”);
           }

level_load : motorda önceden tanımlı bir fonksiyondur ve oyunun üzerinde geçeceği leveli
yüklemenizi sağlar, .mdl,.x(modeller), .hmp(terrain), .wmb(derlenmiş wed haritaları) dosyalarını
level olarak yükleyebilir. Parametre olarak STRING* level_ismi alır.

STRING* : STRING* içinde yazı referansı tutabilen bir değişken türüdür. Kullanımı
STRING* level_ismi = “paltform.wmb”; şeklindedir.

STRING* parametre alan fonksiyonlarda parametreyi geçmek için stringi önceden tanımlamaya
gerek yoktur. Yani level_load a direk olarak level_load(“platform.wmb”); şekilnde parametre
geçilebilir.

Kodunuzu şimdi çalıştırırsanız eğer levelinizde position(sadece wmblerde) varsa, levelinizdeki
positionun gösterdiği yer görünür, eğer position yoksa veya leveliniz wmb dışındaki bir tür
ise(mdl,x,hmp) kamera levelin merkezini gösterecektir.

Ama gördüğünüz gibi leveliniz pencere içinde ve düşük çözünürlükte. Bunun için kullanılabilecek
birden fazla yol var, biz video_set fonksiyonunu kullanarak yapacağız.level_load dan hemen önceki
satıra şunu ekliyoruz:




www.tr3dgs.com– quadraxas.                       5
....
           video_set(800,600,32,2);
           level_load(“platform.wmb”);
           ....

video_set: Önceden tanımlı bir fonksiyon. Parametre olarak:
video_set(ekran genişliği,ekran yüksekliği,renk değeri,ekran şekli);
ekran genişliği ve yüksekliği: bu parameterler ekranın yüksekliğini ve genişliğini ayarlar.
Renk değeri : 16 veya 32 (bit)
ekran şekli: 1 – tam ekran 2- pencere

video_set(800,600,32,2); -> 800x600 32-bit pencere oluşturuyor.

Eğer tam ekran kullanacaksanız standart ekran çözünürlüğü oranını göz önünde bulundurdun
4:3(800x600,1024x768) veya 16:9(widescreen).

Evet şimdilik ana fonksiyonumuzla(main) işimiz bu kadar. Artık oyuncu kontrollerine geçebiliriz.

Bunun için daha önceki derslerden hatırlayacağınız actionları kullanacağız. Actionlar, wedde
behaviour menüsünde görülürler ve oyun dünyasındaki objelere özellik kazandırmamızı sağlarlar.
Main fonksiyonunun dışında bir action oluşturalım.Aynen fonksyionlar gibi oluşturulurlar ama
parametre alamazlar.Actionlar wed de obje üzerine sağtıkladıktan sonra behaviour menüsünden
seçilerek objelere atanır.

           #include <acknex.h>

           function main()
           {
           ...
           }
           action oyuncu()
           {

           }

Konudışı öneri: Script dosyanızı kaydedin ve WED de flie->map properties den script kısmındaki
klasör işaretine tıklayarak script dosyanızı seçin. WED açıkken scriptinize yeni bir action
eklediğinizde, behaviour menüsünde wedi kapatıp açmadan veya scripti map propertiesden tekrar
açmadan gözükmez. Bundan kurtulmak için şunu yapın: WED de file->preferences->advanced-
>Reaload of externally modified files kısmından auto yu seçin. Artık değiştirilen
modelleriniz,scriptleriniz vb. Hepsindeki değişiklik otomatik olarak wed e yansıyacaktır.

Wede geçip oyuncu modelinizi ekleyin ve üzerine sağtıklayıp behavior menüsünü açın. Ve listeden
“oyuncu”yu seçip haritanızı kaydedin ve build edin. Artık oyuncunuz “oyuncu” isimli actiona sahip.
(actionda her değişiklik yaptığınızda haritayı tekrardan build etmenize gerek YOKTUR.)

Oyuncu actionunu tamamlayana kadar wed e de dönmeyeceğiz. Actionumuzu yazmaya başlayalım.
Oyuncu sağ ok tuşuyla sağa, sol ok tuşuyla sola gidecek, boşluk tuşu ile zıplayacak ve E tuşu ile


www.tr3dgs.com– quadraxas.                        6
objelerle etkileşimde(kapı açmak kol çekmek vb.) bulunacak.


            action oyuncu()
            {
              while(1)
              {

                    wait(1);
                }
            }

While, ve wait in işlevlerini önceki derslerimizde anlatmıştık. Kısaca while döngüler oluşturmamızı
sağlıyor, wait ise belli bir frame miktarı boyunca o anki fonksiyonu durdurmaya yarar. While(1) her
koşulda sürekli dönen döngü wait(1) ise döngünün sonunda 1 frame bekleyen bir fonksiyon.
Motorda kullandığınız bütün while larda wait gereklidir, bu tür işlevler çok hızlı
gerçekleştirebildiğinden sınırsız döngüler kısa sürede kaynakları doldurup motoru kilitleyebilir, o
yüzden döngünün frame başına 1 kez dönmesi için wait kullanırız.

Sürekli dönen döngüler kullanmamamızın nedeni ise şu: Örneğin bir tuşa basılıp basılmadığını
anlamamak istiyoruz. Eğer bunu bir kere kontrol edersek sadece o an için kontrol edilir ve bir daha
kontrol edilmez, sınırsız döngü içinde kontrol edersek tuşa basılıp basılmadığı sürekli kontrol edilir
bizde ne zaman basıldığını ne zaman bırakıldığını anlarız.

Oyuncumuzun hareket edebilmesi için oyuncumuza bir vektör uygulanması gereklidir(evet,fizik
dersindeki vektör, umarım ucuca ekleyerek vektör ekleme,çıkarmayı biliyorsunuzdur :D )

bunun için while döngümüzden hemen önce bir vektör tanımlıyoruz, ve olabilecek herhangi bir
prbleme karşı tüm bileşenlerini sıfırlıyoruz.(hala oyuncu actionundayız, karıştırmayın)

                VECTOR* hareket_vektoru; //karakteri yürütecek olan vektör
                 hareket_vektoru.x = 0;
                 hareket_vektoru.y = 0;
                 hareket_vektoru.z = 0;
                 while(1)
                {
            ...

// lardan sonra gelen metnin yorum olduğunu ve ne olursa olsun işletilmediğini unutmayın.

Ve şimdide bu vektörün ok tuşlarıyla büyüklüğünün değişmesini sağlayalım ve karakterimize
uygulayalım. Vektörlerin bileşenleri direk olarak

hareket_vektoru.x = 10; şekilnde değşitirileblir. x,y,z, şekilnde üç bileşeni vardır.

Vektörün boyu bu şekilde değiştirilirken, modele uygulanması esnasında farklı yollar izlenebilir.

İki çeşit uygulama yolu vardır.



www.tr3dgs.com– quadraxas.                          7
1.si vektörü dünyaya göre alarak uygulamak
2.si vektörü modele göre alarak uygulamak




Absolute yazan şekilde modelin yönü ve duruş açısı ne olursa olsun hep aynı vektör uygulanır,
kullanılan koordinat düzlemi dünyanın(haritanın) koordinatlarıdır. Relative yazan şekilde ise, vektör
modelin koordinat sistemine göre uygulanır, model döndüğü zaman koordinatlarıda onunla beraber
döndüğünden vektör değişmediği halde, dünayadan bakıldığında başka yöne uygulandığı görülür.
Şimdi vektörümüzü değiştirip uygulayalım:

           ...
              while(1)
              {
                if(key_cul == 1 || key_cur == 1)//sağ veya sol ok tuşu basılırsa
                {
                      hareket_vektoru.x = 10*time_step;
                }
                else// ok tuşlarına basılmazsa
                {
                     hareket_vektoru.x = 0;
                }

                 c_move(me, hareket_vektoru, nullvector,GLIDE|USE_BOX);
           ...

if ve else, daha önceki derslerde anlatıldı. Kısaca if bloğunun yani if den sonra gelen { } arasındaki
kodların işletilebilmesi için if parantezleri içindeki koşulun sağlanması gerekir, eğer bu koşul
sağlanmazsa else bloğu(elseden sonraki { } arası ) içindeki kodlar işletilir.

key_cul sol ok tuşunu key_cur sağ ok tuşunu key_e e harfini .. vb ifade eder.key_ ile başlayan
değişkenlerin 1 olması demek o tuşun o an basılıyor olması manasına gelir.

Yani eğer tuşlara basılıyorsa hareket_vektoru nun x bileşeni 10*time_step olacak basılmıyorsa 0
olacak.

time_step önceki derslerde anlattığımız time değişkenin yeni adı, motorun farklı fps lerde aynı
davranışı göstermesi için bunu kullanırız, yoksa karakterimiz yüksek fps ile çalışan bilgisayarda
daha hızlı yavaş fps ile çalışan bilgisayarda daha yavaş yürür.(önceki derslerde time olarak ayrıntılı
şekilde anlatılmaktadır.)




www.tr3dgs.com– quadraxas.                         8
c_move vektörümüzü objemize uygulamamızı sağlar. Aldığı parametrelere bakacak olursak:

c_move(obje,rel vektör, abs vektör , notlar);

obje: vektörün hangi objeye uygulanacağını belirtir.
rel vektör: biraz önce açıklanan resimdeki relative gibi, nesneye nazaran uygulama
abs vektör: resimdeki absolute gibi dünyaya nazaran uygulama
notlar: notlar haraketi neyin etkileyip neyin etkilmeyeceğini belirtmemizi sağlar.

Bizim eklediğimiz satır olan:
c_move(me, hareket_vektoru, nullvector,GLIDE|USE_BOX);

me: kullanıldığı actionun atandığı nesneyi belirtir, yani burda bizim oyuncumuzu belirtiyor.
hareket_vektoru : tanımladığımız ve ok tuşlarıyla etkilediğimiz vektör.
Nullvector: tüm bileşenleri 0 olan boş vektör
GLIDE|USE_BOX : glide objenin level blokları üzerinde süzülmesini sağlar, eğer bu notu
düşmezseniz, objenin eğimli bloklara tırmanamadığını görürsünüz. USE_BOX ise sanki objenin
etrafında bir kutu varmış gibi davranmasını sağlar, collisionda yardımcı olacak. Diğer notlar için
manuale bakabilirsiniz.

Şimdi tekrar çalıştırın ve durumu görün.

İki problemle karşılaşmış olabilirsiniz.

1.si her iki yönede basınca aynı yöne gidiyor.
2.si çok hızlı gidiyor veya takıla,takıla gidiyor.

İlk problem çok normal, çünkü hangi yöne basarsak basalım model aynı yöne bakıyor ve vektör
modele göre uygulanıyor, bunu birazdan çözeceğiz.

İkinci problem ise 200 üzeri fps lerde karşılaşabileceğiniz, döngünün bazı framelerde iki kere
dönmesi bazılarında ise hiç dönmemesi problemi(aslında öyle olmuyor ama bize öyle geliyor).
Genelde işlemci veya ramlarinizin ekran kartınıza yetişemediği durumlarda olur. Bu ve bunun gibi
problemler fps ye bir üst sınır koyarak çözülebilir.
Bunu yapmak için maindeki video_set den önce kırımızı ile gösterilen satırı eklemek:

            ....
            fps_max = 60;
            video_set(800,600,32,2);
            level_load(“platform.wmb”);
            ....

Sizinde anladığınız gibi fps nin maksimum sınırını 60 yapıyor.




www.tr3dgs.com– quadraxas.                           9
Şimdi ok tuşlarının oyuncuyu döndürmesi kısmına gelelim.

Bunun için while ın içindeki ifden önce iki yeni if ekleyeceğiz.

Birincisi:

           if(key_cur==1){
              my.pan = 0;
           }
Yani eğer sağ ok tuşuna basılırsa oyuncunun duruş açsını 0 a eşitliyoruz.

İkincisi:

           if(key_cul==1){
               my.pan = 180;
           }
Yani eğer sol tuş basılı olursa oyuncunun açısnı 180 yapıp tam tersi yöne bakmasını sağladık.

my ve me referanslarının o anda o actiona sahip olan nesneyi temsil ettiğini,hem daha önceki
derslerde hemde bu derste söyledik.

Pan,tilt,roll ise önceki derslerdede değindiğimiz gibi objelerin duruş açıları.
Pan xy düzleminde tilt xz düzleminde ve rollda zy düzlemindeki açıyı temsil eder. Bu açılar
oyuncuyu dünya üzerindeki koordinat sisteminde döndürmeye yarar. Yani 0 olarak kabul edilen açı
nesneyi ilk koyduğunuz açı değil, level düzlemlerindeki 0 açılarıdır.

Eğer bu tuşlra basmak karakterinizi sağa sola yerine ileri geri götürüyorsa, levelinizi buna göre
döndürmelisiniz.

Evet şu anda çalışıyor ama ileride zıplama objelerle etkileşim animasyon gibi şeyler ekleyeceğiz.
Bu yüzden daha düzenli bir kod sistemi belirleyip onunla ilerlemeliyiz. Bu tür düzenlemelerde veri
saklamada kullanılma amaçlı her obje(entity) e ait 100 adet skill ismi verilen değişken eklenmiştir.
skill1,skill2,skill3,...skil100 şeklinde. Bunlar my.skill1 = 10; şeklinde kullanılan var türünden
değişkenlerdir. Peki bunları kodumuzu sistematikleştirmek için nasıl kullanacağız. Bu noktada
devreye #define giriyor.
#define: bu anahtar kelime, işletilebilir bir kod değildir sadece derleyiciye kullandığınız bir
kelimenin ne demek olduğunu söyler.Mesela;

#define durum skill20

demek derleyiceiye durum yazdığım heryere skill20 koy öyle derle demektir. Durum u akılda
tutmak skill20 yi akılda tutmaktan kolaydır. Skill20 bir var olduğuna göre içinde sadece sayı
tutabilir durumda durumlarımıza sayılar vereceğiz.

#define yuru 1
#define zipla 2
#define bekle 3



www.tr3dgs.com– quadraxas.                       10
Artık my.skill20 = 3; yerine my.durum = bekle; gibi satırlar yazabileceğiz. Definelar genelde
fonksiyonların dışında yazılır,şimdilik script sayfanızın başında includelarınızla beraber yazmanız
düzenli olması açısından daha iyi.
#include <acknex.h> tan hemen sonra:
           #define durum skill20
           #define yuru 1
           #define zipla 2
           #define bekle 3

ekleyin. Şimdi kodumuzu düzenlemeye geçelim.

Oyuncu actionundaki while ımızın içindeki ifleri düzenleyeceğiz:

           if(key_cur==1){
                  my.pan = 0;
           }
           if(key_cul==1){
                  my.pan =180;
           }
           if(key_cur==1 || key_cul == 1){
                  hareket_vektoru.x = 10*time_step;
           }
           else{
                  hareket_vektoru.x = 0;
           }


Şeklinde olan if lerimizi


           if(key_cur==1){
                  my.pan = 0;
                  my.durum = yuru;
           }
           if(key_cul==1){
                  my.pan =180;
                  my.durum = yuru;
           }
           if(my.durum==yuru){
                  hareket_vektoru.x = 10*time_step;
           }
           else{
                  hareket_vektoru.x = 0;
           }

Şekline getiriyoruz.

Hala aynı işi yapıyor ama anlaması daha kolay ve ileride my.durum==zipla gibi deyimleri
kullanmamıza olanak tanıyacak şekilde.

www.tr3dgs.com– quadraxas.                       11
Bu noktaya geldiyseniz elinizde şu şekilde bir kod olmalı:




Ama oda ne? Karakter durmuyor sürekli haraket ediyor. Bunun sebebi “durum” u “yuru” yaptıktan
sonra hep yuru kaldığından , hareket vektörünü değiştiren if in içine sürekli giriyor olması.
(redimdeki 30. satırdaki if.) Bunu düzeltmek için while içindeki ilk ifden hemen önce
my.durum=bekle; ekliyoruz. Bu şekilde döngü her başladığında en başta durum “bekle” olarak
ayarlanacak, yürüme tuşlarına basılırsa iflerin içine girdiğinden durum tekrar “yuru” olacak Bir tuşa
basılmazsa durum “bekle” olarak kalacak ve 30. satırdaki koşul sağlanmadığından 31. satır
işletilmeyecek. Burada karşımıza ikinci bir çakışma daha çıkıyor, eğer karakter zıplıyorsa “durum”u
“yuru” değil , “zipla”demektir(daha eklemedik) ve ifin(30. satır) içine girmez ve else içine girer ve
buda karakterin sağa sola zıplamasını durdurur. Bu yüzden bu else i de değiştirip if(durum==bekle)
yapacağız.


Yani:
while ın başına (iflerden önce) my.durum = bekle;


www.tr3dgs.com– quadraxas.                       12
while(1)
           {
             my.durum = bekle;
             if(.....
             ......
           }

ve sondaki else yerine if(my.durum==bekle)

           .....
           if(my.durum==yuru){
                  hareket_vektoru.x = 10*time_step;
           }
           if(my.durum==bekle){
                  hareket_vektoru.x = 0;
           }
           .....

ekliyoruz.
Şimdi muhtemelen bu dersin en zor kısmı olan zıplamaya geçeceğiz.

Bunun için c_trace adı verilen, etraftaki nesneleri taramamızı ve ne kadar uzakta olduklarını
anlamamızı sağlayan bir fonksiyon kullanacağız. Karakteri havalandırıp (+z de hareket ettirip),
sonra altındaki yeri tarayacağız ve ayağını basacağı yerle ayaklarının arasındaki uzaklık 0 olana
kadar aşağı çekeceğiz.Peki nasıl kullanılır bu c_trace ?

c_trace(vektör1,vektör2,mod);

vektör1 = taramaya başlayacağımız noktanın konumu
vektör2 = taramanın biteceği noktanın konumu
mod = c_move daki ile hemen hemen aynı olan flaglar dizisi.(yani modelleri es geçmek vb şeyleri
belirttiğimiz yer.)

c_trace vektör1 noktasından vektör2 noktasına doğru tarama yapar. Yani biz vektör1 yerine
oyuncunun o anki konumunu vektör2 yede 5000 metre aşağısını koyarsak, oyuncu ile 5000 metre
aşağısı arasında kalan objeleri taramış oluruz. Buda bize karakterin o anki en yakın olduğu
basabileceği objenin/yerin uzaklığını verir. Şimdi bu dediklerimizi koda dökelim.
Bütün iflerden sonra c_move dan önce şu satırları ekliyoruz.
            .....
                   VECTOR ilk;
                   VECTOR son;
                   vec_set(ilk,my.x);
                   vec_set(son,my.x);
                   son.z - = 5000;


vec_set : İki vektörü birbirine eşitlemeye yarar, ikinci parametreyi, biinciye eşitler. Yani buradaki
vec_setler ilk ve son isimli vektörleri oyuncu konumuna eşitliyor.(Sadece my yazmak vektör değil
entity belirtir, mantıken my.x yazmak ise oyuncunun sadece bulunduğu x'i belirtir. Doğru fakat,

www.tr3dgs.com– quadraxas.                        13
entitylerin my.konum gibi bir vektörü yok,bu tür fonksiyonlarda my.x yazdığımızda motor o anki
konumu kastettiğimizi anlıyor.)
İki vektörüde oyuncunun konumuna getirdik ve son isimli vektörün z sini 5000 quant aşağı çektik.
Yani vektör konum olarak oyuncunun 5000 quant aşağısını göstermiş oldu. Şimdi c_trace ile bu
vektörleri kullanarak oyuncunun o anki yüksekliğini bulalım. Bunun için actionumuzun en başında
“hareket_vektoru” ndan önce veya sonra “var yukseklik = 0;” şekilnde bir değişken tanımlıyoruz.

Ardından biraz önceki vec_setler ve son.z - = 5000; den sonra:

yukseklik = c_trace(ilk,son,IGNORE_ME|IGNORE_PASSABLE|USE_BOX);

Yüksekliği hesaplayıp, “yukeseklik” isimli bir değişkene attık.

Şimdi ise boşluk tuşu ile zıplamayı sağlayacağız. Hemen c_trace in ardından;

           .....
                   if(key_space==1){
                          if (yukseklik < 2)
                          {
                                  yukseklik = 1;
                                  hareket_vektoru.z = 12;
                          }
                   }

Peki neden yüksekliğin 2 den küçük olma şartını koyduk? Çünkü hemen ardından hareket
vektörüne yukarı doğru bir değer veriyoruz. Eğer kontrol etmezsek karakter havadayken tekrar
zıplama tuşuna bastığında biraz daha yükselecektir. Peki neden yüksekliği 1 e eşitledik? Bunu
birazdan karakteri aşağıya çeken kodu yazdığımızda göreceğiz. ;)

Şimdi yüksekliğin 0 dan büyük olduğu durumları ele alalım.Yani (biraz önceki if in hemen ardıdan);


           .....
                   if (yukseklik > 0)
                   {
                           hareket_vektoru.z-=3 * time_step; // düşme
                           my.durum = zipla;
                           if (hareket_vektoru.z < (yukseklik * -1))
                           {
                                   hareket_vektoru.z = yukseklik * -1;
                           }
                   }


Evet, anlatması en zor kısım burası. Ne anlattığımı pek anlayamayabilrisiniz, değerle oynayarak
ekleme/çıkarma yaparak ne demek istediğimi daha iyi anlayabilirsiniz.

Yükseklik 0 dan büyükse, yani karakter havadaysa ya zıplamış ya da bir yerden aşağı atlamış
demektir.


www.tr3dgs.com– quadraxas.                       14
Bu durumda karakteri hareket ettiren haraket_vektoru nun z bileşenini azaltmamız gerekir. Bu
bileşen bir yerden atlama durumunda, karakter tam atladığı yerin sınırından ayrıldığı andan önce 0
dır, ayrıldığı anda artık altı boşluktur ve c_trace yeni tabanın yüksekliğini döndürmüştür. Bu
durumda 0 olan z bileşeni zamanla dahada eksilerek(ivmeli hareket), karakteri aşağı doğru çekiyor.
Zıplama durumunda ise, karakter tam zıpladığı anda bir önceki blokda 12 ye eşitlediğimiz z bileşini
sıfırdan büyük olduğu için bu if içine giriyor ve çalışmaya başlıyor, karakter daha havadayken ve
yükselmekteyken bile z bileşenini azaltıyor. Bi süre sonra z bileşini iyice azalıp 0 ı da aşıyor ve
karakteri aşağıya doğru çekmeye başlıyor.

Ama bu bileşenin çokda fazla azalmaması lazım, eğer çok fazla azalırsa aşağı çeken vektör çok
büyük olacağından karakteri aniden yere yapışıyor gibi görürüz. Bunun içinde bir sorgulama yapıp
yükseklikten daha büyük seviyelere çıktığında, tekrar yüksekliğe eşitliyoruz. (burada –(eksi) nin
aşağı yönü ifade ettiğini biliyorsunuz?)

Hemen ardından şöyle bir else ekliyoruz, önceki if yüksekliğin 0 dan büyük olduğu durumları
kontrol ettiğine göre, buda büyük olduğu durumlarda çalışıyor;

           else
           {
                   my.durum = bekle;
                   hareket_vektoru.z = -1 * yukseklik;
           }


Bu else içindeki işlemler bir kaç farklı durumu ele almamızı sağlıyor. Eğer uzaklık 0'dan küçükse
modeli daha fazla aşağı çekmeye gerek yoktur. hareket_vektörü.z nin yüksekliğe eşitlenmesinin
nedeni ise şöyle açıklanabilir.

Çarpım kulandığımızdan yukseklik =0 sa hareket_vektoru.z = 0 dır. Yani z ekseninde hareket yok.
Eğer yere uzaklık negatif bir değerse, bu modelin bloğun içine girdiği manasına gelir. Bu durumda
bu kod kesimi modeli içeri girdiği miktar kadar yukarı iter. Böylelikle net 0 yükseklik sağlanmış
olur.

Evet, hareket ettirme kısmı biraz zahmetli ve karışık oldu. Fizik dersinin içeriği olan Vektörler
nedeniyle anlayamadığınız bir nokta varsa yardımcı olayamacağım.Bilmiyorsanız, Wikipedia yı
açıp vektörler hakkında az çok bilgi edinebilirsiniz, fakat çok yardımcı olmayabilir. Eğer vektörler
nedir bilmiyorsanız ve oyun programlamak istiyorsanız bir önce öğrenin, oyun motorlarının
hepsinde hareket işlemleri vektörlerle yapılır. Bu ders için ortaokul fiziği yeterlidir, fakat daha
karmaşık işlemlerde, işin içine trigonometri, ve calculus girebilir :D (anlayan anladı)




Şu anda bu aşamadayız:


www.tr3dgs.com– quadraxas.                       15
www.tr3dgs.com– quadraxas.   16
Sanırım artık iflerden önce while lardan sonra diyerek neyi kastetiğimi anlıyorsunuzdur. Bundan
sonra kodun ekran görüntüsünü eklemeyeceğim.

Şimdi animasyonlarımızı oynatmaya ve kameramızı ayarlamaya bakacağız.

Tanımladığımız durumların işe yarayacağı nokta burası. Modellerin animasyonunu göstermek için
ent_animate isimli bir fonksiyon kullanacağız.

Ent_animate bir modelin, belli bir sahnesindeki animasyonu oynatmak için kullanılır.O sahnenin
adına ihtiyaç vardır.

Sahnelerinizi Med-> Edit -> Manage Frames -> Rename Frames den adlandırabilirsiniz.




Peki nasıl kullanılır bu ent_animate ?

ent_animate(obje,sahne,%yuzde,mod);

obje: animasyonunun oynatılmasını istediğini obje
sahne: biaz önce nasıl adlandıracağınızı söylediğim sahne (örn. bekle, kos)
yuzde: % cinsinden sahnenin %desi. 0 ilk kareyi 100 son kareyi ifade eder.(Animosyonunuz 5 kare
bile olsa takılarak gidiyormuş gibi olmaz, Motor bu animasyonu tamamlar)
mod: ent_animate de mod yerine yazabileceğiniz 3 seçenek var.

ANM_SKIP : motorun animasyonunuzu tamamlamasını istemiyorsanız, moda bunu yazın.
ANM_CYCLE : animasyonunuz yürüme,koşma gibi bir sürekli tekrar eden bir animasyonsa bunu
kullanırız.
ANM_ADD: Bone animationda, boneları o kareye getirmektense o karenin bone açılarını bi
sonrakine ekleyek gösterir.

Biz ANM_CYCLE kullanacağız.

www.tr3dgs.com– quadraxas.                      17
Şimdi ent_animate de % olarak kullanacağımız bir değişken tanımlayalım.

While dan önce “var yukseklik” den önce veya sonra yeni bir değişken ekliyoruz:

var anim = 0;

Eğer bunu while içine eklerseniz her döngü başında değişken 0 lanacağından sürekli animasyonun
ilk karesini görürsünüz. Ent_animate e % olarak geçtiğini parmetrenin 100 den büyük olması
problem teşkil etmez.
Yürürken “kos” isimli, beklerken “bekle” isimli sahnerleri kullacanacağım.

O yüzden

if(my.durum == bekle){

}

nin içine

ent_animate(my,“bekle”,anim,ANM_CYCLE);               ekliyorum.

Aynı şekilde durumun yuru olduğu if in içinede

ent_animate(my,“kos”,anim,ANM_CYCLE); ekliyorum.

Durum ayarlarını zaten önceden yaptığımızdan, artık yürürken kosma animasyonunu beklerkende
bekleme animasyonunu göreceğiz. Fakat şu anda anim isimli değişken 0. Bunu döngü her
döndüğünde bir miktar arttırırsak, animasyonun oynamasını sağlamış oluruz. While ın sonundaki
wait den önce

anim+= 3*time_step;

ekliyoruz. Animasyonun yavaş kaldığını düşünoyorsanız 3 yerine başka bir sayı yazabilirsiniz.
Peki ya kamera?
Kameranında diğer objeler gibi, x,y,z ve pan,tilt,roll gibi nitelikleri vardır. Bu nitelikleri bir şekilde
oyuncununkilerler ilişkilendirerek kameranın konumunu/açısını değiştireceğiz.




Kameramız üstteki şekildeki gibi sürekli aynı açı ile yandan oyuncuyu takip etmeli. X ve Z
eksninde oyuncu ile aynı hizada, Y de biraz geride ve 90 derece ile duruyor. Bunu koda dökelim.


www.tr3dgs.com– quadraxas.                          18
Kameranın herframede oyuncunun konumuna göre ayarlanması gerektiği için, oyuncu actionunun
içindeki while döngüsüne ekliyoruz. c_move dan hemen önce şu satırları ekliyorum:


                    camera.x = my.x;
                    camera.z = my.z;
                    camera.y = my.y – 475;
                    camera.pan = 90;



Evet, tam olarak dediğimizyapıyor, kamera x ini ve z sini oyuncuyla aynı yapıp, y sinide oyuncudan
biraz geriye çekiyor ve kamerayı 90 derece döndrüyor.

Şu anda yürüyebiliyor, zıplayabiliyor, animasyonlarınızı görübeliyor olmanız ve kameranında sizi
takip ediyor olması gerekiyor.

Oyuncu ile işimiz şimdilik bu kadar.

Şimdi toplayacağımız anltınları ve puan sistemini hazırlayalım. Bunun için izlenebilecek bir çok
yöntem var. Puanı oyuncunun skill lerinden birinde tutabilirz fakat, level değiştiği zaman, oyuncu
silinip, diğer levelde tekrar oluşturulduğu için (en azından şimdilik böyle diyoruz, ent_create
kullanmadığımızdan.) Bu yüzden puanı normal bir değişkende tutacağız. Mainin dışında define
lardan sonra

var puan = 0;

isimli bir değişken tanımlıyorum. Para aldığımızda bu değişken artacak, ve aynı zamanda ekrande
gösterilecek.

Şimdi para(altın) olarak kullanacağınız objeyi belirleyin, herşey olabilir, med de herhangi bir obje
yapıp onu kullanabilirsiniz.Bu objeye ekleyeceğimiz actionu yazacağız şimdi.

Basit manada paraya dokunulduğu zaman, puana belli bir miktar ekleyip, parayı dünyadan
kaldıracağız. Fakar her para alındığında aynı sayıyı eklemektense, farklı miktarda puanlar ekleyen
para çeşitleri yapalım.Farklı büyüklükte aynı parayı veya değişik obje modellerini kullanmak
isteyebiliriz. (bakır , altın, elmas gibi.). İkinci bir action yazmadan, tek actionla puanın farklı miktar
artmasını sağlayacağız. Bunun için yine skill leri kullanacağız. Definlarımın altına yeni bir define
ekliyorum:

#define miktar skill1

Bu skilli kullanarak dokunulan objenin skill1 i kadar puanın artmasını sağlayacağız. Bu şekilde aynı
actionu kullanarak, wed den ayarladığımız farklı miktarları objeye ekleyeceğiz.(Ek1 e bakın.)

Dokunmayı anlayabilmek içinse EVENT_IMPACT kullanacağız ve eventlere giriş yapmış olacağız.

Actionumuzu ve eventimizi yazmaya başlayabiliriz artık.



www.tr3dgs.com– quadraxas.                         19
Önce actionumuzu yazalım actionumuz basit olarak paranın sürekli dönmesine ve dokunulduğunda
eventi(henüz yazmadık) çağırmaya yarayacak.


           action para_action(){

                   my.emask |= ENABLE_IMPACT;
                   my.event = para_event;

                   while(1){
                          my.pan+= 10*time_step;
                          wait(1);
                   }
            }
While ve waitin ne iş yaptığını biliyoruz. my.pan ı arttırmanın parayı sürekli döndüreceğinide
biliyoruz. Bu kısımda ilk kez gördümüz şeyler emask event ve ENABLE_IMPACT.

Objelerinin etkileşiminin büyük kısmı eventlerle sağlanır, eventler objede bir değişiklik meydana
geldiğinde tetiklenir, hangi değişikliklerde tetikleneceğinizde emask ile belirleriz, objeye birden
farklı türdeevent eklenebilir(dokununca sürüklenen+ateş edince patlayan varil gibi.). Mevcut event
türleri için EK-3 e bakın.

Bu eventlerin tetiklenebilmesi için emask ın ayarlanmış olması gerekir.Örneğin EVENT_CLICK in
ve EVENT_IMPACT in tetiklenmesini istiyoruz. O zaman emask ımız:

my.emask |= ENABLE_IMPACT | ENABLE_CLICK; oluyor. Event fonksiyonu ise my.event=
fonksiyon adı şeklinde şeklinde atanıyor. Tetiklenen aynı fonksiyon olduğuna göre farklı işler
yapmak isterseniz o fonksiyonun içinde hangi eventin tetiklendiğini kontrol etmelisiniz.
if(event_type==EVENT_IMPACT) gibi.

Yani biz

my.emask |= ENABLE_IMPACT;
my.event = para_event;

yazmakla, objeye dokunulduğunda, para_event isimli fonksiyonun çağrılmasını istediğimizi
söylemiş olduk.
Şimdi para_event i yazalım(actionun üstüne).

           function para_event(){
                  if(you==player && event_type == EVENT_IMPACT){
                         puan += my.miktar;
                         ent_remove(me);
                  }
           }

“You” da ne? “You” objenin etkileşime geçtiği diğer objeyi gösteren bir göstergedir. Player ise
herhangi bir amaçla kullanılabilecek başka bir gösterge. Peki oyun bizim “player” olduğumuzu
nerden bilecek?


www.tr3dgs.com– quadraxas.                       20
Bilmesi için oyuncu actionumuzun en başına,
player=me;

eklemeliyiz. Bunu yapmamızın nedeni şu, ilerdeki derslerde düşman eklediğimiz zaman, düşman
altınlara dokunduğunda event_impactin tetiklenmesini engellemek.
ent_remove(obje); ise parametre olarak geçilen objenin yok edilmesini sağlar. Yani
ent_remove(me); diyerek o eventi tetikleyen objenin(para) ortadan kaldırılmasını sağlıyoruz.

Miktar isimli skilli daha önceden tanımlamıştık. O objenin(para) miktarı(skill1) kadar eklee yapıyor
puana. Bunun için bütün paraların skill1 lerini wed den ayarlamamız gerekiyor. Bununla
uğraşmamak için, sadece farklı olmasını istediklerimi düzenlemek istediğim için para actionunda
ufak bir değişiklik yapacağım.

Para actionundaki whiledan önce

if(my.miktar == 0) {my.miktar = 10;}

satırını ekliyorum. Wed e koyulan objelerin koyuldukları zaman tüm skilleri 0 olduğundan, ve
normal bir paranın 10 puan vermesini istediğimden, miktarı 0 olan paraların miktarlarını 10 a
eşitliyorum. Bu durumda skillerine dokunmadığım tüm paralar 10 puan vermiş oluyor, eğer skillde
değişiklik yaparsak yazdığımız sayı kadar puan verecek.(bkz. EK-1)

Şimdi bölümünüze Birkaç para koyun ve çalıştırın, artık paralara dokunduğunuzda kayboluyor
olmalılar.

Şimdi ise puanımızı nasıl ekranda gösterdiğimize geçiyoruz.

Ekranda 2 boyutlu grafikleri göstermek için genel olarak PANEL ler kullanılır. Panellerin üzerinde
buton, slider, yazılar, değişken ve 2 boyutlu grafik gösterilebilir.

Biz basit olarak, arkaya bir resim koyacağız, üstünde de puanımız yazacak.Paneller şu şekilde
tanımlanıyor:

           PANEL* puan_panel = {
                layer = 1;
                bmap = "puan.tga";
                digits(100,70,4,"Arial#48",1,puan);
                flags = CENTER_X | CENTER_Y | VISIBLE
           }


Layer : Katman. Eğer paneller üstüste gelirse hangisinin önde görüneceğini belirlememizi sağlar,
layeri büyük olan üstte görünür.
Bmap : panelin arkasında gösterilecek olan 2 boyulu grafik, tga gibi 32 bit grafiklerin alfa
kanallarını destekler. Şimdilik scriptinizin olduğu dizine atın resminizi.
Flags : c_move,c_trace de kullandığımız modlar gibi, belli özellikleri açıp kapatmamızı sağlar. Tüm
flaglar için manuale bakabilirsiniz.(center flagları digitleri ortalamak için kullanılır, VISIBLE ise
görünürlüğü sağlar)



www.tr3dgs.com– quadraxas.                       21
digits : Digit ekranda yazı, değişken gibi öğeleri göstermemizi sağlar.

digits(x,y,biçim,font,faktör,değişken);

x: panelin sol üst köşesine göre digitin x konumu
y: panelin sol üst köşesine göre digitin y konuu
biçim: "[text1]%[flags][width][.precision]f[text2]"
        text1: Yazı (isteğe bağlı)
        flags:(isteğe bağlı)
                - : sola daylı yap (varsayılan: sağa dayalı)
                + : sayıların işaretini göster(varsayılan: sadece negatif sayıların işaretini göster)
                0 : width e erişene kadar başa 0 ekle
                # : sayılının . İçermesini zorunlu kılar
        width:minimum genişliği belirtmeye yarar(isteğebağlı)
        .precision : noktasan sonraki basamak sayısı (isteğebağlı)
        text2:yazı (isteğebağlı)
faktör:değişkenin katsayısı (belli bir sayıyla çarpmanız gerekirse diye.)
değişken: Göstermek istediğiniz değişken.

Örnekler:
x= 12345.93 için ve
tex_name= “texture” için
digits(0,0,"Vol: %.1f ltr",*,1,x); // "Vol: 12345.9 ltr" gösterir
digits(0,0,"Selaam :)",*,0,0);   // "Selaam :)" gösterir
digits(0,0,0,*,1,tex_name);     // "texture" göterir.
digits(0,0,"Texture Adı: %s",*,1,tex_name); // "Texture Adı: texture" gösterir

bizim yazdığımız ise:

digits(100,70,4,"Arial#48",1,puan); ekranda puanı gösteriyor (ordaki 4 width e krşılık geliyor.)

Şu anda oyunu çalıştırırsanız, koyduğunuz resmi ve puanınızı görüyor olmalısınız.

Ve Şimdide Kapılar & anahtarlar, kollar & geçitler.(kolu çekersiniz, geçit açılır gibi.)

Öncelikle şimdi izleyeceğimiz yöntemin, daha rahat anlaşılması için seçildiğini söyleyeyim.
Anahtar/kapı işini yapmanın en iyi yolu değil, fakat bu oyun için yeterli.

Aslında anahtar/kapı ile kol/geçit aynı şey. Sadece biri kolu çeker çekmez harekete geçiyor diğeri
ise anahtarı alıp yanına gittikten sonra aktifleştirmek istesek çalışıyor.

Bu işi yapmak için diziler kullanacağız, anahtar alındığında/kol çekildiğinde bununla ilgili bir mesaj
göstereceğiz.

Dizi nedir? Diziler, birden fazla değişkeni bir arada tutup, işlerimizi kolaylaştırmaya yarar.
Tanımlanması normal değişkenlerden biraz farklıdır.

var dizi[diziuzunluğu]; şeklinde tanımlanır, dizi uzunluğu tam sayı olmalıdır, ve bir değişken
olamaz. Derleme esnasında dizinin boyu belli olmalıdır.(Linked-List lerde uzunluk çalışma
esnasında değiştirilebilir, ama şu an için yeni başlayanlara dizi kavramak bile zor gelebileceğinden,
linked-list e hiç girmiyorum).


www.tr3dgs.com– quadraxas.                          22
Öncelikle anahtar ve kapılardan başlıyorum.

Bunun için mainden önce

var anahtarlar[5] = {0,0,0,0,0};

ekliyorum.
Bu anahtarlar isminde bir dizi oluşturmamızı, ve bütün elemanlarını 0 yapmamızı sağlıyor.
Dizi elemanlarını kullanmak istediğimizde

anahtarlar[0] diyerk normal değişkenler gibi muamelede bulunabiliriz.Bu dizi için ilk eleman
anahtarlar[0] ,son eleman anahtarlar[4] tür. 6. eleman yani anahtarlar[5] dizi sonunu belirtir. Bunun
içine bir değişken atamaya kalkarsanız oyununuz çöker veya hata verir.

Peki şimdi 5 tane anahtarlar isimli değişkenle ne yapacağız veya neden 5 tane? Şu an için bir
levelde en fazla 5 tane kapı olacağınız öngördüğümden 5 anahtar var.(çok iyi bir yöntem olmadığını
söylemiştim.)

Kapıların ve anahtarların hepsinin bir numarası olcak (0-4 aralığında), bir anahtar alaındığında
dizide o anahtarın numarasına denk gelen eleman 1 e eşitlenecek. Ve kapıyı açmaya çalıştığımda
dizide kapının numarasına denk gelen yer kontrol edilecek ve eğer 1 se kapı açılacak değilse
“kilitli” mesajı gösterilecek.

Evet, şimdi bunu kod ile nasıl yapacağımıza bakalım.

Öncelikle anahtarı ve dokunulduğunda dizideki elemanın 1 olmasını sağlayacak işleleri yapalım.
Bunun için yine skilleri kullanacağız. Kapı ve anahtrların 1. skilleri (skill1) numaraları olacak, bu
şekilde kapı ve anahtar numaralarını wed den ayarlayabileceğiz.

Definlarımın altına yeni bir define ekliyorum.

#define numara skill1

Aynı skillin iki farklı isimle ifade edilmesi probleme neden olmaz. Yapacağımız şey çok zpr değil,
para actionunda yaptığımızın aynısını yapacağız. Bu sefer puan artırmak yerine dizide numaraya
denk gelen elemanı 1 e eşitleyeceğiz. Sayfanın en altına para actionundan sonra şunu ekliyorum:

           action anahtar_action(){
                   my.emask |= ENABLE_IMPACT;
                   my.event = anahtar_event;
                   while(1){
                          my.pan+= 10*time_step;
                          wait(1);
                   }
           }
Anlaşılmayacak herhangi Bir şey yok, parayla neredeyse aynı,bu sefer anahtar_event isimli
fonksiyonu çağıyor. Hemen o fonksiyonuda yazalım.




www.tr3dgs.com– quadraxas.                        23
Bu actiondan önce anahtar_event isimli fonksiyonu yazıyorum.

           function anahtar_event(){
                  if(you==player && event_type == EVENT_IMPACT){
                         anahtarlar[my.numara] = 1;
                         ent_remove(me);
                  }
           }


Bu kadar basit anahtarın numarasına(skill1) denk gelen dizi elamanını 1 yaptık. Hemen kapı
actionuna geçelim.Ardından anahtar alındığında veya kapı kilitli olduğunda mesaj göstermeceğimiz
fonksiyonu yazacağız.

Kapı için bu sefer biraz daha değişik bir yöntem izleyeceğiz ve IMPACT den farklı bir event
kullanacağız. Oyuncu E tuşuna basarak etkileşime geçecek demiştik. Bunu şu şekilde sağlayacağız.
E tuşuna basıldığında karakterin önünü tarayacağız. İşin karakter kısmı bu kadar. Kapı veya kol
kısmında ise EVENT_SCAN kullarak, tarandıkları zaman eventlerinin tetiklenmesini sağlayacağız.

Önce karakter kısmını halledelim. Karakter actionundaki if(key_cul) ve if(key_cur) dan sonra yeni
bir if ekliyoruz.

           if(key_e == 1){
                  c_scan(my.x,my.pan,vector(120,0,50),IGNORE_ME);
           }

Peki neden önceden kullandığımız c_trace değilde c_scan kullanıyoruz. Çünkü c_trace iki konum
vektörü arasında kalan düz çizgiye değen şeyleri tarar. c_scan ise 3 boyutlu uzayda bizim
belirlediğimiz bir koni veya kürenin içine giren objeleri tarar. Tamam, kapı gibi objelerde c_trace in
da değme ihtimali yüksektir ama, örneğin ileri kullanacağımız kol/şalter gibi objeler küçük
olduklarından c_trace in değme ihtimali düşüktür. Koni c_scan e geçilen parametrelerle belirlenir.

c_scan(başlama noktası,koninin açısı,Koni vektörü,mod);
c_scan(my.x,my.pan,vector(120,0,50),IGNORE_ME);

başlama noktası: tarama konisinin yerleştirileceği konum. my.x diyerek oyuncunun merkezine
getirmiş oluyoruz.
Koninin açısı: koninin uzaydaki duruş açısı, oyununcunun açısna eşitledik.
Koni vektörü:
       x bileşeni: Yatay scan alnı, veya açı olarak koni genişliği (360 girersniz küre olur.)
       y bileşeni: Dikey scan alanı, 0 koymak dairesel yapar.
       z bileşeni: Scan uzaklığı(50 quant ileriyi tarayacağız)
mod: Diğerlerine benzer şekilde scan işleminin özelliklerini belirlememizi sağlar.

Artık e ye bastığımız zaman önümüzü tarıyoruz. Şimdi tarandığında tepki veren objemizi(kapı)
yapacağız. Kapı önüne gelinip e ye basıldığında(c_scan edildiğinde), anahtar oup olmadığına
bakılacak ve varsa yukarıya kayarak açılacak.




www.tr3dgs.com– quadraxas.                       24
Bunu yapmak için değişik skill ler kullanacağız? Anahtarları ve numaraları hatırlıyor musunuz?
Evet kapının 1. skillide numarası, 2. skilli açıldığında ne kadar yukarı yükseleceği olacak

#defein kapiacik skill2

artık bu satırı açıklamaya gerek duymuyorum, diğer defineların altına ekleyin.Kapının actionunu
yazalım. Bunu dosyanın en altına ekleyin.

           action kapi_action(){
                   my.kapiacik = my.z + my.kapiacik;
                   my.skill3= my.z;
                   my.emask |= ENABLE_SCAN;
                   my.event = kapi_event;
           }

SCAN a duyarlı hale getirdik ve scan edildiğinde kapi_event isimli fonksiyonu çağırması
gerektiğini söyledik. Actionun ilk 2 satırı ise şunun için, kapiacik(skill2) wed den ayarlanacak ve
kapının ne kadar yükseleğeciğini söyleyecek. Kapı açıldığında ise dünaya göre konumu , ilk
konumu + bizim söylediğimiz yükseklik, kadar olacaktır.

my.kapiacik = my.z + my.kapiacik;

diyerek kapalı haldeki konumu ve verdiğimiz yüksekliğ toplayıp, tekrar my.kapiacik in içine
yerleştirdik.
Skill3 e ise kapının kapalı haldeki(ilk hali) konumunu kaydettik. Açık kapıyı kapatırken bu değeri
kullanacağız.
Yani kapı açıldığında konumunun Z bileşenin değeri, my.kapiacik olacak, kapandığında ise
my.skill3 olacak. Eventimizde bunları düzenleyeceğiz.
Yine actionun üstüne kapi_event isimli fonksiyonu ekliyoruz.
          1 function kapi_event(){
          2           if(you==player){
          3                  if(anahtarlar[my.numara] == 1){
          4                          while(my.z<my.kapiacik ){
          5                                   my.z+= 4*time_step;
          6                                   wait(1);
          7                          }
          8                          if(my.z >= my.kapiacik){ my.z = my.kapiacik;}
          9                          wait(-1);
          10
          11                         while(my.z>my.skill3 ){
          12                                  my.z-= 4*time_step;
          13                                  wait(1);
          14                         }
          15                         if(my.z <= my.skill3){ my.z = my.skill3;}
          16                 }
          17          }
          18 }




www.tr3dgs.com– quadraxas.                       25
Hangi parantezlerin birbirinin karşılığı olduğunu göstermek için farkı renkelere boyadım.

Buraya kadar anladıysanız bundan sonra söylediklerimi anlamanız zor olmayacaktır.

İlk if de scanı yapan kişinin oyuncu olup olmadığına bakıyorum.

İkinci if de anatar dizisinden kapının numarasına(skill1) denk gelen yerin 1 olup olmadığını kontrol
ettim.Anahtar alınca anahtar numarısına denk gelen yerin 1 e eşitlendğini hatırlayın. Yani
anahtarlarınız ve kapılarınız aynı numaraya sahip olmalı. Kapı ve anahtarlarınızı koyarken wed den
numaralandırayı unutmayın.

İlk while da kapının yüksekliği my.kapiacik a eşit oluncaya kadar yukarı çekiyorum.
Hemen ardından gelen if de ise taşmayı kontrol ediyorum. Yani, kapıyı 4er 4er çektiğim için,
gerekli değeri 3 veya 2 gibi bir değerler geçebilir, bu yüzden bu if de o taşmayı geri çekiyorum.

wait(-1); bu aslında önceki derslerde anlattığımız, sleep isimli fonksiyonun karşılığı. Waite
parametre olarak pozitif bir değer geçerseniz, geçtiğiniz parametre kadar frame(kare) bekler. Eğer
negatif bir parametre geçerseniz, geçtiğini parametre kadar saniye bekler. Yani buradaki kullanımı 1
saniye bekliyor. Kapı 1 saniye açık kalığ kapanacak.

Hemen ardındaki while da ise kapının yüksekliği, actionda önceden sakladığımız ilk konum(skill3)
e eşit olana kadar aşağı çekiliyor, ve yine aynı şekilde ardından gelen if de taşma kontrol ediliyor.

Şu anda anahatalarınızı aldıktan sonra, kapılarınızı açabiliyor olmalısınız. Wed de anahtar ve
kapının skill1 lerine numaralarını kapının skill2 sine ise açılma yüksekliğini yazmayı unutmayın.
Kapılara aynı numaraları vererek tek anahtarla farklı kapıların açılmasını sağlayabilirsiniz.

Bu derslik son olarak kollar ve geçitleride anlatığ noktalayacağız.

Dosyamızın başına, anahtarlar dizisinin altına yeni bir dizi ekliyoruz.

           var kollar[5] = {0,0,0,0,0};
Yine aynı mantıkla çalışacağız bu sefer anahtar alıp oyuncunun kapıyı taramasını beklemektense,
kol çekilir çekilmez, hedeflerini harekete geçireceğiz. Bu seferde oyuncu kolun yanına gelip
tarama(e) tuşuna bastığında, kol aktifleşecek ve dizide numarasın karşılık gelen yeri 1 e
eşitleyecek. Kolun hedefi olan platform ise sürekli dizide kendi numarasına denk gelen yeri kontrol
edip, 1 olduğu anda haraket geçecek. Skill1 ler yine numaraları olacak, kolların hedefleri olan
geçitlerin skill2 si ne kadar ne kadar sağa sola hareket etmeleri gerektiğini skill3 leri ise ne kadar
yukarı hareket etmeleri gerektiğini belirtecek. Tek actionla hem yukarı hemde sağa sola kayan
platformları halletmiş olacağız.

Kollardan başlayalım.

           action kol(){
                    my.emask |= ENABLE_SCAN;
                    my.event = kol_event;
           }
Tek yaptığımız scan e duyarlı hale getirmek ve scan edildiğinde kol_event isimli eventi
çağıracağınız belirtmek.


www.tr3dgs.com– quadraxas.                        26
kol_event isimli eventi yazalım.

            function kol_event(){
                    if(kollar[my.numara]!=1){
                            if(you==player){
                                   while(my.tilt > -45){
                                           my.tilt -= 4*time_step;
                                           wait(1);
                                   }
                                   kollar[my.numara] = 1;
                            }
                            wait(-1);
                    }
            }
İlk if kolun zaten çekilip çekilmediğini yani dizide numaranı denk gelen yerin 1 olup olmadığını
kontrol ediyor ve değilse giriyor. (!= in “değilse” manasına geldiğini hatırlayın.) İkinci if ise
herzamanki gibi taramayı yapanın oyuncu olup olmadığını kontrol ediyor.

İçerideki while ise kolun duruş açısını -45 olana kadar azaltıyor. Eğer kol yerine düğme
kullanacaksanız bu while ı kaldırabilrisiniz.(solda kol çekilmeden önce sağda ise çekildikten sonra)




Whiledan hemen sonra ise dizide kolun numarasına denk gelen yeri 1 e eşitliyoruz.
Wait i eventin saniyede en fazla 1 kere çağırılabilmesi için koyduk.

Artık kolu çektiğimizde açısı -45 olana kadar aşağı dönüyor ve dizide numarasına denk gelen yeri 1
yapıyor.

Şimdi ise kol çekildiğinde harekete geçecek platformlara atamamız gereken actionu yazacağız.

Öncelikle skill2 nin x eksenindeki değişikliği skill3 ünde z ekseninde değişikliği belirteceğini
hatırlatayım. Daha rahat hatırlamak için diğer define larımın yanına şunları ekliyorum:

#define kolx skill2
#define kolz skill3

ve actionumuz, dosyanın sonuna ekliyoruz:




www.tr3dgs.com– quadraxas.                        27
1 action kol_hedef(){
         2
         3           var a = my.z + my.kolz;
         4           var b = my.x + my.kolx;
         5
         6           var mod = 1;
         7           if(a<my.z || b<my.x){
         8                    var mod = -1;
         9           }
         10
         11          while(1){
         12
         13                   if(kollar[my.numara] == 1 && mod*my.z< mod*a){
         14                            my.z += mod*4*time_step;
         15                   }
         16
         17                   if(kollar[my.numara] == 1 && mod*my.x< mod*b){
         18                            my.x += mod*4*time_step;
         19                   }
         20                   wait(1);
         21          }
         22 }
Ne yapmaya çalıştığımızı satır satır anlatacağım.

İlk iki işlemde (satır 3 ve 4), biraz önce kapıda yaptığımız gibi, ne kadar haket etmeleri gerekiyorsa,
ilk anki konumlarına ekleyip değişkenlerde tutuyoruz. Yani yukarı aşağı hareket edecekse,
hareketinin sonun konumunun x bileşeni a, yukarı aşağı hareket edicekse konumunun z bileşeni b
olacak.

6-9 satırlarda ise, negatif ve pozitif hareketi kontrol ediyoruz. Eğer öngörülen son konumlar a ve b
den küçükse bu model aşağı veya sola, büyükse yukarı veya sağa gidiyor demektir. Yani a ve b ye
ulaşabilmek için geçerli konumu azaltmamız veya artırmamız gerekebilir. Bunun için modu
kullanacağız, azaltmamız gerektiği zaman mod -1 olacak, artırmamız gerektiği zaman ise mode +1
olacak. Bunu çarpım olarak kullandığımızda ise işareti – ye dönüştürme imkanımız olacak.

11-21 arası, döngümüz.

13-15 arasında yukarı aşağı hareketi kontrol ediyoruz, bunu açıkladığımda ikinci if ide
anlayacaksınız zaten.

kollar[my.numara] == 1 ile dizide numarasına denk gelen yerin 1 olup olmadığını(kolun çekilip
çekilmediğini) kontrol ediyoruz. mod*my.x<mod*b ilede gelmesi gereken yere gelip gelmediğini
kontrol ediyoruz. Burası birz kafa karıştırıcı olabilir, mod +1 olduğunda zaten problem my.x<b
diyip b olana kadar artırmışız gibi oluyor. Mod -1 olduğunda ise durum şöyle, örneğin o anki x
imizin 100 olduğunu ve kolx(skill2) mizin -20 olduğunu varsayalım. Bu durumda b 80 olur.

mod*my.x = -100 olur ve mod*b = -80 olur, ve sağlandığı için if in içine girer.
my.z += mod*4 de ise my.z 4 er 4 er eksilir ve giderek 80 e yaklaşır, 80 olduğumda ise

www.tr3dgs.com– quadraxas.                        28
mod*my.x<mod*b

-1*80<-1*80 olur ve durum sağlanmadığı için ifin içinden çıkar. Diğer ifde aynı mantıkla
çalışmaktadır fakat aynı şeyleri z için yapar.




Evet bu dersin sonu, özellikle son kısmın anlaşılması biraz zor olabilir, fakat önceki dersleri
okuyanların genel olarak bu dersleride anlayacağını tahmin ediyorum. Aslında ders daha uzun
olacaktı, bahsi geçen giriş-çıkış ekranları, sesler, partiküller, bölüm değiştirme, save/load, ekranda
yazı göstermek gibi şeyleride anlatacaktım, ama dersin 30 sayfa olduğunu farkettim ve durmaya
karar verdim. Aslında önceki cümlede söylediğim şeylerin hiçbiri zor değil ama dersi bir 10-15
sayfa daha uzatmayacağım. Bunlar belki ikinci bir ders halinde belkide parça parça olarak
eklenebilir.

Derslerin devam etmesi ise size bağlı, eğer bu dersi okuyup öylece ikinci dersin gelmesini
beklerseniz gelmez. Bu dersten öğrendiklerinizle ve birazda kendiniz kurcayarak ufak birkaç
oyuncuk,projecik yapmazsanız ve forumda göstermezseniz, emin olun bir daha ders filan yazmam.
(hehe :), zaten dersi okurkan bile aklınıza bir çok değişik şey gelmiştir, uygulamaya geçin.)

Son olarak David Lancaster e yazdığı derslerden dolayı teşekkür ediyorum.
Herkese kolay gelsin,
Quadraxas




www.tr3dgs.com– quadraxas.                        29

More Related Content

Featured

Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
Kurio // The Social Media Age(ncy)
 

Featured (20)

PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search Intent
 
How to have difficult conversations
How to have difficult conversations How to have difficult conversations
How to have difficult conversations
 
Introduction to Data Science
Introduction to Data ScienceIntroduction to Data Science
Introduction to Data Science
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best Practices
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project management
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
 
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
 
12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work
 
ChatGPT webinar slides
ChatGPT webinar slidesChatGPT webinar slides
ChatGPT webinar slides
 
More than Just Lines on a Map: Best Practices for U.S Bike Routes
More than Just Lines on a Map: Best Practices for U.S Bike RoutesMore than Just Lines on a Map: Best Practices for U.S Bike Routes
More than Just Lines on a Map: Best Practices for U.S Bike Routes
 
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
 
Barbie - Brand Strategy Presentation
Barbie - Brand Strategy PresentationBarbie - Brand Strategy Presentation
Barbie - Brand Strategy Presentation
 

Sidescroller 1 No Restriction

  • 1. Lite-C SideScroller Workshop by Quadraxas www.tr3dgs.com www.tr3dgs.com– quadraxas. 1
  • 2. Giriş Sidescroller nedir? Sidescroller aslında hepinizin bildiği bir oyun türü. Karakteri ve dünyayı yandan görürsünüz, sürekli sağa veya sola yürürsünüz, zıplar, platformlara tırmanırsınız. Herkesin bildiği Nintendo nun Mario'su, MappleStory v.b. gibi. Bu tür oyunlar aşırı karmaşık özellikler içerebileceği gibi, çok basit minik oyunlar şeklindede olabilir. Basit GameStudio mantığının daha rahat anlaşılması açısından bu türde bir oyun yapacağız. Her oyunda gerekebilecek ve başlangıç seviyesi için uygun bilgiler ele alınacak. Zıplamak, yürümek, altın toplamak, çok basit manada menü yapımı, ses eklemek, giriş ve çıkış ekranları yapımı, basit partiküller, 2d grafiklerin ekranda gösterilmesi vb.. Dersi anlayabilmek için gerekli olan şeyler? Dersi anlayabilmek için önceki script derslerini iyice okumuş (en azından ilk 3 script dersi) ve anlamış olmanız gerekmekte. Bu derste önceki bilgilerin üzerinden devam edilecek. O derslerin yayınlanmasından bu yana meydana gelen değişikliklere bu derste değinilecek. Ders için en az GameStudio A7 Extra veya Lite-c Free versiyonu gerekli. Trial versiyonuda kullanabilirsiniz. Crack versiyonlar eski betaların sürüm numaralarının değiştirilmiş hali olduğu için, bir çok hata meydana gelecektir. Bu tür durumlarda kimseye yardım edilmeyecektir. Bu ders hazırlanırken kullanılan sürüm A7.07 commerical sürümüdür. Metin editörü(OpenOffice Writer, tırnakları ve bazı noktalama işaretlerini değiştirdiğinden kopyala/yapıştır yapmak kodların çalışmamasına neden olabilir.) www.tr3dgs.com– quadraxas. 2
  • 3. Gerekli Harita Konsepti ve Tasarımı1 Yapacağımız sidescroller türündeki platform oyununda, oyuncu haritayı ve modeli yandan görecek ve sadece sağa,sola,yukarı ve aşağı haraket edebilecek, haritayıda buna göre yapacağız. 1 Bu derste anlatılan oyun için. www.tr3dgs.com– quadraxas. 3
  • 4. Haritada görülen oklar oyuncunun haritayı geçebilmesi için izlemesi gereken yol, basit olarak önce gidip anahtarı alması, ardından kilitli kapıyı açıp kolu çekmesi, kol çekildiği için yükselen platform sayesinde yukarı zıplayarak, yeşil yolu izledikten sonra ikinci kolu çekmesi ve ardından 2. kolun açtığı köprüye ulaşmak için pembe yolu izleyip bu haritanın sonuna gelmesi gerekiyor. Harita tasarımı tabiki size kalmış bir şey. Harita oyunun az çok neye benzeyeceği hakkında bilgi veriyor zaten. Basit bir harita yaptım koda geçmek istiyorum! Evet eğer haritanız(haritanız yoksa sadece düz bir plaka koyun işinizi görecektir.) ve modeliniz hazırsa(şu an için herhangi bir model, 3dgs ile gelen cbabe olabilir) oyunumuzu kodlamaya başlayabiliriz. İlk olarak yeni bir sed sayfası açın ve kaydedin(kaydederken isim.c şeklinde kaydedin .c yi unutmayın). Derleyici için bu dosyların normal bir text dosaysından farkı yoktur. İlk satırımız olarak yazdığımız motor fonksiyonlarının tanımlı olabilmesi için, bu fonksionları kullanacağımızı belirten ve bu fonksiyonların oyunumuzun içine eklenmesini sağlayan dosyayı eklemeliyiz. www.tr3dgs.com– quadraxas. 4
  • 5. Bunun için önceki derslerde kullandığımız “include” deyimini kullanacağız. Lite-c de c- scriptden farklı olarak “include”, “define” gibi derleyiciye komut veren deyimler artık normal c dilindeki gibi başına # ekleyerek kullanılıyor. İlk satırımız: #include <acknex.h> Ve motorda tanımlı tüm öğeleri ve fonksyionları kullanabiliriz artık. Peki motor kodları okumaya başlayacağı yeri nereden bilecek? Yine normal c,c++,java dillerindeki gibi program “main” isimli özel bir fonksiyondan işletilmeye başlar. Hemen ekleyelim: #include <acknex.h> function main() { } Şu anda yazdığınız programı derleyip çalıştırırsanız, sadece siyah bir ekran görürsünüz. Zaten olması gerektiği gibi, henüz bir şey yazmadık, o halde level ımızı yükleyelim. #include <acknex.h> function main() { level_load(“platform.wmb”); } level_load : motorda önceden tanımlı bir fonksiyondur ve oyunun üzerinde geçeceği leveli yüklemenizi sağlar, .mdl,.x(modeller), .hmp(terrain), .wmb(derlenmiş wed haritaları) dosyalarını level olarak yükleyebilir. Parametre olarak STRING* level_ismi alır. STRING* : STRING* içinde yazı referansı tutabilen bir değişken türüdür. Kullanımı STRING* level_ismi = “paltform.wmb”; şeklindedir. STRING* parametre alan fonksiyonlarda parametreyi geçmek için stringi önceden tanımlamaya gerek yoktur. Yani level_load a direk olarak level_load(“platform.wmb”); şekilnde parametre geçilebilir. Kodunuzu şimdi çalıştırırsanız eğer levelinizde position(sadece wmblerde) varsa, levelinizdeki positionun gösterdiği yer görünür, eğer position yoksa veya leveliniz wmb dışındaki bir tür ise(mdl,x,hmp) kamera levelin merkezini gösterecektir. Ama gördüğünüz gibi leveliniz pencere içinde ve düşük çözünürlükte. Bunun için kullanılabilecek birden fazla yol var, biz video_set fonksiyonunu kullanarak yapacağız.level_load dan hemen önceki satıra şunu ekliyoruz: www.tr3dgs.com– quadraxas. 5
  • 6. .... video_set(800,600,32,2); level_load(“platform.wmb”); .... video_set: Önceden tanımlı bir fonksiyon. Parametre olarak: video_set(ekran genişliği,ekran yüksekliği,renk değeri,ekran şekli); ekran genişliği ve yüksekliği: bu parameterler ekranın yüksekliğini ve genişliğini ayarlar. Renk değeri : 16 veya 32 (bit) ekran şekli: 1 – tam ekran 2- pencere video_set(800,600,32,2); -> 800x600 32-bit pencere oluşturuyor. Eğer tam ekran kullanacaksanız standart ekran çözünürlüğü oranını göz önünde bulundurdun 4:3(800x600,1024x768) veya 16:9(widescreen). Evet şimdilik ana fonksiyonumuzla(main) işimiz bu kadar. Artık oyuncu kontrollerine geçebiliriz. Bunun için daha önceki derslerden hatırlayacağınız actionları kullanacağız. Actionlar, wedde behaviour menüsünde görülürler ve oyun dünyasındaki objelere özellik kazandırmamızı sağlarlar. Main fonksiyonunun dışında bir action oluşturalım.Aynen fonksyionlar gibi oluşturulurlar ama parametre alamazlar.Actionlar wed de obje üzerine sağtıkladıktan sonra behaviour menüsünden seçilerek objelere atanır. #include <acknex.h> function main() { ... } action oyuncu() { } Konudışı öneri: Script dosyanızı kaydedin ve WED de flie->map properties den script kısmındaki klasör işaretine tıklayarak script dosyanızı seçin. WED açıkken scriptinize yeni bir action eklediğinizde, behaviour menüsünde wedi kapatıp açmadan veya scripti map propertiesden tekrar açmadan gözükmez. Bundan kurtulmak için şunu yapın: WED de file->preferences->advanced- >Reaload of externally modified files kısmından auto yu seçin. Artık değiştirilen modelleriniz,scriptleriniz vb. Hepsindeki değişiklik otomatik olarak wed e yansıyacaktır. Wede geçip oyuncu modelinizi ekleyin ve üzerine sağtıklayıp behavior menüsünü açın. Ve listeden “oyuncu”yu seçip haritanızı kaydedin ve build edin. Artık oyuncunuz “oyuncu” isimli actiona sahip. (actionda her değişiklik yaptığınızda haritayı tekrardan build etmenize gerek YOKTUR.) Oyuncu actionunu tamamlayana kadar wed e de dönmeyeceğiz. Actionumuzu yazmaya başlayalım. Oyuncu sağ ok tuşuyla sağa, sol ok tuşuyla sola gidecek, boşluk tuşu ile zıplayacak ve E tuşu ile www.tr3dgs.com– quadraxas. 6
  • 7. objelerle etkileşimde(kapı açmak kol çekmek vb.) bulunacak. action oyuncu() { while(1) { wait(1); } } While, ve wait in işlevlerini önceki derslerimizde anlatmıştık. Kısaca while döngüler oluşturmamızı sağlıyor, wait ise belli bir frame miktarı boyunca o anki fonksiyonu durdurmaya yarar. While(1) her koşulda sürekli dönen döngü wait(1) ise döngünün sonunda 1 frame bekleyen bir fonksiyon. Motorda kullandığınız bütün while larda wait gereklidir, bu tür işlevler çok hızlı gerçekleştirebildiğinden sınırsız döngüler kısa sürede kaynakları doldurup motoru kilitleyebilir, o yüzden döngünün frame başına 1 kez dönmesi için wait kullanırız. Sürekli dönen döngüler kullanmamamızın nedeni ise şu: Örneğin bir tuşa basılıp basılmadığını anlamamak istiyoruz. Eğer bunu bir kere kontrol edersek sadece o an için kontrol edilir ve bir daha kontrol edilmez, sınırsız döngü içinde kontrol edersek tuşa basılıp basılmadığı sürekli kontrol edilir bizde ne zaman basıldığını ne zaman bırakıldığını anlarız. Oyuncumuzun hareket edebilmesi için oyuncumuza bir vektör uygulanması gereklidir(evet,fizik dersindeki vektör, umarım ucuca ekleyerek vektör ekleme,çıkarmayı biliyorsunuzdur :D ) bunun için while döngümüzden hemen önce bir vektör tanımlıyoruz, ve olabilecek herhangi bir prbleme karşı tüm bileşenlerini sıfırlıyoruz.(hala oyuncu actionundayız, karıştırmayın) VECTOR* hareket_vektoru; //karakteri yürütecek olan vektör hareket_vektoru.x = 0; hareket_vektoru.y = 0; hareket_vektoru.z = 0; while(1) { ... // lardan sonra gelen metnin yorum olduğunu ve ne olursa olsun işletilmediğini unutmayın. Ve şimdide bu vektörün ok tuşlarıyla büyüklüğünün değişmesini sağlayalım ve karakterimize uygulayalım. Vektörlerin bileşenleri direk olarak hareket_vektoru.x = 10; şekilnde değşitirileblir. x,y,z, şekilnde üç bileşeni vardır. Vektörün boyu bu şekilde değiştirilirken, modele uygulanması esnasında farklı yollar izlenebilir. İki çeşit uygulama yolu vardır. www.tr3dgs.com– quadraxas. 7
  • 8. 1.si vektörü dünyaya göre alarak uygulamak 2.si vektörü modele göre alarak uygulamak Absolute yazan şekilde modelin yönü ve duruş açısı ne olursa olsun hep aynı vektör uygulanır, kullanılan koordinat düzlemi dünyanın(haritanın) koordinatlarıdır. Relative yazan şekilde ise, vektör modelin koordinat sistemine göre uygulanır, model döndüğü zaman koordinatlarıda onunla beraber döndüğünden vektör değişmediği halde, dünayadan bakıldığında başka yöne uygulandığı görülür. Şimdi vektörümüzü değiştirip uygulayalım: ... while(1) { if(key_cul == 1 || key_cur == 1)//sağ veya sol ok tuşu basılırsa { hareket_vektoru.x = 10*time_step; } else// ok tuşlarına basılmazsa { hareket_vektoru.x = 0; } c_move(me, hareket_vektoru, nullvector,GLIDE|USE_BOX); ... if ve else, daha önceki derslerde anlatıldı. Kısaca if bloğunun yani if den sonra gelen { } arasındaki kodların işletilebilmesi için if parantezleri içindeki koşulun sağlanması gerekir, eğer bu koşul sağlanmazsa else bloğu(elseden sonraki { } arası ) içindeki kodlar işletilir. key_cul sol ok tuşunu key_cur sağ ok tuşunu key_e e harfini .. vb ifade eder.key_ ile başlayan değişkenlerin 1 olması demek o tuşun o an basılıyor olması manasına gelir. Yani eğer tuşlara basılıyorsa hareket_vektoru nun x bileşeni 10*time_step olacak basılmıyorsa 0 olacak. time_step önceki derslerde anlattığımız time değişkenin yeni adı, motorun farklı fps lerde aynı davranışı göstermesi için bunu kullanırız, yoksa karakterimiz yüksek fps ile çalışan bilgisayarda daha hızlı yavaş fps ile çalışan bilgisayarda daha yavaş yürür.(önceki derslerde time olarak ayrıntılı şekilde anlatılmaktadır.) www.tr3dgs.com– quadraxas. 8
  • 9. c_move vektörümüzü objemize uygulamamızı sağlar. Aldığı parametrelere bakacak olursak: c_move(obje,rel vektör, abs vektör , notlar); obje: vektörün hangi objeye uygulanacağını belirtir. rel vektör: biraz önce açıklanan resimdeki relative gibi, nesneye nazaran uygulama abs vektör: resimdeki absolute gibi dünyaya nazaran uygulama notlar: notlar haraketi neyin etkileyip neyin etkilmeyeceğini belirtmemizi sağlar. Bizim eklediğimiz satır olan: c_move(me, hareket_vektoru, nullvector,GLIDE|USE_BOX); me: kullanıldığı actionun atandığı nesneyi belirtir, yani burda bizim oyuncumuzu belirtiyor. hareket_vektoru : tanımladığımız ve ok tuşlarıyla etkilediğimiz vektör. Nullvector: tüm bileşenleri 0 olan boş vektör GLIDE|USE_BOX : glide objenin level blokları üzerinde süzülmesini sağlar, eğer bu notu düşmezseniz, objenin eğimli bloklara tırmanamadığını görürsünüz. USE_BOX ise sanki objenin etrafında bir kutu varmış gibi davranmasını sağlar, collisionda yardımcı olacak. Diğer notlar için manuale bakabilirsiniz. Şimdi tekrar çalıştırın ve durumu görün. İki problemle karşılaşmış olabilirsiniz. 1.si her iki yönede basınca aynı yöne gidiyor. 2.si çok hızlı gidiyor veya takıla,takıla gidiyor. İlk problem çok normal, çünkü hangi yöne basarsak basalım model aynı yöne bakıyor ve vektör modele göre uygulanıyor, bunu birazdan çözeceğiz. İkinci problem ise 200 üzeri fps lerde karşılaşabileceğiniz, döngünün bazı framelerde iki kere dönmesi bazılarında ise hiç dönmemesi problemi(aslında öyle olmuyor ama bize öyle geliyor). Genelde işlemci veya ramlarinizin ekran kartınıza yetişemediği durumlarda olur. Bu ve bunun gibi problemler fps ye bir üst sınır koyarak çözülebilir. Bunu yapmak için maindeki video_set den önce kırımızı ile gösterilen satırı eklemek: .... fps_max = 60; video_set(800,600,32,2); level_load(“platform.wmb”); .... Sizinde anladığınız gibi fps nin maksimum sınırını 60 yapıyor. www.tr3dgs.com– quadraxas. 9
  • 10. Şimdi ok tuşlarının oyuncuyu döndürmesi kısmına gelelim. Bunun için while ın içindeki ifden önce iki yeni if ekleyeceğiz. Birincisi: if(key_cur==1){ my.pan = 0; } Yani eğer sağ ok tuşuna basılırsa oyuncunun duruş açsını 0 a eşitliyoruz. İkincisi: if(key_cul==1){ my.pan = 180; } Yani eğer sol tuş basılı olursa oyuncunun açısnı 180 yapıp tam tersi yöne bakmasını sağladık. my ve me referanslarının o anda o actiona sahip olan nesneyi temsil ettiğini,hem daha önceki derslerde hemde bu derste söyledik. Pan,tilt,roll ise önceki derslerdede değindiğimiz gibi objelerin duruş açıları. Pan xy düzleminde tilt xz düzleminde ve rollda zy düzlemindeki açıyı temsil eder. Bu açılar oyuncuyu dünya üzerindeki koordinat sisteminde döndürmeye yarar. Yani 0 olarak kabul edilen açı nesneyi ilk koyduğunuz açı değil, level düzlemlerindeki 0 açılarıdır. Eğer bu tuşlra basmak karakterinizi sağa sola yerine ileri geri götürüyorsa, levelinizi buna göre döndürmelisiniz. Evet şu anda çalışıyor ama ileride zıplama objelerle etkileşim animasyon gibi şeyler ekleyeceğiz. Bu yüzden daha düzenli bir kod sistemi belirleyip onunla ilerlemeliyiz. Bu tür düzenlemelerde veri saklamada kullanılma amaçlı her obje(entity) e ait 100 adet skill ismi verilen değişken eklenmiştir. skill1,skill2,skill3,...skil100 şeklinde. Bunlar my.skill1 = 10; şeklinde kullanılan var türünden değişkenlerdir. Peki bunları kodumuzu sistematikleştirmek için nasıl kullanacağız. Bu noktada devreye #define giriyor. #define: bu anahtar kelime, işletilebilir bir kod değildir sadece derleyiciye kullandığınız bir kelimenin ne demek olduğunu söyler.Mesela; #define durum skill20 demek derleyiceiye durum yazdığım heryere skill20 koy öyle derle demektir. Durum u akılda tutmak skill20 yi akılda tutmaktan kolaydır. Skill20 bir var olduğuna göre içinde sadece sayı tutabilir durumda durumlarımıza sayılar vereceğiz. #define yuru 1 #define zipla 2 #define bekle 3 www.tr3dgs.com– quadraxas. 10
  • 11. Artık my.skill20 = 3; yerine my.durum = bekle; gibi satırlar yazabileceğiz. Definelar genelde fonksiyonların dışında yazılır,şimdilik script sayfanızın başında includelarınızla beraber yazmanız düzenli olması açısından daha iyi. #include <acknex.h> tan hemen sonra: #define durum skill20 #define yuru 1 #define zipla 2 #define bekle 3 ekleyin. Şimdi kodumuzu düzenlemeye geçelim. Oyuncu actionundaki while ımızın içindeki ifleri düzenleyeceğiz: if(key_cur==1){ my.pan = 0; } if(key_cul==1){ my.pan =180; } if(key_cur==1 || key_cul == 1){ hareket_vektoru.x = 10*time_step; } else{ hareket_vektoru.x = 0; } Şeklinde olan if lerimizi if(key_cur==1){ my.pan = 0; my.durum = yuru; } if(key_cul==1){ my.pan =180; my.durum = yuru; } if(my.durum==yuru){ hareket_vektoru.x = 10*time_step; } else{ hareket_vektoru.x = 0; } Şekline getiriyoruz. Hala aynı işi yapıyor ama anlaması daha kolay ve ileride my.durum==zipla gibi deyimleri kullanmamıza olanak tanıyacak şekilde. www.tr3dgs.com– quadraxas. 11
  • 12. Bu noktaya geldiyseniz elinizde şu şekilde bir kod olmalı: Ama oda ne? Karakter durmuyor sürekli haraket ediyor. Bunun sebebi “durum” u “yuru” yaptıktan sonra hep yuru kaldığından , hareket vektörünü değiştiren if in içine sürekli giriyor olması. (redimdeki 30. satırdaki if.) Bunu düzeltmek için while içindeki ilk ifden hemen önce my.durum=bekle; ekliyoruz. Bu şekilde döngü her başladığında en başta durum “bekle” olarak ayarlanacak, yürüme tuşlarına basılırsa iflerin içine girdiğinden durum tekrar “yuru” olacak Bir tuşa basılmazsa durum “bekle” olarak kalacak ve 30. satırdaki koşul sağlanmadığından 31. satır işletilmeyecek. Burada karşımıza ikinci bir çakışma daha çıkıyor, eğer karakter zıplıyorsa “durum”u “yuru” değil , “zipla”demektir(daha eklemedik) ve ifin(30. satır) içine girmez ve else içine girer ve buda karakterin sağa sola zıplamasını durdurur. Bu yüzden bu else i de değiştirip if(durum==bekle) yapacağız. Yani: while ın başına (iflerden önce) my.durum = bekle; www.tr3dgs.com– quadraxas. 12
  • 13. while(1) { my.durum = bekle; if(..... ...... } ve sondaki else yerine if(my.durum==bekle) ..... if(my.durum==yuru){ hareket_vektoru.x = 10*time_step; } if(my.durum==bekle){ hareket_vektoru.x = 0; } ..... ekliyoruz. Şimdi muhtemelen bu dersin en zor kısmı olan zıplamaya geçeceğiz. Bunun için c_trace adı verilen, etraftaki nesneleri taramamızı ve ne kadar uzakta olduklarını anlamamızı sağlayan bir fonksiyon kullanacağız. Karakteri havalandırıp (+z de hareket ettirip), sonra altındaki yeri tarayacağız ve ayağını basacağı yerle ayaklarının arasındaki uzaklık 0 olana kadar aşağı çekeceğiz.Peki nasıl kullanılır bu c_trace ? c_trace(vektör1,vektör2,mod); vektör1 = taramaya başlayacağımız noktanın konumu vektör2 = taramanın biteceği noktanın konumu mod = c_move daki ile hemen hemen aynı olan flaglar dizisi.(yani modelleri es geçmek vb şeyleri belirttiğimiz yer.) c_trace vektör1 noktasından vektör2 noktasına doğru tarama yapar. Yani biz vektör1 yerine oyuncunun o anki konumunu vektör2 yede 5000 metre aşağısını koyarsak, oyuncu ile 5000 metre aşağısı arasında kalan objeleri taramış oluruz. Buda bize karakterin o anki en yakın olduğu basabileceği objenin/yerin uzaklığını verir. Şimdi bu dediklerimizi koda dökelim. Bütün iflerden sonra c_move dan önce şu satırları ekliyoruz. ..... VECTOR ilk; VECTOR son; vec_set(ilk,my.x); vec_set(son,my.x); son.z - = 5000; vec_set : İki vektörü birbirine eşitlemeye yarar, ikinci parametreyi, biinciye eşitler. Yani buradaki vec_setler ilk ve son isimli vektörleri oyuncu konumuna eşitliyor.(Sadece my yazmak vektör değil entity belirtir, mantıken my.x yazmak ise oyuncunun sadece bulunduğu x'i belirtir. Doğru fakat, www.tr3dgs.com– quadraxas. 13
  • 14. entitylerin my.konum gibi bir vektörü yok,bu tür fonksiyonlarda my.x yazdığımızda motor o anki konumu kastettiğimizi anlıyor.) İki vektörüde oyuncunun konumuna getirdik ve son isimli vektörün z sini 5000 quant aşağı çektik. Yani vektör konum olarak oyuncunun 5000 quant aşağısını göstermiş oldu. Şimdi c_trace ile bu vektörleri kullanarak oyuncunun o anki yüksekliğini bulalım. Bunun için actionumuzun en başında “hareket_vektoru” ndan önce veya sonra “var yukseklik = 0;” şekilnde bir değişken tanımlıyoruz. Ardından biraz önceki vec_setler ve son.z - = 5000; den sonra: yukseklik = c_trace(ilk,son,IGNORE_ME|IGNORE_PASSABLE|USE_BOX); Yüksekliği hesaplayıp, “yukeseklik” isimli bir değişkene attık. Şimdi ise boşluk tuşu ile zıplamayı sağlayacağız. Hemen c_trace in ardından; ..... if(key_space==1){ if (yukseklik < 2) { yukseklik = 1; hareket_vektoru.z = 12; } } Peki neden yüksekliğin 2 den küçük olma şartını koyduk? Çünkü hemen ardından hareket vektörüne yukarı doğru bir değer veriyoruz. Eğer kontrol etmezsek karakter havadayken tekrar zıplama tuşuna bastığında biraz daha yükselecektir. Peki neden yüksekliği 1 e eşitledik? Bunu birazdan karakteri aşağıya çeken kodu yazdığımızda göreceğiz. ;) Şimdi yüksekliğin 0 dan büyük olduğu durumları ele alalım.Yani (biraz önceki if in hemen ardıdan); ..... if (yukseklik > 0) { hareket_vektoru.z-=3 * time_step; // düşme my.durum = zipla; if (hareket_vektoru.z < (yukseklik * -1)) { hareket_vektoru.z = yukseklik * -1; } } Evet, anlatması en zor kısım burası. Ne anlattığımı pek anlayamayabilrisiniz, değerle oynayarak ekleme/çıkarma yaparak ne demek istediğimi daha iyi anlayabilirsiniz. Yükseklik 0 dan büyükse, yani karakter havadaysa ya zıplamış ya da bir yerden aşağı atlamış demektir. www.tr3dgs.com– quadraxas. 14
  • 15. Bu durumda karakteri hareket ettiren haraket_vektoru nun z bileşenini azaltmamız gerekir. Bu bileşen bir yerden atlama durumunda, karakter tam atladığı yerin sınırından ayrıldığı andan önce 0 dır, ayrıldığı anda artık altı boşluktur ve c_trace yeni tabanın yüksekliğini döndürmüştür. Bu durumda 0 olan z bileşeni zamanla dahada eksilerek(ivmeli hareket), karakteri aşağı doğru çekiyor. Zıplama durumunda ise, karakter tam zıpladığı anda bir önceki blokda 12 ye eşitlediğimiz z bileşini sıfırdan büyük olduğu için bu if içine giriyor ve çalışmaya başlıyor, karakter daha havadayken ve yükselmekteyken bile z bileşenini azaltıyor. Bi süre sonra z bileşini iyice azalıp 0 ı da aşıyor ve karakteri aşağıya doğru çekmeye başlıyor. Ama bu bileşenin çokda fazla azalmaması lazım, eğer çok fazla azalırsa aşağı çeken vektör çok büyük olacağından karakteri aniden yere yapışıyor gibi görürüz. Bunun içinde bir sorgulama yapıp yükseklikten daha büyük seviyelere çıktığında, tekrar yüksekliğe eşitliyoruz. (burada –(eksi) nin aşağı yönü ifade ettiğini biliyorsunuz?) Hemen ardından şöyle bir else ekliyoruz, önceki if yüksekliğin 0 dan büyük olduğu durumları kontrol ettiğine göre, buda büyük olduğu durumlarda çalışıyor; else { my.durum = bekle; hareket_vektoru.z = -1 * yukseklik; } Bu else içindeki işlemler bir kaç farklı durumu ele almamızı sağlıyor. Eğer uzaklık 0'dan küçükse modeli daha fazla aşağı çekmeye gerek yoktur. hareket_vektörü.z nin yüksekliğe eşitlenmesinin nedeni ise şöyle açıklanabilir. Çarpım kulandığımızdan yukseklik =0 sa hareket_vektoru.z = 0 dır. Yani z ekseninde hareket yok. Eğer yere uzaklık negatif bir değerse, bu modelin bloğun içine girdiği manasına gelir. Bu durumda bu kod kesimi modeli içeri girdiği miktar kadar yukarı iter. Böylelikle net 0 yükseklik sağlanmış olur. Evet, hareket ettirme kısmı biraz zahmetli ve karışık oldu. Fizik dersinin içeriği olan Vektörler nedeniyle anlayamadığınız bir nokta varsa yardımcı olayamacağım.Bilmiyorsanız, Wikipedia yı açıp vektörler hakkında az çok bilgi edinebilirsiniz, fakat çok yardımcı olmayabilir. Eğer vektörler nedir bilmiyorsanız ve oyun programlamak istiyorsanız bir önce öğrenin, oyun motorlarının hepsinde hareket işlemleri vektörlerle yapılır. Bu ders için ortaokul fiziği yeterlidir, fakat daha karmaşık işlemlerde, işin içine trigonometri, ve calculus girebilir :D (anlayan anladı) Şu anda bu aşamadayız: www.tr3dgs.com– quadraxas. 15
  • 17. Sanırım artık iflerden önce while lardan sonra diyerek neyi kastetiğimi anlıyorsunuzdur. Bundan sonra kodun ekran görüntüsünü eklemeyeceğim. Şimdi animasyonlarımızı oynatmaya ve kameramızı ayarlamaya bakacağız. Tanımladığımız durumların işe yarayacağı nokta burası. Modellerin animasyonunu göstermek için ent_animate isimli bir fonksiyon kullanacağız. Ent_animate bir modelin, belli bir sahnesindeki animasyonu oynatmak için kullanılır.O sahnenin adına ihtiyaç vardır. Sahnelerinizi Med-> Edit -> Manage Frames -> Rename Frames den adlandırabilirsiniz. Peki nasıl kullanılır bu ent_animate ? ent_animate(obje,sahne,%yuzde,mod); obje: animasyonunun oynatılmasını istediğini obje sahne: biaz önce nasıl adlandıracağınızı söylediğim sahne (örn. bekle, kos) yuzde: % cinsinden sahnenin %desi. 0 ilk kareyi 100 son kareyi ifade eder.(Animosyonunuz 5 kare bile olsa takılarak gidiyormuş gibi olmaz, Motor bu animasyonu tamamlar) mod: ent_animate de mod yerine yazabileceğiniz 3 seçenek var. ANM_SKIP : motorun animasyonunuzu tamamlamasını istemiyorsanız, moda bunu yazın. ANM_CYCLE : animasyonunuz yürüme,koşma gibi bir sürekli tekrar eden bir animasyonsa bunu kullanırız. ANM_ADD: Bone animationda, boneları o kareye getirmektense o karenin bone açılarını bi sonrakine ekleyek gösterir. Biz ANM_CYCLE kullanacağız. www.tr3dgs.com– quadraxas. 17
  • 18. Şimdi ent_animate de % olarak kullanacağımız bir değişken tanımlayalım. While dan önce “var yukseklik” den önce veya sonra yeni bir değişken ekliyoruz: var anim = 0; Eğer bunu while içine eklerseniz her döngü başında değişken 0 lanacağından sürekli animasyonun ilk karesini görürsünüz. Ent_animate e % olarak geçtiğini parmetrenin 100 den büyük olması problem teşkil etmez. Yürürken “kos” isimli, beklerken “bekle” isimli sahnerleri kullacanacağım. O yüzden if(my.durum == bekle){ } nin içine ent_animate(my,“bekle”,anim,ANM_CYCLE); ekliyorum. Aynı şekilde durumun yuru olduğu if in içinede ent_animate(my,“kos”,anim,ANM_CYCLE); ekliyorum. Durum ayarlarını zaten önceden yaptığımızdan, artık yürürken kosma animasyonunu beklerkende bekleme animasyonunu göreceğiz. Fakat şu anda anim isimli değişken 0. Bunu döngü her döndüğünde bir miktar arttırırsak, animasyonun oynamasını sağlamış oluruz. While ın sonundaki wait den önce anim+= 3*time_step; ekliyoruz. Animasyonun yavaş kaldığını düşünoyorsanız 3 yerine başka bir sayı yazabilirsiniz. Peki ya kamera? Kameranında diğer objeler gibi, x,y,z ve pan,tilt,roll gibi nitelikleri vardır. Bu nitelikleri bir şekilde oyuncununkilerler ilişkilendirerek kameranın konumunu/açısını değiştireceğiz. Kameramız üstteki şekildeki gibi sürekli aynı açı ile yandan oyuncuyu takip etmeli. X ve Z eksninde oyuncu ile aynı hizada, Y de biraz geride ve 90 derece ile duruyor. Bunu koda dökelim. www.tr3dgs.com– quadraxas. 18
  • 19. Kameranın herframede oyuncunun konumuna göre ayarlanması gerektiği için, oyuncu actionunun içindeki while döngüsüne ekliyoruz. c_move dan hemen önce şu satırları ekliyorum: camera.x = my.x; camera.z = my.z; camera.y = my.y – 475; camera.pan = 90; Evet, tam olarak dediğimizyapıyor, kamera x ini ve z sini oyuncuyla aynı yapıp, y sinide oyuncudan biraz geriye çekiyor ve kamerayı 90 derece döndrüyor. Şu anda yürüyebiliyor, zıplayabiliyor, animasyonlarınızı görübeliyor olmanız ve kameranında sizi takip ediyor olması gerekiyor. Oyuncu ile işimiz şimdilik bu kadar. Şimdi toplayacağımız anltınları ve puan sistemini hazırlayalım. Bunun için izlenebilecek bir çok yöntem var. Puanı oyuncunun skill lerinden birinde tutabilirz fakat, level değiştiği zaman, oyuncu silinip, diğer levelde tekrar oluşturulduğu için (en azından şimdilik böyle diyoruz, ent_create kullanmadığımızdan.) Bu yüzden puanı normal bir değişkende tutacağız. Mainin dışında define lardan sonra var puan = 0; isimli bir değişken tanımlıyorum. Para aldığımızda bu değişken artacak, ve aynı zamanda ekrande gösterilecek. Şimdi para(altın) olarak kullanacağınız objeyi belirleyin, herşey olabilir, med de herhangi bir obje yapıp onu kullanabilirsiniz.Bu objeye ekleyeceğimiz actionu yazacağız şimdi. Basit manada paraya dokunulduğu zaman, puana belli bir miktar ekleyip, parayı dünyadan kaldıracağız. Fakar her para alındığında aynı sayıyı eklemektense, farklı miktarda puanlar ekleyen para çeşitleri yapalım.Farklı büyüklükte aynı parayı veya değişik obje modellerini kullanmak isteyebiliriz. (bakır , altın, elmas gibi.). İkinci bir action yazmadan, tek actionla puanın farklı miktar artmasını sağlayacağız. Bunun için yine skill leri kullanacağız. Definlarımın altına yeni bir define ekliyorum: #define miktar skill1 Bu skilli kullanarak dokunulan objenin skill1 i kadar puanın artmasını sağlayacağız. Bu şekilde aynı actionu kullanarak, wed den ayarladığımız farklı miktarları objeye ekleyeceğiz.(Ek1 e bakın.) Dokunmayı anlayabilmek içinse EVENT_IMPACT kullanacağız ve eventlere giriş yapmış olacağız. Actionumuzu ve eventimizi yazmaya başlayabiliriz artık. www.tr3dgs.com– quadraxas. 19
  • 20. Önce actionumuzu yazalım actionumuz basit olarak paranın sürekli dönmesine ve dokunulduğunda eventi(henüz yazmadık) çağırmaya yarayacak. action para_action(){ my.emask |= ENABLE_IMPACT; my.event = para_event; while(1){ my.pan+= 10*time_step; wait(1); } } While ve waitin ne iş yaptığını biliyoruz. my.pan ı arttırmanın parayı sürekli döndüreceğinide biliyoruz. Bu kısımda ilk kez gördümüz şeyler emask event ve ENABLE_IMPACT. Objelerinin etkileşiminin büyük kısmı eventlerle sağlanır, eventler objede bir değişiklik meydana geldiğinde tetiklenir, hangi değişikliklerde tetikleneceğinizde emask ile belirleriz, objeye birden farklı türdeevent eklenebilir(dokununca sürüklenen+ateş edince patlayan varil gibi.). Mevcut event türleri için EK-3 e bakın. Bu eventlerin tetiklenebilmesi için emask ın ayarlanmış olması gerekir.Örneğin EVENT_CLICK in ve EVENT_IMPACT in tetiklenmesini istiyoruz. O zaman emask ımız: my.emask |= ENABLE_IMPACT | ENABLE_CLICK; oluyor. Event fonksiyonu ise my.event= fonksiyon adı şeklinde şeklinde atanıyor. Tetiklenen aynı fonksiyon olduğuna göre farklı işler yapmak isterseniz o fonksiyonun içinde hangi eventin tetiklendiğini kontrol etmelisiniz. if(event_type==EVENT_IMPACT) gibi. Yani biz my.emask |= ENABLE_IMPACT; my.event = para_event; yazmakla, objeye dokunulduğunda, para_event isimli fonksiyonun çağrılmasını istediğimizi söylemiş olduk. Şimdi para_event i yazalım(actionun üstüne). function para_event(){ if(you==player && event_type == EVENT_IMPACT){ puan += my.miktar; ent_remove(me); } } “You” da ne? “You” objenin etkileşime geçtiği diğer objeyi gösteren bir göstergedir. Player ise herhangi bir amaçla kullanılabilecek başka bir gösterge. Peki oyun bizim “player” olduğumuzu nerden bilecek? www.tr3dgs.com– quadraxas. 20
  • 21. Bilmesi için oyuncu actionumuzun en başına, player=me; eklemeliyiz. Bunu yapmamızın nedeni şu, ilerdeki derslerde düşman eklediğimiz zaman, düşman altınlara dokunduğunda event_impactin tetiklenmesini engellemek. ent_remove(obje); ise parametre olarak geçilen objenin yok edilmesini sağlar. Yani ent_remove(me); diyerek o eventi tetikleyen objenin(para) ortadan kaldırılmasını sağlıyoruz. Miktar isimli skilli daha önceden tanımlamıştık. O objenin(para) miktarı(skill1) kadar eklee yapıyor puana. Bunun için bütün paraların skill1 lerini wed den ayarlamamız gerekiyor. Bununla uğraşmamak için, sadece farklı olmasını istediklerimi düzenlemek istediğim için para actionunda ufak bir değişiklik yapacağım. Para actionundaki whiledan önce if(my.miktar == 0) {my.miktar = 10;} satırını ekliyorum. Wed e koyulan objelerin koyuldukları zaman tüm skilleri 0 olduğundan, ve normal bir paranın 10 puan vermesini istediğimden, miktarı 0 olan paraların miktarlarını 10 a eşitliyorum. Bu durumda skillerine dokunmadığım tüm paralar 10 puan vermiş oluyor, eğer skillde değişiklik yaparsak yazdığımız sayı kadar puan verecek.(bkz. EK-1) Şimdi bölümünüze Birkaç para koyun ve çalıştırın, artık paralara dokunduğunuzda kayboluyor olmalılar. Şimdi ise puanımızı nasıl ekranda gösterdiğimize geçiyoruz. Ekranda 2 boyutlu grafikleri göstermek için genel olarak PANEL ler kullanılır. Panellerin üzerinde buton, slider, yazılar, değişken ve 2 boyutlu grafik gösterilebilir. Biz basit olarak, arkaya bir resim koyacağız, üstünde de puanımız yazacak.Paneller şu şekilde tanımlanıyor: PANEL* puan_panel = { layer = 1; bmap = "puan.tga"; digits(100,70,4,"Arial#48",1,puan); flags = CENTER_X | CENTER_Y | VISIBLE } Layer : Katman. Eğer paneller üstüste gelirse hangisinin önde görüneceğini belirlememizi sağlar, layeri büyük olan üstte görünür. Bmap : panelin arkasında gösterilecek olan 2 boyulu grafik, tga gibi 32 bit grafiklerin alfa kanallarını destekler. Şimdilik scriptinizin olduğu dizine atın resminizi. Flags : c_move,c_trace de kullandığımız modlar gibi, belli özellikleri açıp kapatmamızı sağlar. Tüm flaglar için manuale bakabilirsiniz.(center flagları digitleri ortalamak için kullanılır, VISIBLE ise görünürlüğü sağlar) www.tr3dgs.com– quadraxas. 21
  • 22. digits : Digit ekranda yazı, değişken gibi öğeleri göstermemizi sağlar. digits(x,y,biçim,font,faktör,değişken); x: panelin sol üst köşesine göre digitin x konumu y: panelin sol üst köşesine göre digitin y konuu biçim: "[text1]%[flags][width][.precision]f[text2]" text1: Yazı (isteğe bağlı) flags:(isteğe bağlı) - : sola daylı yap (varsayılan: sağa dayalı) + : sayıların işaretini göster(varsayılan: sadece negatif sayıların işaretini göster) 0 : width e erişene kadar başa 0 ekle # : sayılının . İçermesini zorunlu kılar width:minimum genişliği belirtmeye yarar(isteğebağlı) .precision : noktasan sonraki basamak sayısı (isteğebağlı) text2:yazı (isteğebağlı) faktör:değişkenin katsayısı (belli bir sayıyla çarpmanız gerekirse diye.) değişken: Göstermek istediğiniz değişken. Örnekler: x= 12345.93 için ve tex_name= “texture” için digits(0,0,"Vol: %.1f ltr",*,1,x); // "Vol: 12345.9 ltr" gösterir digits(0,0,"Selaam :)",*,0,0); // "Selaam :)" gösterir digits(0,0,0,*,1,tex_name); // "texture" göterir. digits(0,0,"Texture Adı: %s",*,1,tex_name); // "Texture Adı: texture" gösterir bizim yazdığımız ise: digits(100,70,4,"Arial#48",1,puan); ekranda puanı gösteriyor (ordaki 4 width e krşılık geliyor.) Şu anda oyunu çalıştırırsanız, koyduğunuz resmi ve puanınızı görüyor olmalısınız. Ve Şimdide Kapılar & anahtarlar, kollar & geçitler.(kolu çekersiniz, geçit açılır gibi.) Öncelikle şimdi izleyeceğimiz yöntemin, daha rahat anlaşılması için seçildiğini söyleyeyim. Anahtar/kapı işini yapmanın en iyi yolu değil, fakat bu oyun için yeterli. Aslında anahtar/kapı ile kol/geçit aynı şey. Sadece biri kolu çeker çekmez harekete geçiyor diğeri ise anahtarı alıp yanına gittikten sonra aktifleştirmek istesek çalışıyor. Bu işi yapmak için diziler kullanacağız, anahtar alındığında/kol çekildiğinde bununla ilgili bir mesaj göstereceğiz. Dizi nedir? Diziler, birden fazla değişkeni bir arada tutup, işlerimizi kolaylaştırmaya yarar. Tanımlanması normal değişkenlerden biraz farklıdır. var dizi[diziuzunluğu]; şeklinde tanımlanır, dizi uzunluğu tam sayı olmalıdır, ve bir değişken olamaz. Derleme esnasında dizinin boyu belli olmalıdır.(Linked-List lerde uzunluk çalışma esnasında değiştirilebilir, ama şu an için yeni başlayanlara dizi kavramak bile zor gelebileceğinden, linked-list e hiç girmiyorum). www.tr3dgs.com– quadraxas. 22
  • 23. Öncelikle anahtar ve kapılardan başlıyorum. Bunun için mainden önce var anahtarlar[5] = {0,0,0,0,0}; ekliyorum. Bu anahtarlar isminde bir dizi oluşturmamızı, ve bütün elemanlarını 0 yapmamızı sağlıyor. Dizi elemanlarını kullanmak istediğimizde anahtarlar[0] diyerk normal değişkenler gibi muamelede bulunabiliriz.Bu dizi için ilk eleman anahtarlar[0] ,son eleman anahtarlar[4] tür. 6. eleman yani anahtarlar[5] dizi sonunu belirtir. Bunun içine bir değişken atamaya kalkarsanız oyununuz çöker veya hata verir. Peki şimdi 5 tane anahtarlar isimli değişkenle ne yapacağız veya neden 5 tane? Şu an için bir levelde en fazla 5 tane kapı olacağınız öngördüğümden 5 anahtar var.(çok iyi bir yöntem olmadığını söylemiştim.) Kapıların ve anahtarların hepsinin bir numarası olcak (0-4 aralığında), bir anahtar alaındığında dizide o anahtarın numarasına denk gelen eleman 1 e eşitlenecek. Ve kapıyı açmaya çalıştığımda dizide kapının numarasına denk gelen yer kontrol edilecek ve eğer 1 se kapı açılacak değilse “kilitli” mesajı gösterilecek. Evet, şimdi bunu kod ile nasıl yapacağımıza bakalım. Öncelikle anahtarı ve dokunulduğunda dizideki elemanın 1 olmasını sağlayacak işleleri yapalım. Bunun için yine skilleri kullanacağız. Kapı ve anahtrların 1. skilleri (skill1) numaraları olacak, bu şekilde kapı ve anahtar numaralarını wed den ayarlayabileceğiz. Definlarımın altına yeni bir define ekliyorum. #define numara skill1 Aynı skillin iki farklı isimle ifade edilmesi probleme neden olmaz. Yapacağımız şey çok zpr değil, para actionunda yaptığımızın aynısını yapacağız. Bu sefer puan artırmak yerine dizide numaraya denk gelen elemanı 1 e eşitleyeceğiz. Sayfanın en altına para actionundan sonra şunu ekliyorum: action anahtar_action(){ my.emask |= ENABLE_IMPACT; my.event = anahtar_event; while(1){ my.pan+= 10*time_step; wait(1); } } Anlaşılmayacak herhangi Bir şey yok, parayla neredeyse aynı,bu sefer anahtar_event isimli fonksiyonu çağıyor. Hemen o fonksiyonuda yazalım. www.tr3dgs.com– quadraxas. 23
  • 24. Bu actiondan önce anahtar_event isimli fonksiyonu yazıyorum. function anahtar_event(){ if(you==player && event_type == EVENT_IMPACT){ anahtarlar[my.numara] = 1; ent_remove(me); } } Bu kadar basit anahtarın numarasına(skill1) denk gelen dizi elamanını 1 yaptık. Hemen kapı actionuna geçelim.Ardından anahtar alındığında veya kapı kilitli olduğunda mesaj göstermeceğimiz fonksiyonu yazacağız. Kapı için bu sefer biraz daha değişik bir yöntem izleyeceğiz ve IMPACT den farklı bir event kullanacağız. Oyuncu E tuşuna basarak etkileşime geçecek demiştik. Bunu şu şekilde sağlayacağız. E tuşuna basıldığında karakterin önünü tarayacağız. İşin karakter kısmı bu kadar. Kapı veya kol kısmında ise EVENT_SCAN kullarak, tarandıkları zaman eventlerinin tetiklenmesini sağlayacağız. Önce karakter kısmını halledelim. Karakter actionundaki if(key_cul) ve if(key_cur) dan sonra yeni bir if ekliyoruz. if(key_e == 1){ c_scan(my.x,my.pan,vector(120,0,50),IGNORE_ME); } Peki neden önceden kullandığımız c_trace değilde c_scan kullanıyoruz. Çünkü c_trace iki konum vektörü arasında kalan düz çizgiye değen şeyleri tarar. c_scan ise 3 boyutlu uzayda bizim belirlediğimiz bir koni veya kürenin içine giren objeleri tarar. Tamam, kapı gibi objelerde c_trace in da değme ihtimali yüksektir ama, örneğin ileri kullanacağımız kol/şalter gibi objeler küçük olduklarından c_trace in değme ihtimali düşüktür. Koni c_scan e geçilen parametrelerle belirlenir. c_scan(başlama noktası,koninin açısı,Koni vektörü,mod); c_scan(my.x,my.pan,vector(120,0,50),IGNORE_ME); başlama noktası: tarama konisinin yerleştirileceği konum. my.x diyerek oyuncunun merkezine getirmiş oluyoruz. Koninin açısı: koninin uzaydaki duruş açısı, oyununcunun açısna eşitledik. Koni vektörü: x bileşeni: Yatay scan alnı, veya açı olarak koni genişliği (360 girersniz küre olur.) y bileşeni: Dikey scan alanı, 0 koymak dairesel yapar. z bileşeni: Scan uzaklığı(50 quant ileriyi tarayacağız) mod: Diğerlerine benzer şekilde scan işleminin özelliklerini belirlememizi sağlar. Artık e ye bastığımız zaman önümüzü tarıyoruz. Şimdi tarandığında tepki veren objemizi(kapı) yapacağız. Kapı önüne gelinip e ye basıldığında(c_scan edildiğinde), anahtar oup olmadığına bakılacak ve varsa yukarıya kayarak açılacak. www.tr3dgs.com– quadraxas. 24
  • 25. Bunu yapmak için değişik skill ler kullanacağız? Anahtarları ve numaraları hatırlıyor musunuz? Evet kapının 1. skillide numarası, 2. skilli açıldığında ne kadar yukarı yükseleceği olacak #defein kapiacik skill2 artık bu satırı açıklamaya gerek duymuyorum, diğer defineların altına ekleyin.Kapının actionunu yazalım. Bunu dosyanın en altına ekleyin. action kapi_action(){ my.kapiacik = my.z + my.kapiacik; my.skill3= my.z; my.emask |= ENABLE_SCAN; my.event = kapi_event; } SCAN a duyarlı hale getirdik ve scan edildiğinde kapi_event isimli fonksiyonu çağırması gerektiğini söyledik. Actionun ilk 2 satırı ise şunun için, kapiacik(skill2) wed den ayarlanacak ve kapının ne kadar yükseleğeciğini söyleyecek. Kapı açıldığında ise dünaya göre konumu , ilk konumu + bizim söylediğimiz yükseklik, kadar olacaktır. my.kapiacik = my.z + my.kapiacik; diyerek kapalı haldeki konumu ve verdiğimiz yüksekliğ toplayıp, tekrar my.kapiacik in içine yerleştirdik. Skill3 e ise kapının kapalı haldeki(ilk hali) konumunu kaydettik. Açık kapıyı kapatırken bu değeri kullanacağız. Yani kapı açıldığında konumunun Z bileşenin değeri, my.kapiacik olacak, kapandığında ise my.skill3 olacak. Eventimizde bunları düzenleyeceğiz. Yine actionun üstüne kapi_event isimli fonksiyonu ekliyoruz. 1 function kapi_event(){ 2 if(you==player){ 3 if(anahtarlar[my.numara] == 1){ 4 while(my.z<my.kapiacik ){ 5 my.z+= 4*time_step; 6 wait(1); 7 } 8 if(my.z >= my.kapiacik){ my.z = my.kapiacik;} 9 wait(-1); 10 11 while(my.z>my.skill3 ){ 12 my.z-= 4*time_step; 13 wait(1); 14 } 15 if(my.z <= my.skill3){ my.z = my.skill3;} 16 } 17 } 18 } www.tr3dgs.com– quadraxas. 25
  • 26. Hangi parantezlerin birbirinin karşılığı olduğunu göstermek için farkı renkelere boyadım. Buraya kadar anladıysanız bundan sonra söylediklerimi anlamanız zor olmayacaktır. İlk if de scanı yapan kişinin oyuncu olup olmadığına bakıyorum. İkinci if de anatar dizisinden kapının numarasına(skill1) denk gelen yerin 1 olup olmadığını kontrol ettim.Anahtar alınca anahtar numarısına denk gelen yerin 1 e eşitlendğini hatırlayın. Yani anahtarlarınız ve kapılarınız aynı numaraya sahip olmalı. Kapı ve anahtarlarınızı koyarken wed den numaralandırayı unutmayın. İlk while da kapının yüksekliği my.kapiacik a eşit oluncaya kadar yukarı çekiyorum. Hemen ardından gelen if de ise taşmayı kontrol ediyorum. Yani, kapıyı 4er 4er çektiğim için, gerekli değeri 3 veya 2 gibi bir değerler geçebilir, bu yüzden bu if de o taşmayı geri çekiyorum. wait(-1); bu aslında önceki derslerde anlattığımız, sleep isimli fonksiyonun karşılığı. Waite parametre olarak pozitif bir değer geçerseniz, geçtiğiniz parametre kadar frame(kare) bekler. Eğer negatif bir parametre geçerseniz, geçtiğini parametre kadar saniye bekler. Yani buradaki kullanımı 1 saniye bekliyor. Kapı 1 saniye açık kalığ kapanacak. Hemen ardındaki while da ise kapının yüksekliği, actionda önceden sakladığımız ilk konum(skill3) e eşit olana kadar aşağı çekiliyor, ve yine aynı şekilde ardından gelen if de taşma kontrol ediliyor. Şu anda anahatalarınızı aldıktan sonra, kapılarınızı açabiliyor olmalısınız. Wed de anahtar ve kapının skill1 lerine numaralarını kapının skill2 sine ise açılma yüksekliğini yazmayı unutmayın. Kapılara aynı numaraları vererek tek anahtarla farklı kapıların açılmasını sağlayabilirsiniz. Bu derslik son olarak kollar ve geçitleride anlatığ noktalayacağız. Dosyamızın başına, anahtarlar dizisinin altına yeni bir dizi ekliyoruz. var kollar[5] = {0,0,0,0,0}; Yine aynı mantıkla çalışacağız bu sefer anahtar alıp oyuncunun kapıyı taramasını beklemektense, kol çekilir çekilmez, hedeflerini harekete geçireceğiz. Bu seferde oyuncu kolun yanına gelip tarama(e) tuşuna bastığında, kol aktifleşecek ve dizide numarasın karşılık gelen yeri 1 e eşitleyecek. Kolun hedefi olan platform ise sürekli dizide kendi numarasına denk gelen yeri kontrol edip, 1 olduğu anda haraket geçecek. Skill1 ler yine numaraları olacak, kolların hedefleri olan geçitlerin skill2 si ne kadar ne kadar sağa sola hareket etmeleri gerektiğini skill3 leri ise ne kadar yukarı hareket etmeleri gerektiğini belirtecek. Tek actionla hem yukarı hemde sağa sola kayan platformları halletmiş olacağız. Kollardan başlayalım. action kol(){ my.emask |= ENABLE_SCAN; my.event = kol_event; } Tek yaptığımız scan e duyarlı hale getirmek ve scan edildiğinde kol_event isimli eventi çağıracağınız belirtmek. www.tr3dgs.com– quadraxas. 26
  • 27. kol_event isimli eventi yazalım. function kol_event(){ if(kollar[my.numara]!=1){ if(you==player){ while(my.tilt > -45){ my.tilt -= 4*time_step; wait(1); } kollar[my.numara] = 1; } wait(-1); } } İlk if kolun zaten çekilip çekilmediğini yani dizide numaranı denk gelen yerin 1 olup olmadığını kontrol ediyor ve değilse giriyor. (!= in “değilse” manasına geldiğini hatırlayın.) İkinci if ise herzamanki gibi taramayı yapanın oyuncu olup olmadığını kontrol ediyor. İçerideki while ise kolun duruş açısını -45 olana kadar azaltıyor. Eğer kol yerine düğme kullanacaksanız bu while ı kaldırabilrisiniz.(solda kol çekilmeden önce sağda ise çekildikten sonra) Whiledan hemen sonra ise dizide kolun numarasına denk gelen yeri 1 e eşitliyoruz. Wait i eventin saniyede en fazla 1 kere çağırılabilmesi için koyduk. Artık kolu çektiğimizde açısı -45 olana kadar aşağı dönüyor ve dizide numarasına denk gelen yeri 1 yapıyor. Şimdi ise kol çekildiğinde harekete geçecek platformlara atamamız gereken actionu yazacağız. Öncelikle skill2 nin x eksenindeki değişikliği skill3 ünde z ekseninde değişikliği belirteceğini hatırlatayım. Daha rahat hatırlamak için diğer define larımın yanına şunları ekliyorum: #define kolx skill2 #define kolz skill3 ve actionumuz, dosyanın sonuna ekliyoruz: www.tr3dgs.com– quadraxas. 27
  • 28. 1 action kol_hedef(){ 2 3 var a = my.z + my.kolz; 4 var b = my.x + my.kolx; 5 6 var mod = 1; 7 if(a<my.z || b<my.x){ 8 var mod = -1; 9 } 10 11 while(1){ 12 13 if(kollar[my.numara] == 1 && mod*my.z< mod*a){ 14 my.z += mod*4*time_step; 15 } 16 17 if(kollar[my.numara] == 1 && mod*my.x< mod*b){ 18 my.x += mod*4*time_step; 19 } 20 wait(1); 21 } 22 } Ne yapmaya çalıştığımızı satır satır anlatacağım. İlk iki işlemde (satır 3 ve 4), biraz önce kapıda yaptığımız gibi, ne kadar haket etmeleri gerekiyorsa, ilk anki konumlarına ekleyip değişkenlerde tutuyoruz. Yani yukarı aşağı hareket edecekse, hareketinin sonun konumunun x bileşeni a, yukarı aşağı hareket edicekse konumunun z bileşeni b olacak. 6-9 satırlarda ise, negatif ve pozitif hareketi kontrol ediyoruz. Eğer öngörülen son konumlar a ve b den küçükse bu model aşağı veya sola, büyükse yukarı veya sağa gidiyor demektir. Yani a ve b ye ulaşabilmek için geçerli konumu azaltmamız veya artırmamız gerekebilir. Bunun için modu kullanacağız, azaltmamız gerektiği zaman mod -1 olacak, artırmamız gerektiği zaman ise mode +1 olacak. Bunu çarpım olarak kullandığımızda ise işareti – ye dönüştürme imkanımız olacak. 11-21 arası, döngümüz. 13-15 arasında yukarı aşağı hareketi kontrol ediyoruz, bunu açıkladığımda ikinci if ide anlayacaksınız zaten. kollar[my.numara] == 1 ile dizide numarasına denk gelen yerin 1 olup olmadığını(kolun çekilip çekilmediğini) kontrol ediyoruz. mod*my.x<mod*b ilede gelmesi gereken yere gelip gelmediğini kontrol ediyoruz. Burası birz kafa karıştırıcı olabilir, mod +1 olduğunda zaten problem my.x<b diyip b olana kadar artırmışız gibi oluyor. Mod -1 olduğunda ise durum şöyle, örneğin o anki x imizin 100 olduğunu ve kolx(skill2) mizin -20 olduğunu varsayalım. Bu durumda b 80 olur. mod*my.x = -100 olur ve mod*b = -80 olur, ve sağlandığı için if in içine girer. my.z += mod*4 de ise my.z 4 er 4 er eksilir ve giderek 80 e yaklaşır, 80 olduğumda ise www.tr3dgs.com– quadraxas. 28
  • 29. mod*my.x<mod*b -1*80<-1*80 olur ve durum sağlanmadığı için ifin içinden çıkar. Diğer ifde aynı mantıkla çalışmaktadır fakat aynı şeyleri z için yapar. Evet bu dersin sonu, özellikle son kısmın anlaşılması biraz zor olabilir, fakat önceki dersleri okuyanların genel olarak bu dersleride anlayacağını tahmin ediyorum. Aslında ders daha uzun olacaktı, bahsi geçen giriş-çıkış ekranları, sesler, partiküller, bölüm değiştirme, save/load, ekranda yazı göstermek gibi şeyleride anlatacaktım, ama dersin 30 sayfa olduğunu farkettim ve durmaya karar verdim. Aslında önceki cümlede söylediğim şeylerin hiçbiri zor değil ama dersi bir 10-15 sayfa daha uzatmayacağım. Bunlar belki ikinci bir ders halinde belkide parça parça olarak eklenebilir. Derslerin devam etmesi ise size bağlı, eğer bu dersi okuyup öylece ikinci dersin gelmesini beklerseniz gelmez. Bu dersten öğrendiklerinizle ve birazda kendiniz kurcayarak ufak birkaç oyuncuk,projecik yapmazsanız ve forumda göstermezseniz, emin olun bir daha ders filan yazmam. (hehe :), zaten dersi okurkan bile aklınıza bir çok değişik şey gelmiştir, uygulamaya geçin.) Son olarak David Lancaster e yazdığı derslerden dolayı teşekkür ediyorum. Herkese kolay gelsin, Quadraxas www.tr3dgs.com– quadraxas. 29