Bloga Geri Dön
Tutorial10 dk. okuma

FiveM Dövme ve Berber Sistemi: Özelleştirme Scriptleri

FiveM şehrinize dövme salonları ve berberler ekleyin. Kamera açıları, arayüzler, randevu akışı ve roleplay için en iyi özelleştirme scriptleri.

Agency Scripts

Agency Scripts Kurucusu ve Baş Geliştiricisi

Ped Görünüm Bileşenlerini Anlamak

FiveM'de bir dövme ve berber dükkanı sistemi geliştirmek, GTA V'in ped (karakter) görünümünü nasıl işlediğine dair sağlam bir anlayış gerektirir. Görünüm sistemi birkaç bileşen kategorisine ayrılmıştır: Lekeler, sakal/bıyık, kaşlar ve makyaj gibi özellikler için head overlays, kıyafet ve saç stilleri için drawable components ve ped modelinin üzerine katmanlanan dövme dekorasyonları. Her bileşen türü farklı native fonksiyonlar kullanır ve kendi indeksleme sistemini takip eder. Head overlays: lekeler (0), sakal/bıyık (1), kaşlar (2), yaşlanma (3), makyaj (4), allık (5) ve ruj (8) gibi özellikleri kontrol etmek için 0-12 arası indeksleri kullanır. Saç stilleri, baş saçı için indeks 2'deki drawable component sistemi üzerinden ayarlanır. Dövmeler, koleksiyon adları ve hash değerleri içeren tamamen ayrı bir dekorasyon sistemi kullanır. UI'ı oluşturmadan önce, erkek ve kadın karakterlerin farklı stil setlerine sahip olması nedeniyle, mevcut ped modeli için geçerli varyasyon sayısı da dahil olmak üzere her bileşen için mevcut tüm seçenekleri haritalandırmanız gerekir. Kullanın GetNumHeadOverlayValues(overlayIndex) çalışma zamanında her overlay türü için kaç seçeneğin bulunduğunu sorgulamak için.

Karakter Önizlemesi İçin Kamera Sistemi

Harika bir berber ve dövme deneyimi, oyuncunun seçtiği şeyi gerçek zamanlı olarak görebilmesine bağlıdır. Oyuncu seçenekler arasında gezinirken ilgili vücut bölümüne odaklanan özel bir kamera sistemi oluşturun. Saç düzenlerken kamerayı kafaya yakınlaştırın. Gövde için dövme seçerken üst vücudu göstermek için kamerayı geriye çekin. Bacak dövmeleri üzerinde çalışırken kamerayı alt gövdeyi çerçeveleyecek şekilde konumlandırın. Oyuncu kategoriler arasında geçiş yaparken bakış açıları arasında yumuşak geçişler oluşturmak için scripted kamera native'lerini kullanın. İşte birden fazla yakınlaştırma seviyesini ve vücut odak alanını yöneten bir kamera yönetim sistemi:

local customCam = nil
local camActive = false

local CameraPresets = {
    head = {offset = vector3(0.0, 0.65, 0.65), fov = 35.0},
    face = {offset = vector3(0.0, 0.45, 0.62), fov = 25.0},
    torso = {offset = vector3(0.0, 1.2, 0.2), fov = 45.0},
    legs = {offset = vector3(0.0, 1.5, -0.5), fov = 50.0},
    full = {offset = vector3(0.0, 2.5, 0.2), fov = 50.0},
}

