Giriş
Bu eğitim, Garry's Mod tarafından dosyalardan yeni nesne sınıflarını tanımlamak için kullanılan yöntemleri tartışmaktadır. Bu eğitim GMod'daki uygulamaya odaklansa da, kod ve kavramlar başka yerlerde de kullanılabilir.
Nesne Nedir?
Programlamada bir nesne, belirli bir şekilde organize edilmiş ve yapılandırılmış bir veri koleksiyonudur ve bir sınıftan türetilmiştir. Sınıf örnekleri arasında Entity'ler, Silahlar (ki bunlar sadece süslü entity'lerdir) ve Panel'ler bulunur. Vektörler ve ConVar'lar gibi şeyler de sınıftır ancak bu eğitimin amacı olan dosyalardan oluşturulmazlar.
Çoğu sınıfın, özelliklerini miras aldığı bir temel sınıfı (baseclass) vardır. Daha fazla sınıf oluşturuldukça, bir temel sınıf ağacı oluşmaya başlar. Buna bir örnek, "weapon" sınıfını temel alan, o da "anim" sınıfını temel alan, o da "entity" sınıfını temel alan HL2 "weapon_pistol" silahıdır. Silah, pozisyon ve model gibi bir entity'nin tüm özelliklerine sahiptir ve ayrıca şarjör boyutu ve hasar gibi kendine özgü özellikleri de vardır.
Bu, Silahlar ve Ajanlardan oluşan varsayımsal bir sistemden bir kalıtım hiyerarşisi örneğidir.

