Materyal hakkında ön bilgilendirme.
Tahmini okuma süresi: 10 dakika
Öğrenme zorluk seviyesi: OrtaBu öğreticiyi daha iyi kavrayabilmek için Lua Programlama Dili Söz Dizimi Öğrenimi öğreticisine erişebilirsiniz.
Merhaba! Bu materyalde şunları öğreneceksiniz:
- Programlama
- Veri türleri
- Kullanım yerleri
Programlama nedir?
Roblox platformunda kullanılan Lua programlama dili, oyun tasarlamada önemli bir yere sahiptir. Modelleme, inşa etme, animasyon üretme vb. farklı dallar vardır ve bunlardan en önemli olanlarından biri ise programlamadır.
Programcılık kısaca şöyle tanımlanabilir: İnsanın verdiği komutların bilgisayar tarafından yürütülmesi. İnsanın anlayabileceği türden dilde verilen komutların bilgisayar makinesinde bilgisayarın algıladığı şekilde dönüşüme uğramasıyla bilgisayar ile insan arasında köprü kurmaktır. Bu komutların verilmesi için bilgisayarın anlayabileceği bir dil kullanılmalıdır. Bu dil, insanların kavrayamayabileceği türden olduğu için farklı programlama türleri doğmuştur. Dolayısıyla, yazılan diller her ne kadar insan dillerine yakın olsa da bilgisayarda farklı bir şekilde yürütülür.
Yazılım yapmak için birtakım söz dizimsel kuralların bilinmesi zorunludur. Bu kurallar çerçevesinde bilgisayar ortamındaki varlıkları tasnif etmek için veri türleri ortaya çıkmıştır.
Roblox Lua’nın 5.1 versiyonunu kullanır. Yıllar içinde zamanla gelişen Roblox, çekirdek kod betiklerinin uzunluğu hayli arttığı, sayısı artan geliştiricilerin Roblox Studio’da performansı yüksek bir deneyim elde etmesi için Lua’dan türetilmiş olan Luau dilini kullanmaya başlamıştır.
Burada öğrenilecek kavramlar, Roblox platformunun kendi içinde kullanılan veri türleriyle karıştırılmamalıdır.
Temel veri türleri
Lua programlama dilinde 8 temel veri türü vardır. Bunlar: boolean
, nil
, number
, string
, function
, table
, thread
, userdata
.
boolean
İsmini matematikçi George Boole’un yaptığı çalışmalardan alır (Boole cebiri). Bu veri türü sadece iki değer alır: true
ve false
. Anlamları sırasıyla “doğru” ve "yanlış"tır. Genellikle kondisyonlarda kullanılır. Lua’da her zaman küçük harfle başlarlar.
type
fonksiyonu, verilen argümanın türünü döndürür. Buna ek olarak, Roblox’un eklediği typeof
fonksiyonu vardır. Bu fonksiyon da aşağıdaki gibi kullanılabilir.
type
ve typeof
ile ilgili karşılaştırmalar sayfanın alt kısmında yer almaktadır.
Kullanım yerleri
Örneğin, oyunun sahibi olan gruba üye olan oyuncu oyuna katıldığında ona ödül veriliyor. Ödül verilmesinin iki şartı var: Grupta olması ve günlük ödülü almamış olması. and
mantık kapısı ile yapılan bu kondisyon, iki değer de true
döndürürse kondisyon sağlanır.
Meraklısı için
Lua’da ternary
(koşul) operatörü olmadığı için Luau takımı tarafından yeni bir yöntem geliştirildi.
Aynı zamanda, sadece bir değil; iki, üç vs. kondisyon yazılabilir. Bu da elseif
ile sağlanabilir.
Lua’nın kendi söz dizimi tarafından kabul edilmemektedir, sadece Roblox Lua’da çalışır.
if
kondisyonu söz diziminden tek farkı, sonunda end
kelimesi bulundurmamasıdır.
Söz dizimsel olarak aynı gözüken fakat normalde farklı olan değerler olabilir.
- Bellekte depolanan veriler
Bu veri türlerinin saklanması, RAM’de (rastgele erişimli hafıza) gerçekleşir ve her fonksiyon, dizi gibi veri türü oluşturulduğunda bu verilerin hafızada depolandığı bölüm farklı olur.
Yukarıda belirtildiği gibi, hex
değerleri her biri için farklıdır ve bellekte farklı bölümü işaret eder.
- 0/0 belirsizliği
Bu da ayrıca diğer bir kondisyonlardan biridir. 0/0 nan
(not a number) (sayı değil) döndürür. nan == nan
her zaman false
döndürecektir.
nil
Kısacası hiçbir şey demektir. Herhangi bir şeyin var olmadığını gösterir. Var olan bir veri nil
ile yok edilebilir ve tekrar başka bir veri atanabilir.
Lua’da false
ve nil
değerleri dışındaki bütün veriler doğru kabul edilir. Python gibi dillerde karakter içermeyen string
ve içi boş tuple
değerleri false döndürürken Lua’da böyle bir durum söz konusu değildir.
false
ve nil
yanlış kabul edilir ancak false
ve nil
birbirine eşit değildir. Bunların olumsuzu true
değerine dönüşür.
Aynı zamanda, false
ve nil
dışındaki her şeyin olumsuzu false
döndürürken nil
döndürmez.
Kullanım yerleri
Örneğin, ReplicatedStorage
servisinde bir nesne bulmaya çalışılıyor. Bu nesne var ise kod akışına devam edilir ancak yoksa kod akışı durdurulur.
FindFirstChild
, o anda var olan bir nesneyi arar. Eğer o nesne yoksa nil
döndürür. Olumsuzu true
olduğu için kondisyon sağlanmıştır.
return
kelimesi function
başlığı içinde anlatılmıştır.
number
Lua, double-precision floating-point
formatındaki sayıları (çift kesinlikli (duyarlı) kayan noktalı sayılar) (kısaca double) kullanır. Bu sayıların özellikleri şu şekildedir:
- Tek duyarlı kayan noktalı sayılara göre işlemler birazcık daha uzun sürer fakat performans farkı ihmal edilebilir derecededir.
- -2^53 ve 2^53 arasındaki (-2^53 ve 2^53 dahil) bütün tamsayılar, işlemlerden geçerken kesinlik kaybetmez. Fakat bu değerlerin dışındaki tamsayılar, işlem yapılmasına rağmen, her zaman çift sayıya dönüşür ve kesinlik kaybeder. Örneğin 2^53 + 1 yine 2^53 olarak gösterilecektir.
- Gösterilebilen en büyük sayı yaklaşık olarak 1.7x10^308 ya da 2^1024, en küçük sayı bu sayının negatifidir.
- Bu sayılarda karmaşık sayılar kabul edilmez. Python, Fortran, C++ gibi programlama dillerine kıyasla karmaşık sayılar Lua’da ifade edilemez.
- Lua’da 0^0 ifadesi 1 kabul edilir. 0 dışındaki herhangi bir sayının 0’a bölümü işaretiyle birlikte
inf
ve bu da işaretiyle birliktemath.huge
ifadesine eşittir. 0’ın 0’a bölümünan
verir. 0’ın negatif kuvvetleri yineinf
döndürür.
Lua’da sayı oluşturmanın birkaç yolu vardır. Sırasıyla:
- Binary (base-2) (ikilik taban) formatı
- Hexadecimal (base-16) (on altılık taban) formatı
- E notasyonu (mühendislik notasyonu değil)
- Alt tire yardımı
- Birler basamağı olmadan (sıfır)
Kullanım yerleri
Hemen hemen her yerde kullanılır. Daha çok simülator oyunlarında karşımıza çıkar.
string
Tanımı kısaca şöyledir: bir dizi karakterden oluşan yapı. Bilgisayarlarda kullanılan karakter terimi; sembol, harf gibi simgeleri ya da grafemi temsil eder.
string
oluşturmanın birkaç yolu vardır. Bunlar çift tırnak işareti, tek tırnak işareti ve çift köşeli parantezler yöntemleridir. Çift köşeli parantez kullanmanın faydası, string
in kendi içinde yeni satır karakterini içerebilmek ve tırnak işaretlerini beraber koyabilmektir.
Lua’da belirli sebeplerle string
veri türü içinde veriyi kendi içinde değiştirme amacıyla bazı karakterler, başka karakterlerin yerini alır. Örneğin çift parantez kullanılmadığı zaman yeni satır karakterini kullanmak olanaksızdır. Bunun yerine \n
ifadesi kullanılır. Ters slash
sembolü, bu işlev için kullanılmaktadır. Tek başına kullanıldığında hata verir. Bunun için sembolün iki kere yazılması gerekir.
Eğer bir string
ile number
matematiksel işlemlerden geçiriliyorsa string
, number
türüne dönüşütürülmeye çalışılır. Eğer olmazsa betik hata verir.
string
veri türünde sayılar verilmişse ve karşılaştırma yapılıyorsa şu tür durumlarla karşılaşılır.
İlk durumda 123’ün 9’dan büyükmüş gibi görünmesi, aslında sayıların string
olarak depolanmasından kaynaklanır. Çünkü 9 karakter olarak ondalık gösterimde 57’lik değere sahipken 1 değeri 49’a sahiptir. İlk defada 9 ve 1 karakterleri karşılaştırıldığı için "9" > "123"
ifadesi doğrudur.
İkinci durumda "0" == 0
ifadesinin yanlış olmasının nedeni, veri türlerinin farklı olmasıdır.
Sonuç olarak, string
ve number
beraber kullanılırken ilişkisel operatörler (==, ~=, >, <, >=, <=) çalışmazken matematiksel operatörler (+, -, *, /, %, ^) ve bileşik matematik operatörleri (+=, -=, *=, /=, %=, ^=) ve ek olarak ..
ile ..=
ile çalışır.
function
Fonksiyonun faydaları:
- Yazılımda kullanılan benzer ifadelerin ya da aynı işlevi gören blokların fonksiyon çağrılarak kullanılması ve kod uzunluğunun kısaltılması
- Karmaşıklığı önlemek için farklı işlev yapan kodların, programcının anlayabileceği bir şekilde bir fonksiyon isimlendirmesiyle bu fonksiyonda kullanılması
Fonksiyon oluşturmanın iki yolu vardır: Diğer değişkenler gibi fonksiyonun =
ile atanması ve sugar syntax
(söz dizimsel şeker) olarak kabul edilen, fonksiyon isminin function
kelimesinden sonra yazılması. Söz dizimsel şeker, kısaca okumayı ve yazmayı kolaylaştıran, programlama dilinin mantığını bozmadığı sürece kabul edilmiş söz dizimi demektir.
Fonksiyonlarda sıkça kullanılan kelimelerden biri ise return
ifadesidir. Temel olarak iki görevi vardır:
- Fonksiyonun çağrılmasının ardından fonksiyonun bitmesiyle bir değeri döndürmek
- Kod akışını durdurulmak (oradaki
scope
için)
return
kelimesinin kullanılmasıyla getir
fonksiyonu görevini tamamlamıştır. Bunun yanında getir
fonksiyonu pi
değişkenini math.pi
değerine atamıştır. Böylece bu değişken artık betiğin tamamında kullanılabilir.
Kullanım yerleri
Oyunumuzdan alınan bu yazılım örneği gibi birçok satırdan oluşan ve farklı yerlerde kullanılmak üzere olan kodlar, kullanım kolaylığı için tek bir fonksiyona -onShop3DRequested
- dökülmüştür.
table
Numaralarla ya da özel anahtarla belirlenmiş olan değerleri saklamak için kullanılan bir veri türüdür. Bu veri türünde diğer veri türleri depolanabilir ve istendiği zaman bu değerler alınabilir, silinebilir, taşınabilir; değerlerin anahtarları değiştirilebilir.
Array (Dizi): Sıralı ögelerden oluşan table
türü.
Dictionary (Sözlük): İndisleri sayılardan farklı olabilen table
türü.
a
değişkeni boş bir table
oluşturmuştur.
b
değişkeni indisi yazılmamış bir array
oluşturmuştur.
c
değişkeni indisleri yazılmış bir array
oluşturmuştur.
d
değişkeni anahtar-değer şeklinde yazılan bir dictionary
oluşturmuştur.
Dictionary
oluştururken anahtarı string
türü olan veriler şu şekilde yazılabilir:
Array
ve dictionary
türleri tek bir table
’a yerleştirilebilir fakat yapılması önerilmez.
Bunu yapmada hiçbir sıkıntı yoktur fakat asıl sorun nerede kullanıldığı ile ilgilidir. Lua’da ipairs
fonksiyonu kullanırken anahtar number
dışında bir türse, ipairs
o anahtarı ve saklanan değeri görmezden gelir.
Diğer bir sorun ise, Roblox’un kendi içinde uygulamış olduğu ayarlar sebebiyle, bu tür table
’larda veri kaybı yaşanır (mixed array
sorunu). Bunun örnekleri RemoteEvent nesnesinde ve HTTPService:JSONEncode metodunda görülür. Bunu önlemek için sayılardan oluşan indisler tostring
fonksiyonu ile string
’e dönüştürülür.
Kullanım yerleri
Oyuncunun oyun içi verilerini depolamak için DataStoreService kullanılır. Bu verileri kaydetmek için önemli bir rol oynar.
thread
Kod akışından farklı olarak yürütülen komutlardır. Betik içinde yazılan her satır sıraya göre çalıştırılır. Bir satır bitmeden diğerine geçilmez fakat thread
sayesinde kod akışı tarafından oluşturulmuş başka bir komut, akıştan farklı bir biçimde yürütülür.
Lua’da non-preemptive threading
(kesintiye uğramadan iş parçacığı yürütme) mevcuttur. Bunun anlamı, bir thread
oluşturulduktan sonra başka bir thread
oluşturulabilmesi için öncekinin bitirilmesi ya da durdurulmasına kadar beklenmesi gerekmektedir.
thread
oluşturmak için coroutine
ya da task
kütüphanesine ihtiyaç duyulur.
thread
değişkeni thread
türündedir. thread
türünün kod akışı dışında ilerlediğini gösteren örnek:
1’den 10’a kadar olan sayılar (1 ve 10 dahil), “Selam!” yazmadan önce yazdırılmıştır. 3 saniye geçince “Selam!” yazdırılmıştır.
task
kütüphanesi de coroutine
’e benzer şekilde işler.
thread
’i dead
konumuna getirmek için aşağıdaki fonksiyonlar kullanılır:
task
ile oluşturulmuş bir thread
, coroutine
kütüphanesiyle durdurulabilir; coroutine
kütüphanesiyle oluşturulmuş bir thread
, task
kütüphanesiyle durdurulabilir. Tek farkı, coroutine.close()
fonksiyonu, eğer thread
hata vermediyse true
değerini döndürür; öbür türlü false
ve hata mesajı döndürür. task.cancel()
hiçbir şey döndürmez.
userdata
userdata
, Roblox geliştiricileri tarafından en az kullanılan veri türlerinden olsa gerek. Keyfi C
türündeki verilerin Lua değişkenlerinde saklanmasını sağlar. Pratik olarak çok kullanımı olmasa da şunları belirtmek gereklidir:
- Roblox’un kendi veri türlerinde kullanılır. Örneğin
UDim2.new()
,workspace
gibileri bireruserdata
veri türünden ibarettir. -
Metatable
sayesindemetamethod
eklenerekuserdata
üzerinde hangi operasyonların yapılabileceği belirlenebilir.
Roblox’ta yepyeni bir userdata
oluşturmak için newproxy()
kullanılır.
Meraklısı için
newproxy()
fonksiyonu ile yeni bir userdata oluşturulmuştur. Aldığı argüman, metatable
eklenip eklenmeyeceğine karar verir.
userdata
türüne indeksleme metodunu engellemek amacıyla metatable
eklenmiştir. Bu yüzden metatable
’a __newindex
metodu eklenmiştir. Bu yöntem userdata
içeriğini görmeyi engellemek içindir. Bu userdata
herhangi bir veriyle indekslenmeye kalkılırsa betik hata verir.
Lua’daki 8 temel veri türünü öğrendiniz! Tebrikler! Şimdi sıra birkaç dipnot bırakmaya ve uyarıda bulunmaya geldi.
type
vetypeof
fonksiyonları
Lua’da typeof
fonksiyonu bulunmazken type
fonksiyonu kullanılır. Roblox, kendi veri türlerini oluşturunca type
fonksiyonuna bunu gömmek istiyordu fakat bu geriye dönük uyumluluk olduğu için
typeof
fonksiyonu ekledi. Bu fonksiyon, Roblox’un kendi veri türlerini (örneğin; CFrame, Vector2, PathWaypoint, RBXScriptConnection gibi) döndürür. type
fonksiyonu kullanıldığında ise 8 temel veri türlerini döndürür ve bu tür veriler için aralarından userdata
türünü döndürür. Çünkü Roblox veri türleri birer userdata
’dır.
Roblox’un veri türlerinden sadece bir tanesi, type
fonksiyonunda userdata
olarak gözükmesinin gerekmesine rağmen, farklı bir şekilde gösterilir. Bu veri türü ise Vector3
’tür. Artık bir userdata
olmaktan çıkmıştır. Bunun sebebi burada detaylı anlatılmıştır:
- Kütüphaneler
Genellikle string
için string ve utf8; array
, dictionary
için table; number
için math ve bit32; thread
için coroutine ve task kullanılır.
Göz attığınız için teşekkür ederim. Umarım anlattıklarım faydalı olmuştur. Temel amacım, programlamaya dair Türkçe kaynak oluşturabilmek ve bunu Türk geliştiricilere aktarabilmektir. Kafanızda yatmayan bir soru olursa lütfen sormaktan çekinmeyin. Yanlışım varsa lütfen düzeltin.
Bu materyalde bahsi geçen kelimeler
George Boole
İkili sayı sistemi
Kayan noktalı sayılar
Lua
Luau
On altılı sayı sistemi
Programlama dili
RAM
Söz dizim
Söz dizimsel şeker
Yararlı bulabileceğiniz
ScriptProperties - Check your script stats instantly and while writing!
Scale UIStroke Objects & Limit Thickness with Minimum and Maximum Values
İyi günler!