function SetupPreviewCamera(preset)
    local ped = PlayerPedId()
    local pedCoords = GetEntityCoords(ped)
    local pedHeading = GetEntityHeading(ped)
    local headingRad = math.rad(pedHeading)

    local cam = CameraPresets[preset] or CameraPresets.full
    local camX = pedCoords.x + cam.offset.y * math.sin(-headingRad)
    local camY = pedCoords.y + cam.offset.y * math.cos(-headingRad)
    local camZ = pedCoords.z + cam.offset.z

    if customCam then
        local newCam = CreateCam('DEFAULT_SCRIPTED_CAMERA', true)
        SetCamCoord(newCam, camX, camY, camZ)
        PointCamAtCoord(newCam, pedCoords.x, pedCoords.y, pedCoords.z + cam.offset.z)
        SetCamFov(newCam, cam.fov)
        SetCamActiveWithInterp(newCam, customCam, 800, 1, 1)

        Wait(800)
        DestroyCam(customCam, false)
        customCam = newCam
    else
        customCam = CreateCam('DEFAULT_SCRIPTED_CAMERA', true)
        SetCamCoord(customCam, camX, camY, camZ)
        PointCamAtCoord(customCam, pedCoords.x, pedCoords.y, pedCoords.z + cam.offset.z)
        SetCamFov(customCam, cam.fov)
        SetCamActive(customCam, true)
        RenderScriptCams(true, true, 500, true, false)
    end
    camActive = true
end

function DestroyPreviewCamera()
    if customCam then
        RenderScriptCams(false, true, 500, true, false)
        DestroyCam(customCam, false)
        customCam = nil
        camActive = false
    end
end

Oyuncuların değişiklikleri önizlerken karakterlerini döndürebilmeleri için fare veya analog çubuk döndürme desteği ekleyin. NUI fare hareketini kullanmadığında hareketi yakalayın ve oyuncu ped'ine heading rotasyonu olarak uygulayın. Bu, oyuncuların satın almadan önce dövmelerini birden fazla açıdan incelemelerini sağlar ve alışveriş deneyimini önemli ölçüde iyileştirir. Özelleştirme oturumu sırasında oyuncu ped'ini sabitleyin ve oyuncu gezinirken karakterin doğal görünmesini sağlamak için idle animasyonu oynatın.

Saç ve Sakal Özelleştirmesi

Saç ve sakal özelleştirmesi sırasıyla drawable component ve head overlay sistemlerini kullanır. Saç stilleri şununla ayarlanır: SetPedComponentVariation bileşen indeksi 2 (saç) ve indeks 1 (doku/renk varyasyonu) kullanılarak. Saç rengi şununla ayrı olarak uygulanır: SetPedHairColor birincil renk dizini ve vurgu rengi dizini alır. Sakal stilleri, yüzdeki kılların ne kadar kalın veya ince görüneceğini kontrol eden bir opaklık değeriyle dizin 1'deki head overlay sistemini kullanır. Oyuncu seçeneklere tıkladıkça ped modelini gerçek zamanlı güncelleyerek mevcut her stil için küçük resimler veya adlar gösterecek şekilde NUI oluşturun. Gerçek zamanlı önizleme ile saç ve sakal değişikliklerini uygulamaya yönelik Lua mantığı şöyledir:

function ApplyHairStyle(ped, styleIndex, textureIndex, primaryColor, highlightColor)
    SetPedComponentVariation(ped, 2, styleIndex, textureIndex or 0, 0)
    SetPedHairColor(ped, primaryColor, highlightColor)
end

function ApplyBeardStyle(ped, styleIndex, opacity, color)
    SetPedHeadOverlay(ped, 1, styleIndex, opacity or 1.0)
    SetPedHeadOverlayColor(ped, 1, 1, color, color)
end

function ApplyEyebrows(ped, styleIndex, opacity, color)
    SetPedHeadOverlay(ped, 2, styleIndex, opacity or 1.0)
    SetPedHeadOverlayColor(ped, 2, 1, color, color)
end

function GetAvailableHairStyles(ped)
    local styles = {}
    local numStyles = GetNumberOfPedDrawableVariations(ped, 2)

    for i = 0, numStyles - 1 do
        local numTextures = GetNumberOfPedTextureVariations(ped, 2, i)
        table.insert(styles, {
            index = i,
            textures = numTextures,
            label = 'Style ' .. (i + 1)
        })
    end

    return styles
end

function GetAvailableBeardStyles(ped)
    local styles = {}
    local numStyles = GetNumHeadOverlayValues(1)

    for i = 0, numStyles - 1 do
        table.insert(styles, {
            index = i,
            label = 'Beard ' .. (i + 1)
        })
    end

    return styles
