ox_target e Interazioni

INFO

ox_target permette di creare punti di interazione nel mondo. Perfetto per negozi, veicoli, NPC e oggetti custom.

ObiettivoDettagli
Cosa imparerai• Creare zone di interazione (box, sphere, entity)
• Integrare ox_target con veicoli e NPC
• Usare opzioni avanzate come filtri per job/item
Prerequisiti• ox_target installato e avviato
• Conoscenza base FiveM events
• ox_lib per notifiche

Cos’è ox_target

ox_target sostituisce i vecchi sistemi di interazione (es. drawtext, 3dtext, qtarget). Mostra un menu contestuale quando il giocatore punta e interagisce con oggetti/zona nel mondo.


Tipi di Zone

TipoDescrizioneQuando Usarlo
addBoxZoneZona rettangolareNegozi, porte, ingressi
addSphereZoneZona sfericaAree circolari
addCircleZoneZona cerchioRaggio intorno a un punto
addEntityZoneEntità GTA VVeicoli, ped, oggetti
addModelZoneTutte le entità di un modelloEs. tutte le sedie
addTargetBoneOsso specificoPorte veicolo, ruote

1. Zona Base (Box)

-- client.lua
CreateThread(function()
    exports.ox_target:addBoxZone({
        coords = vector3(250.0, -150.0, 29.5),  -- Centro zona
        size = vec3(2.0, 2.0, 2.0),              -- Larghezza, profondità, altezza
        rotation = 0,                              -- Rotazione
        debug = Config.Debug,                      -- Mostra il box (debug)
        
        options = {
            {
                name = 'open_shop',               -- ID univoco
                event = 'myresource:openShop',    -- Evento da triggerare
                icon = 'fa-solid fa-shop',         -- Icona FontAwesome
                label = 'Apri Negozio',            -- Testo
                canInteract = function(entity, distance, coords, name, bone)
                    return true                    -- Condizione per mostrare
                end,
                distance = 2.5,                    -- Distanza di interazione
                items = nil,                       -- Item richiesti (es. {'key'})
                job = nil,                         -- Job richiesto (es. 'police')
            }
        }
    })
end)

2. Interazione con Veicoli

WARNING

addModel va chiamato una sola volta (all’avvio della risorsa). ox_target applica automaticamente le opzioni a tutti i veicoli di quel modello nel mondo. Chiamarlo dentro un while true registra le stesse opzioni migliaia di volte e degrada il server.

-- client.lua
CreateThread(function()
    -- Una singola chiamata: vale per ogni veicolo modello 'charger20'
    -- che appare (o apparirà) nel mondo.
    exports.ox_target:addModel('charger20', {
        options = {
            {
                name = 'lock_vehicle',
                icon = 'fa-solid fa-lock',
                label = 'Blocca/Sblocca',
                onSelect = function(data)
                    local plate = GetVehicleNumberPlateText(data.entity)
                    TriggerServerEvent('myresource:toggleDoor', plate)
                end,
                distance = 3.0,
                canInteract = function(entity, distance)
                    -- Mostra l'opzione solo se il giocatore ha la chiave di quel veicolo
                    local plate = GetVehicleNumberPlateText(entity)
                    local count = exports.ox_inventory:Search(nil, 'count', 'vehiclekey', { plate = plate })
                    return count > 0
                end
            },
            {
                name = 'check_vehicle',
                icon = 'fa-solid fa-info',
                label = 'Controlla Veicolo',
                event = 'myresource:checkVehicle',
                job = 'police',  -- Solo polizia
                distance = 3.0,
            }
        }
    })
end)

NOTE

La firma corretta di Search in ox_inventory è exports.ox_inventory:Search(inv, 'count', item, metadata) — sul client si passa nil come inventario (il giocatore locale) e 'count' per ricevere il numero di item. Gli eventi di interazione si collegano con event (TriggerServerEvent) oppure onSelect (callback locale).


3. Interazione con Entità (Entity)

-- client.lua
-- Per un oggetto specifico nel mondo (es. un banco da lavoro spawnato)
CreateThread(function()
    -- Prima spawna l'oggetto
    local model = GetHashKey('prop_toolchest_01')
    RequestModel(model)
    while not HasModelLoaded(model) do Wait(100) end
    
    local workbench = CreateObjectNoOffset(model, 300.0, -100.0, 29.5, true, false, false)
    SetEntityHeading(workbench, 0.0)
    FreezeEntityPosition(workbench, true)
    
    -- Poi aggiungi interazione (entity handle, non il nome)
    exports.ox_target:addLocalEntity(workbench, {
        options = {
            {
                name = 'open_crafting',
                icon = 'fa-solid fa-screwdriver-wrench',
                label = 'Apriti Banco da Lavoro',
                event = 'myresource:openCrafting',
                distance = 2.0,
            }
        }
    })
end)

