Sidescroller 1 No Restriction

1,045 views

Published on

Published in: Business, Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,045
On SlideShare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
6
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Sidescroller 1 No Restriction

  1. 1. Lite-C SideScroller Workshop by Quadraxas www.tr3dgs.com www.tr3dgs.com– quadraxas. 1
  2. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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
  16. 16. www.tr3dgs.com– quadraxas. 16
  17. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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

×