end

NUI arayüzü, GTA'nın dahili renk indekslerini gerçek RGB karşılıklarıyla eşleyerek saç renklerini numaralı indeksler yerine görsel bir palet olarak sunmalıdır. Oyuncuların sakal yoğunluğunu hafif kirli sakaldan gür bir sakala kadar hassas şekilde ayarlamasına olanak tanıyan bir sakal opaklığı kaydırıcısı ekleyin. Oyuncu iptal düğmesine bastığında tüm değişiklikleri geri alabilmek ve yanlışlıkla yapılan değişikliklerin oyuncuya para kaybettirmesini önlemek için berber menüsünü açmadan önce oyuncunun önceki görünümünü saklayın.

Dövme Katman Sistemi

GTA V'teki dövmeler, koleksiyon ve overlay hash çiftlerini kullanarak ped modeli üzerine doku katmanları yerleştiren dekorasyon sistemini kullanır. Her dövme, belirli dövme varlığını birlikte tanımlayan bir koleksiyon adı (örneğin "mpairraces_overlays") ve bir overlay adı (örneğin "MP_Airraces_Tattoo_000_M") ile tanımlanır. Dövmeleri şununla uygulayın: AddPedDecorationFromHashes ve tüm dövmeleri şununla kaldırın: ClearPedDecorations. Zor kısım ise tek bir dövmeyi silmeye yarayan bir native olmamasıdır, bu nedenle bir oyuncu bir dövmeyi sildirmek istediğinde tüm dekorasyonları temizlemeniz ve silinen dışındaki her şeyi yeniden uygulamanız gerekir. Bu da veri modelinizde oyuncunun mevcut dövmelerinin tam bir listesini tutmanız gerektiği anlamına gelir. Dövme koleksiyonunu ve uygulamasını şu şekilde yönetebilirsiniz:

-- Tattoo database structure
local TattooZones = {
    head = {label = 'Head', camera = 'face'},
    torso = {label = 'Torso', camera = 'torso'},
    left_arm = {label = 'Left Arm', camera = 'torso'},
    right_arm = {label = 'Right Arm', camera = 'torso'},
    left_leg = {label = 'Left Leg', camera = 'legs'},
    right_leg = {label = 'Right Leg', camera = 'legs'},
    back = {label = 'Back', camera = 'torso'}
}

-- Available tattoos per zone (abbreviated, real list has hundreds)
Config.Tattoos = {
    torso = {
        {collection = 'mpairraces_overlays', overlay = 'MP_Airraces_Tattoo_000_M',
         label = 'Wing Design', price = 500, zone = 'torso'},
        {collection = 'mpbiker_overlays', overlay = 'MP_MP_Biker_Tat_000_M',
         label = 'Flame Skull', price = 750, zone = 'torso'},
    },
    left_arm = {
        {collection = 'mpchristmas2_overlays', overlay = 'MP_Xmas2_M_Tat_000',
         label = 'Sleeve Art', price = 600, zone = 'left_arm'},
    }
}

function ApplyAllTattoos(ped, tattooList)
    ClearPedDecorations(ped)

    for _, tattoo in ipairs(tattooList) do
        local collectionHash = GetHashKey(tattoo.collection)
        local overlayHash = GetHashKey(tattoo.overlay)
        AddPedDecorationFromHashes(ped, collectionHash, overlayHash)
    end
end

function PreviewTattoo(ped, tattoo, currentTattoos)
    local previewList = {}
    for _, t in ipairs(currentTattoos) do
        table.insert(previewList, t)
    end
    table.insert(previewList, tattoo)
    ApplyAllTattoos(ped, previewList)
end

function RemoveTattoo(ped, tattooIndex, currentTattoos)
    local newList = {}
    for i, t in ipairs(currentTattoos) do
        if i ~= tattooIndex then
            table.insert(newList, t)
        end
    end
    ApplyAllTattoos(ped, newList)
    return newList
end