Nesneler bir yapıcı (constructor) kullanılarak oluşturulur. Bir yapıcı temel olarak sınıfın bir kopyasını oluşturur ve onu yeni bir nesne olarak döndürür. Garry's Mod'daki yapıcı örnekleri ents.Create, vgui.Create ve Vector'dür.
Lua'da Nesneler
Yöntem 1: module
Lua'da iki tür nesne vardır: C++'da tanımlananlar (userdata olarak adlandırılır) ve Lua içinde tanımlananlar (özel tablolar). Bu durumda, Lua'da tanımlanan nesnelerle devam edeceğiz.
Hadi yeni bir sınıf oluşturalım (sınıfları ayrı dosyalarda oluşturmaya daha sonra geleceğiz).
local AirportClass
= {}
AirportClass.Name
= "Airport"
AirportClass.Code
= "ABC"
AirportClass.City
= "Cityville"
AirportClass.State
= "CA"
function Airport(code)
local newAirport
= table.
Copy(AirportClass)
if code
then
newAirport.Code
= code
end
return newAirport
end
local BWI
= Airport(
"BWI")
local LAX
= Airport(
"LAX")
local ORD
= Airport(
"ORD")
BWI.Name
= "Thurgood Marshall"
BWI.City
= "Baltimore"
BWI.State
= "MD"
LAX.Name
= "Los Angeles International Airport"
LAX.City
= "Los Angeles"
ORD.City
= "Chicago"
ORD.State
= "IL"
ORD.Name
= "O'Hare Airport"
O kadar da zor değildi, değil mi? Bir sınıf tanımlayın, sınıfı bir yapıcıyla kopyalayın ve gerektiği gibi değiştirin. Şimdi dosya tabanlı sınıflara geçelim.
Garry's Mod'da, her sınıfı tanımlamak için klasörler kullanan SWEP'ler, efektler ve SENT'ler gibi birkaç sistem vardır. Özünde, bu sistemler şu adımları izler:
Tanımlanacak tüm sınıfları bulun. Her sınıf klasörü/dosyası için:
- İçine sınıfın tanımlanacağı bir tablo oluşturun.
- Dosyaları çalıştırın.
- Sınıf tablosunu ileride kullanmak üzere bir yere kaydedin.
- O sınıfa ait mevcut nesneleri yenileyin. (Bunu eğitimimizde yapmayacağız.)
- Sınıf tablosunu silin. (Ama başka bir yere kaydettiğimizi değil. Onu daha sonra kullanacağız.)
Öyleyse bu sistemle envanter öğeleri yapalım. Aşağıdaki kod "lua/includes/modules/invitem.lua" dosyasına yazılmalıdır:
local string
= string
local table
= table
local error
= error
local Material
= Material
local baseclass
= baseclass
module(
"invitem")
local invitems
= invitems
or {}
local allitems
= allitems
or {}
invitems.item_baseitem
= {}
invitems.item_baseitem.Icon
= Material(
"vgui/items/baseweapon.png")
invitems.item_baseitem.Name
= "Base Item"
invitems.item_baseitem.Width
= 1
invitems.item_baseitem.Height
= 1
invitems.item_baseitem.Weight
= 1
invitems.item_baseitem.Owner
= NULL
invitems.item_baseitem.BaseClass
= {}
invitems.item_baseitem.UniqueID
= -1
function invitems.item_baseitem:
Init()
end
function invitems.item_baseitem:
Remove()
allitems
[self.id
] = nil
self:
OnRemove()
end
function invitems.item_baseitem:
OnRemove()
end
function invitems.item_baseitem:
GetSize()
return self.Width, self.Height
end
function invitems.item_baseitem:
GetIcon()
return self.Icon
end
baseclass.
Set(
"item_baseitem", invitems.item_baseitem)
function Register(classtbl, name)
name
= string.
lower(name)
baseclass.
Set( name, classtbl )
classtbl.BaseClass
= baseclass.
Get(classtbl.Base)
invitems
[ name
] = classtbl
end
function Create(class)
if not invitems
[class
] then error(
"Tried to create new inventory item from non-existant class: "..class)
end
local newItem
= table.
Copy(invitems
[class
])
local id
= table.
insert(allitems, newItem)
newItem.UniqueID
= id
newItem:
Init()
return newItem
end
function GetClasses()
return invitems
end
function GetClassTable(classname)
return invitems
[classname
]
end
function GetClassTableCopy(classname)
return table.
Copy(invitems
[classname
])
end
function GetAll()
return allitems
end
Artık öğe sınıflarımızı kaydeden, yeni öğe nesneleri oluşturmamıza izin veren, talep üzerine belirli bir sınıfı görüntülememizi sağlayan ve oyundaki mevcut tüm öğe nesnelerinin takibini yapan bir modülümüz var. Ayrıca yeni sınıflarımızı temel alacağımız bir temel sınıfımız (baseclass) da var.
Yeni bir dosyada, lua/autorun/inventory.lua, tüm dosyalarımızı çalıştıralım:
if SERVER
then
AddCSLuaFile()
AddCSLuaFile(
"../includes/modules/invitem.lua")
end
require(
"invitem")
local files,folders
= file.
Find(
"items/*",
"LUA")
for k,File
in pairs(files)
do
local name
= string.
sub(
File,1,string.
find(File,
"%.lua")
-1)
ITEM
= {}
ITEM.ClassName
= name
if SERVER
then
AddCSLuaFile(
"items/"..File)
end
include(
"items/"..File)
if not ITEM.Base
then ITEM.Base
= "item_baseitem" end
invitem.
Register(name,ITEM)
ITEM
= nil
end
for k,folder
in pairs(folders)
do
local name
= string.
sub(
folder,1,string.
find(folder,
"%.lua")
-1)
ITEM
= {}
ITEM.ClassName
= name
local dir
= "items/"..folder
.."/"
if SERVER
then
if file.
Exists(dir
.."shared.lua",
"LUA")
then
AddCSLuaFile(dir
.."shared.lua")
end
if file.
Exists(dir
.."cl_init.lua",
"LUA")
then
AddCSLuaFile(dir
.."cl_init.lua")
end
if file.
Exists(dir
.."init.lua",
"LUA")
then
include(dir
.."init.lua")
end
end
if file.
Exists(dir
.."shared.lua",
"LUA")
then
include(dir
.."shared.lua")
end
if CLIENT
then
if file.
Exists(dir
.."cl_init.lua",
"LUA")
then
include(dir
.."cl_init.lua")
end
end
if not ITEM.Base
then ITEM.Base
= "item_baseitem" end
invitem.
Register(name,ITEM)
ITEM
= nil
end
for classname,classtbl
in pairs(
invitem.
GetClasses())
do
table.
Inherit(classtbl,classtbl.BaseClass)
end
Bununla birlikte, öğeleriniz otomatik olarak dahil edilmeli, kaydedilmeli ve miras alınmalıdır.
Bu sistemin çalışan bir örneğini buradan indirebilirsiniz. Kod test edilmemiştir ancak çalışması gerekir.
--[[Kullanıcı:Bobblehead|Bobblehead]] 00:01, 13 Aralık 2014 (UTC)
Metatablolar, davranış biçimleri sayesinde nesne yönelimli programlamayı simüle etmek için kullanışlı bir araçtır.
Aynı metatabloya sahip nesneler, aynı metayöntemlere ve özel fonksiyonlara erişebilir.
Metatablomuzu oluşturarak başlayalım
Book = {}
Book.__index = Book
Şimdi, nesnemizi döndürecek ve genellikle "new" olarak adlandırılan bir fonksiyona ihtiyacımız var
Book
= {}
Book.__index
= Book
function Book:
new( series, seriesNum, title, text )
local EmptyBook
= {
series
= series
or "",
seriesNum
= seriesNum
or 0,
title
= title
or "",
text
= text
or "",
}
setmetatable( EmptyBook, Book )
return EmptyBook
end
Şimdi temelimizi kurduğumuza göre, birkaç fonksiyon ekleyelim
function Book:
Print()
if self:
IsEmpty()
then return end
print(
"\n====================================" )
if self.seriesNum
> 0 then
print( self.series
.. " " .. self.seriesNum
.. ": " .. self.title
.. "\n" )
else
print( self.title
.. "\n" )
end
print( self.text )
print(
"====================================\n")
end
function Book:
IsEmpty()
return #self.text
== 0
end
function Book:
SetSeries( series )
self.series
= series
end
function Book:
GetSeries()
return self.series
end
function Book:
SetSeriesNum( num )
self.seriesNum
= num
end
function Book:
GetSeriesNum()
return self.seriesNum
end
function Book:
SetTitle( title )
self.title
= title
end
function Book:
GetTitle()
return self.title
end
function Book:
AddText( text )
self.text
= self.text
.. text
end
function Book:
AddLine()
self.text
= self.text
.. "\n"
end
function Book:
RemoveLine()
if self:
IsEmpty()
then return end
local index
= string.
find( self.text,
"\n" )
if not index
then self.text
= "" return end
local lastIndex
= index
while index
do
lastIndex
= index
index
= string.
find( self.text,
"\n", index
+1 )
end
self.text
= string.
sub( self.text,
1, lastIndex
-1 )
end
Son olarak, biraz metasi-hirbazlık kullanarak Book:new() ile aynı olan bir Book() fonksiyonu yapacağız
Yeni simüle edilmiş sınıfımızı - Kitap! - başarıyla oluşturduk.
Book
= {}
Book.__index
= Book
function Book:
new( series, seriesNum, title, text )
local EmptyBook
= {
series
= series
or "",
seriesNum
= seriesNum
or 0,
title
= title
or "",
text
= text
or "",
}
setmetatable( EmptyBook, Book )
return EmptyBook
end
function Book:
Print()
if self:
IsEmpty()
then return end
print(
"\n====================================" )
if self.seriesNum
> 0 then
print( self.series
.. " " .. self.seriesNum
.. ": " .. self.title
.. "\n" )
else
print( self.title
.. "\n" )
end
print( self.text )
print(
"====================================\n")
end
function Book:
IsEmpty()
return #self.text
== 0
end
function Book:
SetSeries( series )
self.series
= series
end
function Book:
GetSeries()
return self.series
end
function Book:
SetSeriesNum( num )
self.seriesNum
= num
end
function Book:
GetSeriesNum()
return self.seriesNum
end
function Book:
SetTitle( title )
self.title
= title
end
function Book:
GetTitle()
return self.title
end
function Book:
AddText( text )
self.text
= self.text
.. text
end
function Book:
AddLine()
self.text
= self.text
.. "\n"
end
function Book:
RemoveLine()
if self:
IsEmpty()
then return end
local index
= string.
find( self.text,
"\n" )
if not index
then self.text
= "" return end
local lastIndex
= index
while index
do
lastIndex
= index
index
= string.
find( self.text,
"\n", index
+1 )
end
self.text
= string.
sub( self.text,
1, lastIndex
-1 )
end
setmetatable( Book,
{__call
= Book.new
} )
İşte Kitap sınıfını kullanan bir örnek kod
local myBook
= Book()
myBook:
SetSeries(
"My First Series" )
myBook:
SetSeriesNum(
1 )
myBook:
SetTitle(
"My First Book" )
myBook:
AddText(
"This is my very first book.\nThe End" )
myBook:
Print()
local myBook2
= Book(
"My First Series",
2,
"My Second Book",
"This is my second book.\nIt's a bit longer than the first one" )
myBook2:
Print()
myBook:
RemoveLine()
myBook:
AddLine()
myBook:
AddText(
"I changed it a bit" )
myBook:
AddLine()
myBook:
AddText(
"The End" )
myBook:
SetSeries(
"" )
myBook:
SetSeriesNum(
0 )
myBook:
Print()
Çıktı:
