# Nesne Yönelimli Lua

- **İngilizce aslı:** https://wiki.facepunch.com/gmod/Object_Oriented_Lua
- **Çeviri tarihi:** 2025-09-08

## 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. ![](https://gmod.tr/api/uploads/wiki/07c66e382a01ddfb28e2.png)

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](https://gmod.tr/wiki/ents.Create), [vgui.Create](https://gmod.tr/wiki/vgui.Create) ve [Vector](https://gmod.tr/wiki/Global.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).

```lua
--Sınıfımızı tanımlayalım. Havaalanı nesneleri oluşturacağız.
--Yapılan tüm yeni havaalanı nesnelerinin gerekli bazı özelliklerinin varsayılanlarını önceden ayarlayacağız.
local AirportClass = {}
AirportClass.Name = "Airport"
AirportClass.Code = "ABC"
AirportClass.City = "Cityville"
AirportClass.State = "CA"

--[[Şimdi, havaalanı nesnelerimizi türeteceğimiz, var olmayan bir havaalanını temsil eden temel bir tablomuz var.
Havaalanı nesneleri oluşturmaya başlayabilmemiz için bir yapıcı (constructor) oluşturalım. Temel bir yapıcı aşağıdaki gibidir:]]
function Airport(code) --Kod isteğe bağlı bir argümandır.

	local newAirport = table.Copy(AirportClass)
	--table.Copy bir Garry's Mod fonksiyonudur. Farklı bir API'de çoğaltmanız gerekirse kaynak koduna bakın.

	--Değiştirecek yeni bir kodumuz varsa, eski varsayılan Kod özelliğini geçersiz kılın:
	if code then
		newAirport.Code = code
	end

	--Yeni Nesnemizi döndür.
	return newAirport

end

--Şimdi bazı Havaalanı nesneleri oluşturmaya hazırız! Birkaç tane tanımlayarak başlayalım...
local BWI = Airport("BWI")
local LAX = Airport("LAX")
local ORD = Airport("ORD")

--Tamam, şimdi varlar.
--AMA BEKLEYİN! Yeni havaalanlarımız orijinal BaseAirport sınıfıyla aynı!
--Bu kabul edilemez. Haydi havaalanlarımızın özelliklerini değiştirelim.
BWI.Name = "Thurgood Marshall"
BWI.City = "Baltimore"
BWI.State = "MD"

LAX.Name = "Los Angeles International Airport"
LAX.City = "Los Angeles"
-- LAX.State = "CA"
-- Eyalet varsayılan olarak "CA" olduğu için burada değiştirmemize gerek yok.

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:

1. İçine sınıfın tanımlanacağı bir tablo oluşturun.
2. Dosyaları çalıştırın.
3. Sınıf tablosunu ileride kullanmak üzere bir yere kaydedin.
4. O sınıfa ait mevcut nesneleri yenileyin. (Bunu eğitimimizde yapmayacağız.)
5. 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:

```lua
local string = string
local table = table
local error = error
local Material = Material
local baseclass = baseclass

module("invitem")

--Tüm envanter öğelerinin bir listesini oluşturun.
local invitems = invitems or {}
local allitems = allitems or {}

--Tüm öğelerin bir şekilde temel aldığı kök temel sınıfımızı (baseclass) oluşturun.
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 --Bunu nesneyi oluşturduğumuzda ayarlarız.
function invitems.item_baseitem:Init()

end
function invitems.item_baseitem:Remove()
	allitems[self.id] = nil
	self:OnRemove()
end
function invitems.item_baseitem:OnRemove()
	--Bu, sınıf başına geçersiz kılabileceğimiz fonksiyondur.
end
-- Bu iki fonksiyon, bu sistemin uyumlu olduğu Izgara Tabanlı Envanter Eğitimi içindir.
function invitems.item_baseitem:GetSize()
	return self.Width, self.Height
end
function invitems.item_baseitem:GetIcon()
	return self.Icon
end
--baseclass.Set bir GMod fonksiyonudur. lua/includes/modules/baseclass.lua dosyasına bakın.
baseclass.Set("item_baseitem", invitems.item_baseitem)

--Bir sınıfı dahili öğe listemize kaydeder ve sınıfımızın temel sınıfını (baseclass) tanımlar.
function Register(classtbl, name)

	name = string.lower(name)

	baseclass.Set( name, classtbl )

	classtbl.BaseClass = baseclass.Get(classtbl.Base)

	invitems[ name ] = classtbl

end

--Sınıfı belirlemek için bir argüman alan yapıcımız (constructor).
function Create(class)
	--Var olmayan sınıfların oluşturulmasını önleyin.
	if not invitems[class] then error("Tried to create new inventory item from non-existant class: "..class) end

	local newItem = table.Copy(invitems[class])

	--Yeni nesnemizi oyundaki mevcut tüm öğelerin listesine ekleyin.
	local id = table.insert(allitems, newItem)
	--Ona benzersiz bir ID verin.
	newItem.UniqueID = id

	--Yeni öğeyi oluşturduğumuzda Init fonksiyonumuzu çağırın.
	newItem:Init()

	return newItem
end

--Tüm sınıfların bir tablosunu döndürür.
function GetClasses()
	return invitems
end

--Kaydedilmiş listemizden belirli bir sınıfın sınıf tablosunu döndürür.
function GetClassTable(classname)
	return invitems[classname]
end

--Sınıf tablosunun bir KOPYASINI döndürür, böylece orijinalini değiştirmeyiz.
function GetClassTableCopy(classname)
	return table.Copy(invitems[classname])
end

--Mevcut tüm öğe nesnelerinin bir listesini döndürür.
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:

```lua
if SERVER then
	AddCSLuaFile()--Sadece Garry's Mod'da gereklidir.
	AddCSLuaFile("../includes/modules/invitem.lua")
end

--Modülümüzü çalıştırın:
require("invitem")

--Sınıf dosyalarımızı çalıştıralım:

--Sınıflar klasörümüzdeki tüm dosya ve klasörlerin bir listesini alın.
--file.Find bir Garry's Mod fonksiyonudur. Yeniden yapmak isterseniz wiki'ye bakın.
local files,folders = file.Find("items/*", "LUA") --Dosyalarımızı lua/items/ içinde saklayın

--"item_dildo.lua" gibi tek başına bulunan dosyaları paylaşılan olarak kabul edin.
for k,File in pairs(files)do

	local name = string.sub(File,1,string.find(File,"%.lua")-1)

	--Dosyaların içine yazdığı sınıf tablomuzu oluşturun.
	ITEM = {}

	--Gelecekte başvurmak üzere ClassName'imizi ayarlayın.
	ITEM.ClassName = name

	if SERVER then
		AddCSLuaFile("items/"..File)
	end
	include("items/"..File)

	if not ITEM.Base then ITEM.Base = "item_baseitem" end

	--Sınıf tablosunu kaydedin.
	invitem.Register(name,ITEM)

	--Sınıf tablosunu silin.
	ITEM = nil
end

--Her dosyayı, ör. init.lua, shared.lua ve cl_init.lua, kendi alanlarında dahil edin.
for k,folder in pairs(folders)do

	local name = string.sub(folder,1,string.find(folder,"%.lua")-1)

	--Dosyaların içine yazdığı sınıf tablomuzu oluşturun.
	ITEM = {}

	--Gelecekte başvurmak üzere ClassName'imizi ayarlayın.
	ITEM.ClassName = name

	--Bu öğe için tüm dosyalarımızı dahil edin.
	local dir = "items/"..folder.."/"
	if SERVER then
		--file.Exists bir Garry's Mod fonksiyonudur. Yeniden yapmak isterseniz wiki'ye bakın.
		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

	--Sınıf tablosunu kaydedin.
	invitem.Register(name,ITEM)

	--Sınıf tablosunu silin.
	ITEM = nil
end

--Tüm sınıf dosyalarımızı dahil ettiğimize göre, şimdi temel sınıflarını (baseclass) miras almalarını sağlayalım.
for classname,classtbl in pairs(invitem.GetClasses())do

	--table.Inherit bir tablodaki nil değerlerini başka bir tablodaki nil olmayan değerlerle değiştirir. lua/includes/extensions/table.lua dosyasına bakın.
	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](https://www.dropbox.com/s/cn1w46q6oxmp05u/inventory.zip?dl=1) indirebilirsiniz. Kod test edilmemiştir ancak çalışması gerekir.

--[[Kullanıcı:Bobblehead|Bobblehead]] 00:01, 13 Aralık 2014 (UTC)

### Yöntem 2: Metatablolar

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

```lua
Book = {} -- Bu bizim metatablomuzdur. "Sınıfımızı" temsil edecektir
Book.__index = Book
--Eğer bir anahtar tabloda bulunamazsa, metatablosunun __index'ine bakacaktır.
--Bu, 'Book' tablosu için tanımladığımız herhangi bir fonksiyonun, metatablosu 'Book' olan herhangi bir nesne tarafından erişilebilir olacağı anlamına gelir
```

Şimdi, nesnemizi döndürecek ve genellikle "new" olarak adlandırılan bir fonksiyona ihtiyacımız var

```lua
Book = {} -- Bu bizim metatablomuzdur. "Sınıfımızı" temsil edecektir
Book.__index = Book

function Book:new( series, seriesNum, title, text ) -- Değişkenler isteğe bağlıdır
	-- Bu, döndüreceğimiz tablodur
	local EmptyBook = {
		series = series or "",
		seriesNum = seriesNum or 0,
		title = title or "",
		text = text or "",
	}

	setmetatable( EmptyBook, Book ) -- 'EmptyBook'un metatablosunu 'Book' olarak ayarla
	return EmptyBook -- Metatablosu 'Book' olan 'EmptyBook' tablosunu döndür. Bu bizim nesnemizdir

	--[[
	Çoğu zaman, tablo fonksiyonun kendi içinde şu şekilde ayarlanacaktır:

	return setmetatable( {
		series = series or "",
		seriesNum = seriesNum or 0,
		title = title or "",
		text = text or "",
	}, Book )
	]]
end
```

Şimdi temelimizi kurduğumuza göre, birkaç fonksiyon ekleyelim

```lua
-- İlk olarak, Kitabımızı yazdırmak için bir fonksiyon
function Book:Print()
	if self:IsEmpty() then return end -- Boş bir kitabı yazdırmanın bir anlamı yok

	print( "\n====================================" ) -- Yazdırma işlemimizin ne zaman başladığını netleştirelim
	if self.seriesNum > 0 then -- Seri adını yalnızca bir serinin parçasıysa yazdır (Ve dolayısıyla seriesNum > 0)
		print( self.series .. " " .. self.seriesNum .. ": " .. self.title .. "\n" ) -- Güzel format
	else
		print( self.title .. "\n" ) -- Aksi takdirde, sadece başlığı yazdırabiliriz
	end
	print( self.text ) -- Ve tabii ki, metni yazdır
	print( "====================================\n") -- Yazdırma işlemimizin ne zaman bittiğini netleştirelim
end

-- Şimdi birkaç fonksiyon daha tanımlayacağız, bunlar sadece benim yapmak istediğim fonksiyonlar
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

-- Metnin son satırını kaldır
function Book:RemoveLine()
	if self:IsEmpty() then return end -- Metin yoksa bir satır silemezsiniz

	local index = string.find( self.text, "\n" )
	if not index then self.text = "" return end -- Yalnızca 1 satır varsa, metni boş olarak ayarlayın

	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

```lua
setmetatable( Book, {__call = Book.new } )
```

Yeni simüle edilmiş sınıfımızı - Kitap! - başarıyla oluşturduk.

```lua
Book = {} -- Bu bizim metatablomuzdur. "Sınıfımızı" temsil edecektir
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 -- Boş bir kitabı yazdırmanın bir anlamı yok

	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

```lua
-- Seçenek #1: Boş bir kitap oluşturun, ardından verilerini tanımladığımız metafonksiyonlarla ayarlayın
local myBook = Book()
myBook:SetSeries( "My First Series" )
myBook:SetSeriesNum( 1 ) -- Serinin ilk kitabı
myBook:SetTitle( "My First Book" )
myBook:AddText( "This is my very first book.\nThe End" )
myBook:Print()

-- Seçenek #2: Tüm (veya bazı) verileriyle yeni bir kitap oluşturun
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ı**:

![](https://gmod.tr/api/uploads/wiki/d4b134f21cdfefd5e695.png)

- [GMod Wiki ana sayfası](https://gmod.tr/wiki)

---

[Tüm sunucular](https://gmod.tr/) · [GmodTR Launcher](https://gmod.tr/launcher) · [Rehber](https://gmod.tr/rehber) · [GMod Wiki](https://gmod.tr/wiki) · [GmodTR nedir?](https://gmod.tr/hakkinda) · [Sunucu ekle](https://gmod.tr/sunucu-ekle) · [Discord](https://discord.gg/gmodtr)

Kaynak: https://gmod.tr/wiki/Object_Oriented_Lua