GTA V içindeki dövme kataloğu, birden fazla DLC koleksiyonuna yayılmış yüzlerce girdi içerir. NUI'nin alana göre filtreleyebilmesi için bunları yapılandırmanızda vücut bölgesine göre düzenleyin. Çoğu dövmenin _M veya _F ile biten ayrı varlık adları bulunduğundan, her dövme için oyuncunun ped modeline bağlı olarak erkek veya kadın varyantının kullanılması gerekip gerekmediğini kontrol edin. Oyuncu katalogdaki bir dövmenin üzerine geldiğinde bir önizleme gösterin ve yalnızca seçimi onayladıklarında ücretlendirin.

Makyaj ve Yüz Boyama Sistemi

Makyaj, çeşitli indeksler genelinde head overlay sistemini kullanır: allık (5), ruj (8) ve ek efektler için göğüs kılı veya ten kaplamaları. Her makyaj türünün birden fazla stil seçeneği ve yoğunluğu kontrol eden bir opaklık kaydırıcısı vardır. Berber dükkanı NUI'sinde mevcut renkleri gösteren görsel renk örnekleriyle her kategoriyi sunan bir makyaj bölümü oluşturun. Makyaj için renk sistemi şunları kullanır: SetPedHeadOverlayColor renk türü parametresi ile: varsayılan renkler için tip 0, saç renkleri (sakal ve kaşlar için kullanılır) için tip 1 ve makyaj renkleri için tip 2. Makyaj özellikle çeşitli ten tonları, kırmızılar, pembeler ve dramatik renkler içeren kozmetik renk paleti sunan renk tipi 2'yi kullanır. Oyuncuların hafif doğal görünümler veya cesur dramatik stiller elde edebilmeleri için her makyaj bileşeni adına bir opaklık kaydırıcısı ekleyin. Oturumlar arasında korunmaları için tüm makyaj ayarlarını oyuncunun görünüm verileriyle birlikte saklayın ve oyuncunun evinde dükkanı ziyaret etmeden makyajını ayarlayabileceği bir ayna etkileşimi sunun.

Ödeme Sistemi ve Fiyatlandırma

Ödeme sisteminin, oyuncunun oturumu sırasında neleri değiştirdiğini takip etmesi ve sunulan hizmetlere göre toplam maliyeti hesaplaması gerekir. Bir oyuncu mağaza menüsünü açtığında mevcut görünümünün anlık görüntüsünü alın. Değişiklik yaptıkça her düzenlemeyi toplamı biriktiren bir oturum sepetinde takip edin. Onaylayıp çıktıklarında yapılan tüm değişikliklerin toplam tutarını tahsil edin. İptal ederlerse anlık görüntüye geri dönün. Temel saç kesimlerinin premium tarzlara kıyasla daha ucuz olduğu ve dövme fiyatlarının boyut ile karmaşıklığa göre değiştiği kademeli fiyatlandırma uygulayın. İşte bir oturum takip ve ödeme sistemi:

local sessionChanges = {}
local originalAppearance = nil

function StartCustomizationSession()
    local ped = PlayerPedId()
    originalAppearance = CaptureFullAppearance(ped)
    sessionChanges = {}
end

function TrackChange(category, item, price)
    -- Remove previous change in same category if exists
    for i = #sessionChanges, 1, -1 do
        if sessionChanges[i].category == category then
            table.remove(sessionChanges, i)
        end
    end

    table.insert(sessionChanges, {
        category = category,
        item = item,
        price = price
    })

    UpdateCartUI()
end

function UpdateCartUI()
    local total = 0
    local items = {}

    for _, change in ipairs(sessionChanges) do
        total = total + change.price
        table.insert(items, {
            label = change.category .. ': ' .. change.item,
            price = change.price
        })
    end

    SendNUIMessage({
        action = 'updateCart',
        items = items,
        total = total
    })
end

function ConfirmAndPay()
    local total = 0
    for _, change in ipairs(sessionChanges) do
        total = total + change.price
    end

    TriggerServerEvent('appearance:server:pay', total, sessionChanges)
end

