Ön Gereksinimler
- Lua bilgisi.
- Bir eşya sistemi. Her eşyanın iki fonksiyonu olmalıdır:
- ITEM:GetIcon() -- Bir Material() nesnesi döndürmelidir.
- ITEM:GetSize() -- Hücre cinsinden bir genişlik ve yükseklik döndürmelidir.
Buna benzer bir sistem, Nesne Yönelimli Lua eğitiminde bulunabilir.
Unutmayın ki bu eğitim sadece envanterin istemci tarafı (clientside) yönetimini ele almaktadır.
Sunucu tarafı (serverside) ağ iletişimi için fazla tembelim...
Hadi Başlayalım
Yani her eşyanın sırt çantasında bir konumu ve o sırt çantasında bir boyutu vardır.
Başlamak için bir tabloya (table) ihtiyacınız olacak.
Buna ply.Inv diyeceğiz.
ply.Inv hem sırt çantasını hem de envanter hakkındaki bilgileri içerecektir.
ply.Inv içinde birkaç alt tablo ve değer oluşturalım.
ply.Inv.Backpack = {}
ply.Inv.Equipped = {}
ply.Inv.Weight = 0
(Sisteminiz için ihtiyaç duyacağınız her türlü değeri oluşturabilirsiniz. Ağırlık gerekli olmayabilir, vb.)
Sırada, sırt çantası tablosunu 2 boyutlu bir tablo haline getireceğiz; satırlar ilk anahtar olacak ve her satır sütunları içerecek. Bu şuna benzer bir şey olacaktır:
for i
=1,
8 do
ply.Inv.Backpack
[i
] = {}
end
for k,v
in pairs(ply.Inv.Backpack)
do
for i
=1,
4 do
ply.Inv.Backpack
[k
][i
] = false
end
end
Bu, 8 genişliğinde, 4 yüksekliğinde 2 boyutlu bir tablo oluşturacaktır.
Yani 2,4 koordinatındaki eşyayı almak için ply.Inv.Backpack[2][4] yapmanız gerekir.
Oldukça basit.
Ancak bir kolaylık fonksiyonuyla her zaman daha basittir:
local plymeta
= FindMetaTable(
"Player")
function plymeta:
GetInvItem(x,y)
return self.Inv.Backpack
[x
][y
]
end
Tamam, şimdi sistemin temelini açıklayalım.
Fikir şu:
Yeni bir VGUI elemanı oluşturacağız. Bu eleman, ızgaradaki (grid) tek bir kare olacak. Bu sayede parlamalarını falan sağlayabiliriz. Bu elemanı tasarlamayı bitirdiğimizde, daha önce ayarladığımız false değerlerini değiştirebiliriz.
Bir eşyayı ızgarada bir yere koyduğumuzda, eşyanın boyutunu (genişlik ve yükseklik) alırız. Ardından o alandaki tüm karelere, artık üzerlerinde bir eşya olduğunu söyleriz. Eşyayı tüm karelere köklemeyeceğiz; sadece eşyanın sol üstünde bulunan kareye kökleyeceğiz. Diğer tüm karelere haber veren kareye. Bu, eşyanın ebeveyn (parent) karesi olacak.
Öyleyse bu ızgara elemanlarını yapalım.
local PANEL
= {}
AccessorFunc(PANEL,
"m_ItemPanel",
"ItemPanel")
AccessorFunc(PANEL,
"m_Color",
"Color")
function PANEL:
Init()
self.m_Coords
= {x
=0,y
=0}
self:
SetSize(
30,
30)
self:
SetColor(
Color(
200,
200,
200))
self:
SetItemPanel(
false)
self:
Receiver(
"invitem",
function(pnl, item, drop, i, x, y)
if drop
then
item
= item
[1]
local x1,y1
= pnl:
GetPos()
local x2,y2
= item:
GetPos()
if math.
Dist(x1,y1,x2,y2)
<= 30 then
if not pnl:
GetItemPanel()
then
local itm
= item:
GetItem()
local x,y
= pnl:
GetCoords()
local itmw, itmh
= itm:
GetSize()
local full
= false
for i1
=x, (x
+itmw)
-1 do
if full
then break end
for i2
=y, (y
+itmh)
-1 do
if LocalPlayer():
GetInvItem(i1,i2):
GetItemPanel()
then
full
= true
break
end
end
end
if not full
then
for i1
=x, (x
+itmw)
-1 do
for i2
=y, (y
+itmh)
-1 do
LocalPlayer():
GetInvItem(i1,i2):
SetItemPanel(item)
end
end
item:
SetRoot(pnl)
item:
SetPos(
pnl:
GetPos())
end
end
end
else
end
end,
{})
end
function PANEL:
SetCoords(x,y)
self.m_Coords.x
= x
self.m_Coords.y
= y
end
function PANEL:
GetCoords()
return self.m_Coords.x, self.m_Coords.y
end
local col
function PANEL:
Paint(w,h)
draw.
NoTexture()
col
= self:
GetColor()
surface.
SetDrawColor(col.r,col.g,col.b,
255)
surface.
DrawRect(
0,
0,w
-2,h
-2)
surface.
SetDrawColor(
70,
70,
70,
255)
surface.
DrawRect(w
-2,
0,h,
2)
surface.
DrawRect(
0,h
-2,
2,w)
end
vgui.
Register(
"InvSlot", PANEL,
"DPanel")
Bitti. Şimdi tüm işlevselliği ekliyoruz.
Eşya sisteminin, her bir eşyayı tanımlamak için sadece rastgele sınıf ID'leri değil, benzersiz eşyalar içerdiğini varsaymalıyız.
Bunu yapmanın en iyi yolu, her eşyayı bir entity index'i ile ilişkilendirmektir. Bu, eğer eşyaların hepsi bir noktada entity ise işe yarar.
Bir eşyayı aldığınızda, entity versiyonunu kaldırır (entity index'ini kaydederek) ve bıraktığınızda, aynı türde ve aynı bilgilerle yeni bir entity oluşturur.
Bunların hepsi sadece bir konsept. Bu eğitimde bir eşya sistemi yazmıyorum.
Yani her envanter yuvası için bir yuva paneli oluşturarak başlayacağız.
for k,v
in pairs(ply.Inv.Backpack)
do
for i
=1,
4 do
ply.Inv.Backpack
[k
][i
] = vgui.
Create(
"InvSlot")
ply.Inv.Backpack
[k
][i
]:
SetPos(k
*30,i
*30)
ply.Inv.Backpack
[k
][i
]:
SetCoords(k,i)
end
end
İkonlar. Her yerde ikonlar var.
Sırada, başka bir VGUI elemanı yapalım. Bu, sırt çantanızdaki bir eşyayı temsil edecek.
local PANEL
= {}
AccessorFunc(PANEL,
"m_Item",
"Item")
AccessorFunc(PANEL,
"m_Root",
"Root")
function PANEL:
Init()
self:
SetSize(
30,
30)
self:
SetItem(
false)
self:
SetColor(
Color(
100,
100,
100))
self:
SetDroppable(
"invitem")
end
function PANEL:
PaintOver(w,h)
draw.
NoTexture()
if self:
GetItem()
then
surface.
SetMaterial(
self:
GetItem():
GetIcon())
surface.
DrawTexturedRect(
0,
0,w,h)
end
end
local col
function PANEL:
Paint(w,h)
draw.
NoTexture()
col
= self:
GetColor()
surface.
SetDrawColor(col.r,col.g,col.b,
180)
surface.
DrawRect(
0,
0,w,h)
end
vgui.
Register(
"InvItem", PANEL,
"DPanel")
Tamam, şimdi asıl eşyalara sahibiz.
Unutmayın, sadece bir sırt çantası sisteminin temellerini tartışıyoruz. İsterseniz daha sonra daha fazlasını ekleyebilirsiniz.
Sırada, belirli bir eşya için sırt çantasında yer olup olmadığını bulan bir fonksiyon oluşturalım.
Eğer yer varsa, köklenecek paneli döndürecek. Yoksa, false döndürecek.
function IsRoomFor(item)
for k,v
in ipairs(
LocalPlayer().Inv.Backpack)
do
for k2, pnl
in ipairs(
LocalPlayer().Inv.Backpack
[k
])
do
if not pnl:
GetItemPanel()
then
local x,y
= pnl:
GetCoords()
local itmw, itmh
= item:
GetSize()
local full
= false
for i1
=x, (x
+itmw)
-1 do
if full
then break end
for i2
=y, (y
+itmh)
-1 do
if LocalPlayer():
GetInvItem(i1,i2):
GetItemPanel()
then
full
= true
break
end
end
end
if full
then
return pnl
end
end
end
end
return false
end
Bu kodun çoğu, daha önceki sürükle-bırak işlevselliğinden kopyalanmıştır.
Sırada, eşyaların yerden alınmasını sağlayalım.
function PickupItem(item)
local place
= IsRoomFor(item)
if place
then
local itm
= vgui.
Create(
"InvItem")
itm:
SetItem(item)
itm:
SetRoot(place)
itm:
SetPos(
place:
GetPos())
local x,y
= place:
GetCoords()
local itmw, itmh
= item:
GetSize()
for i1
=x, (x
+itmw)
-1 do
for i2
=y, (y
+itmh)
-1 do
LocalPlayer():
GetInvItem(i1,i2):
SetItemPanel(itm)
end
end
return true
else
return false
end
end Son Ürün
local ply
= LocalPlayer()
ply.Inv
= {}
ply.Inv.Backpack
= {}
ply.Inv.Equipped
= {}
ply.Inv.Weight
= 0
for i
=1,
8 do
ply.Inv.Backpack
[i
] = {}
end
for k,v
in pairs(ply.Inv.Backpack)
do
for i
=1,
4 do
ply.Inv.Backpack
[k
][i
] = false
end
end
local plymeta
= FindMetaTable(
"Player")
function plymeta:
GetInvItem(x,y)
return self.Inv.Backpack
[x
][y
]
end
local PANEL
= {}
AccessorFunc(PANEL,
"m_ItemPanel",
"ItemPanel")
AccessorFunc(PANEL,
"m_Color",
"Color")
function PANEL:
Init()
self.m_Coords
= {x
=0,y
=0}
self:
SetSize(
30,
30)
self:
SetColor(
Color(
200,
200,
200))
self:
SetItemPanel(
false)
self:
Receiver(
"invitem",
function(pnl, item, drop, i, x, y)
if drop
then
item
= item
[1]
local x1,y1
= pnl:
GetPos()
local x2,y2
= item:
GetPos()
if math.
Dist(x1,y1,x2,y2)
<= 30 then
if not pnl:
GetItemPanel()
then
local itm
= item:
GetItem()
local x,y
= pnl:
GetCoords()
local itmw, itmh
= itm:
GetSize()
local full
= false
for i1
=x, (x
+itmw)
-1 do
if full
then break end
for i2
=y, (y
+itmh)
-1 do
if LocalPlayer():
GetInvItem(i1,i2):
GetItemPanel()
then
full
= true
break
end
end
end
if not full
then
for i1
=x, (x
+itmw)
-1 do
for i2
=y, (y
+itmh)
-1 do
LocalPlayer():
GetInvItem(i1,i2):
SetItemPanel(item)
end
end
item:
SetRoot(pnl)
item:
SetPos(
pnl:
GetPos())
end
end
end
else
end
end,
{})
end
function PANEL:
SetCoords(x,y)
self.m_Coords.x
= x
self.m_Coords.y
= y
end
function PANEL:
GetCoords()
return self.m_Coords.x, self.m_Coords.y
end
local col
function PANEL:
Paint(w,h)
draw.
NoTexture()
col
= self:
GetColor()
surface.
SetDrawColor(col.r,col.g,col.b,
255)
surface.
DrawRect(
0,
0,w
-2,h
-2)
surface.
SetDrawColor(
70,
70,
70,
255)
surface.
DrawRect(w
-2,
0,
2,h)
surface.
DrawRect(
0,h
-2,w,
2)
end
vgui.
Register(
"InvSlot", PANEL,
"DPanel")
local dfram
= vgui.
Create(
"DFrame")
dfram:
SetSize(
ScrW()
/2,
ScrH()
/2)
dfram:
Center()
dfram:
MakePopup()
for k,v
in pairs(ply.Inv.Backpack)
do
for i
=1,
4 do
ply.Inv.Backpack
[k
][i
] = vgui.
Create(
"InvSlot", dfram)
ply.Inv.Backpack
[k
][i
]:
SetPos((k
*30)
+100,(i
*30)
+100)
ply.Inv.Backpack
[k
][i
]:
SetCoords(k,i)
end
end
PANEL
= {}
AccessorFunc(PANEL,
"m_Item",
"Item")
AccessorFunc(PANEL,
"m_Root",
"Root")
function PANEL:
Init()
self:
SetSize(
30,
30)
self:
SetItem(
false)
self:
SetColor(
Color(
100,
100,
100))
self:
SetDroppable(
"invitem")
end
function PANEL:
PaintOver(w,h)
draw.
NoTexture()
if self:
GetItem()
then
surface.
SetMaterial(
self:
GetItem():
GetIcon())
surface.
DrawTexturedRect(
0,
0,w,h)
end
end
local col
function PANEL:
Paint(w,h)
draw.
NoTexture()
col
= self:
GetColor()
surface.
SetDrawColor(col.r,col.g,col.b,
180)
surface.
DrawRect(
0,
0,w,h)
end
vgui.
Register(
"InvItem", PANEL,
"DPanel")
function IsRoomFor(item)
for k,v
in ipairs(
LocalPlayer().Inv.Backpack)
do
for k2, pnl
in ipairs(
LocalPlayer().Inv.Backpack
[k
])
do
if not pnl:
GetItemPanel()
then
local x,y
= pnl:
GetCoords()
local itmw, itmh
= item:
GetSize()
local full
= false
for i1
=x, (x
+itmw)
-1 do
if full
then break end
for i2
=y, (y
+itmh)
-1 do
if LocalPlayer():
GetInvItem(i1,i2):
GetItemPanel()
then
full
= true
break
end
end
end
if full
then
return pnl
end
end
end
end
return false
end
function PickupItem(item)
local place
= IsRoomFor(item)
if place
then
local itm
= vgui.
Create(
"InvItem")
itm:
SetItem(item)
itm:
SetRoot(place)
itm:
SetPos(
place:
GetPos())
local x,y
= place:
GetCoords()
local itmw, itmh
= item:
GetSize()
for i1
=x, (x
+itmw)
-1 do
for i2
=y, (y
+itmh)
-1 do
LocalPlayer():
GetInvItem(i1,i2):
SetItemPanel(itm)
end
end
return true
else
return false
end
end Test Sonuçları