4. Interazione con Ped (NPC)

INFO

Le entità spawnate (ped, oggetti) persistono nel mondo finché non vengono cancellate con DeleteEntity(). Usa ox_target:removeLocalEntity() quando rimuovi l’entità per pulire anche le interazioni.

-- client.lua
CreateThread(function()
    -- Spawna un NPC
    local model = GetHashKey('s_m_y_cop_01')
    RequestModel(model)
    while not HasModelLoaded(model) do Wait(100) end
    
    local npc = CreatePed(1, model, 250.0, -150.0, 30.0, 180.0, true, false)
    SetEntityInvincible(npc, true)
    FreezeEntityPosition(npc, true)
    TaskStartScenarioInPlace(npc, 'WORLD_HUMAN_CLIPBOARD', 0, true)
    
    -- Aggiungi interazione al ped
    exports.ox_target:addEntity(npc, {
        options = {
            {
                name = 'talk_to_armorer',
                icon = 'fa-solid fa-gun',
                label = 'Parla con l\'Armaiolo',
                event = 'myresource:openWeaponShop',
                distance = 2.5,
            }
        }
    })
end)

5. Eventi Lato Server

-- client.lua
RegisterNetEvent('myresource:openShop')
AddEventHandler('myresource:openShop', function()
    -- Apri lo shop registrato (vedi file 03: data/shops.lua o RegisterShop)
    exports.ox_inventory:openInventory('shop', {
        type = 'weapon_shop_basic',
    })
end)

NOTE

openInventory('shop', { type = ... }) apre un negozio registrato (in data/shops.lua o tramite exports.ox_inventory:RegisterShop). Non si passano items/slots/label inline: quelle proprietà vengono dal negozio registrato. Vedi Armi Custom con ESX.

-- server.lua
RegisterNetEvent('myresource:buyItemServer')
AddEventHandler('myresource:buyItemServer', function(item, price)
    local xPlayer = ESX.GetPlayerFromId(source)
 
    -- MAI fidarsi del prezzo inviato dal client: ricalcola dal config
    if type(item) ~= 'string' then return end
    local shopItem = Config.ShopItems[item]
    if not shopItem then return end
    price = shopItem.price
 
    if xPlayer.getAccount('money').money >= price then
        xPlayer.removeAccountMoney('money', price)
        xPlayer.addInventoryItem(item, 1)
 
        exports.ox_lib:notify(source, {
            title = 'Acquisto',
            description = item .. ' acquistato!',
            type = 'success'
        })
    end
end)

6. Opzioni Avanzate di ox_target

Opzioni Dinamiche

exports.ox_target:addBoxZone({
    coords = vector3(250.0, -150.0, 29.5),
    size = vec3(1.0, 1.0, 2.0),
    rotation = 0,
    options = {
        -- Opzione visibile solo se il giocatore ha un item
        {
            name = 'repair_vehicle',
            icon = 'fa-solid fa-wrench',
            label = 'Ripara Veicolo',
            event = 'myresource:repairVehicle',
            items = 'repair_kit',  -- Richiede repair_kit nell'inventario
            distance = 2.0,
        },
        -- Opzione visibile solo per un job specifico
        {
            name = 'impound_vehicle',
            icon = 'fa-solid fa-tow-truck',
            label = 'Sequestra Veicolo',
            event = 'myresource:impoundVehicle',
            job = 'police',
            distance = 2.0,
        },
        -- Opzione con funzione personalizzata
        {
            name = 'custom_action',
            icon = 'fa-solid fa-star',
            label = 'Azione Custom',
            canInteract = function(entity, distance, coords)
                local hour = GetClockHours()
                return hour >= 9 and hour <= 18  -- Solo in orario ufficio
            end,
            onSelect = function()
                TriggerEvent('myresource:customAction')
            end,
            distance = 2.0,
        }
    }
})

Rimuovere una Zona

-- Rimuovi una zona specifica
exports.ox_target:removeZone('open_shop')
 
-- Rimuovi tutte le zone di una risorsa
exports.ox_target:removeLocalEntity(npc)

TIP

Prossimo passo: 07 - ox_lib UI


Torna alla: Indice Generale