function CancelSession()
    if originalAppearance then
        RestoreFullAppearance(PlayerPedId(), originalAppearance)
    end
    sessionChanges = {}
    DestroyPreviewCamera()
end

Server tarafında, görünüm değişikliklerini uygulamadan önce oyuncunun yeterli bakiyesi olduğunu doğrulayın. Ödeme başarısız olursa, değişiklikleri geri alması için client tarafını bilgilendirin. Saç kesimi ve sakal düzeltmeyi birlikte almanın tekil hizmetlerin toplamından daha ucuza geldiği paket teklifler sunmayı değerlendirin; bu sayede oyuncuları tek bir ziyarette tüm hizmet yelpazesinden yararlanmaya teşvik edebilirsiniz.

Kıyafet Kaydetme ve Gardırop Entegrasyonu

Berber ve dövme sistemini, oyuncuların eksiksiz görünüm yapılandırmalarını adlandırılmış ön ayarlar olarak kaydetmelerine olanak tanıyan bir kıyafet kaydetme özelliğiyle genişletin. Her ön ayar; saç stili ve rengi, sakal ve bıyık, makyaj ve tüm aktif dövmeler dahil olmak üzere oyuncunun görünümünün tam durumunu yakalar. Oyuncular daha sonra evlerindeki gardıroptan veya dükkanı tekrar ziyaret ederek kayıtlı görünümler arasında geçiş yapabilirler. Kıyafetleri, tüm görünüm verilerini içeren bir JSON bloğuyla oyuncunun citizen ID'sine bağlı olarak veritabanında saklayın. Oyuncu başına kayıtlı kıyafet sayısını sınırlayın veya premium bir özellik olarak ek yuvalar sunun. Oyuncunun evindeki gardırop etkileşimi, oyuncunun onaylamadan önce görebilmesi için her görünümü geçici olarak uygulayan bir önizleme işlevine sahip, kayıtlı kıyafetleri listeleyen basit bir NUI paneli sunmalıdır. Bu, kişisel görünüm sistemini mülk sistemine bağlayarak her iki özelliği ayrı olduklarından daha değerli hale getirir.

Mağaza Konumları ve NPC Berber Entegrasyonu

Harita genelinde, her biri potansiyel olarak farklı hizmetlere ve fiyat çarpanlarına sahip birden fazla dükkan konumu tanımlayın. Güney yakasındaki uygun fiyatlı bir berber düşük fiyatlarla temel saç kesimleri sunabilirken, Vinewood bölgesindeki lüks bir salon yüksek fiyatlar talep edip özel saç modelleri ve renkler sunabilir. Bir oyuncu berber koltuğuna veya dövme istasyonuna yaklaştığında dükkan menüsünü tetiklemek için target sistemini veya yakınlık işaretçilerini kullanın. Oyuncuyu şu yöntemi kullanarak koltuğa oturtun: TaskStartScenarioInPlace berber dükkanları için oturma senaryosu ile veya dövme seansları için belirli bir noktada ayakta durmalarını sağlayarak. Uygun ped modellerini kullanarak her konumda NPC berberler veya dövme sanatçıları spawn edin ve onlara çalışıyor gibi görünmelerini sağlayan boşta kalma animasyonları atayın. Bir oyuncu dükkanla etkileşime girdiğinde, NPC sunulan hizmeti simüle etmek için oyuncunun yakınında bir çalışma animasyonu oynatabilir ve deneyime görsel derinlik katabilir. Seanstan sonra NPC boşta kalma pozisyonuna geri döner. Girişimcilerin kendi berber dükkanlarını veya dövme salonlarını satın alıp yönettiği, fiyatları belirlediği ve NPC personel ya da diğer oyuncuları çalışan olarak işe aldığı oyuncu mülkiyetindeki dükkan oynanışını desteklemek için veritabanında dükkan başına geliri takip edin.

Başlamaya Hazır mısınız?

Scriptleri mağazamızdan edinin veya destek, güncellemeler ve gelecek yeniliklere göz atmak için Discord'a katılın.