games / fivem
Interactions : zones et ox_target
Explication
Ce que vous allez apprendre
- Détecter la proximité d'un joueur avec un point d'intérêt par polling manuel
- Ajuster dynamiquement le
Wait()d'une boucle de détection selon la distance - Utiliser
ox_targetpour centraliser la détection de zones et d'entités interactives - Choisir entre une zone géométrique (
addBoxZone) et une entité ciblée (addLocalEntity) - Retirer dynamiquement une interaction devenue inutile
Dans quel contexte ?
Une boutique en jeu doit afficher un marqueur au sol et proposer une interaction "Ouvrir la boutique" uniquement quand un joueur s'en approche suffisamment. Si vingt boutiques différentes sur le serveur utilisent chacune leur propre boucle de vérification de distance, la charge cumulée devient vite sensible — cette leçon montre d'abord la méthode manuelle, puis la solution centralisée qui règle ce problème à l'échelle du serveur.
| Approche | Coût à grande échelle | Cas d'usage typique |
|---|---|---|
Polling manuel (CreateThread + distance) | Élevé si répété par de nombreux scripts | Cas isolé, prototype rapide |
ox_target (zones/entités déclarées) | Faible, mutualisé | Production, plusieurs dizaines de points d'intérêt |
Astuce
Même en polling manuel, ajuste dynamiquement le Wait() selon la distance (comme montré dans le code) : rester "au repos" avec un Wait(1000) tant que le joueur est loin, puis accélérer la boucle seulement à proximité, réduit considérablement le coût cumulé.
Détecter qu'un joueur est "au bon endroit"
Une immense partie du gameplay roleplay repose sur des interactions liées à la position : ouvrir une boutique en s'approchant d'un point précis, parler à un PNJ, utiliser un objet du décor. Il faut donc un moyen fiable de savoir, à tout instant, si un joueur se trouve suffisamment proche d'un endroit ou d'un objet donné pour déclencher une action.
L'approche manuelle : simple, mais coûteuse à grande échelle
La méthode la plus intuitive consiste à créer une boucle qui vérifie en continu la distance entre le joueur et le point d'intérêt. C'est parfaitement fonctionnel pour un seul point, mais si vingt ressources différentes font chacune tourner leur propre boucle de vérification, cela représente vingt vérifications redondantes exécutées en permanence — un gaspillage de performance qui devient sensible à l'échelle d'un vrai serveur.
Pourquoi une bibliothèque dédiée change la donne
Des bibliothèques comme ox_target centralisent cette détection de proximité en un seul système partagé : toutes les zones et entités interactives sont déclarées une seule fois au démarrage, et une seule logique optimisée se charge de vérifier lesquelles sont pertinentes à chaque instant, au lieu de dizaines de boucles indépendantes qui font chacune le même travail dans leur coin.
Deux façons de définir une interaction
Une "zone" géométrique (une boîte dans l'espace) convient pour un lieu fixe comme l'entrée d'une boutique. Cibler directement une "entité" (un personnage, un objet précis) convient mieux quand l'interaction doit suivre cet objet, même s'il se déplace. Choisir la bonne approche selon le cas d'usage évite de recréer artificiellement des zones là où cibler l'entité serait plus simple et plus robuste.
Commandes & code
Interactions : zones et ox_target
Deux approches pour détecter la proximité d'un joueur avec un point d'intérêt : le polling manuel, ou une librairie dédiée.
-- Méthode "manuelle" : polling de distance, avec sleep dynamique (voir leçon Performance)
CreateThread(function()
local shopCoords = vector3(215.0, -810.0, 30.0)
while true do
local sleep = 1000
local playerCoords = GetEntityCoords(PlayerPedId())
local distance = #(playerCoords - shopCoords)
if distance < 10.0 then
sleep = 0 -- boucle rapide seulement quand on est proche (optimisation)
if distance < 2.0 then
DrawMarker(1, shopCoords.x, shopCoords.y, shopCoords.z - 1.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.5, 1.5, 1.0, 0, 255, 0, 100, false, true, 2, false, nil, nil, false)
if IsControlJustPressed(0, 38) then -- touche E
TriggerEvent('technologik:openShop')
end
end
end
Wait(sleep)
end
end)-- ox_target : bien plus performant, zones/entités déclarées une seule fois au démarrage
exports.ox_target:addBoxZone({
coords = vector3(215.0, -810.0, 30.0),
size = vector3(2.0, 2.0, 2.0),
rotation = 0.0,
options = {
{
name = 'open_shop',
icon = 'fa-solid fa-cart-shopping',
label = 'Ouvrir la boutique',
onSelect = function()
TriggerEvent('technologik:openShop')
end,
},
},
})-- Cibler une entité spécifique (ex: un PNJ vendeur)
local shopKeeperPed = CreatePed(4, GetHashKey('a_m_m_business_01'),
215.0, -808.0, 30.0, 90.0, false, false)
FreezeEntityPosition(shopKeeperPed, true)
exports.ox_target:addLocalEntity(shopKeeperPed, {
{
name = 'talk_to_shopkeeper',
icon = 'fa-solid fa-comment',
label = 'Parler au vendeur',
distance = 2.5,
onSelect = function(data)
TriggerEvent('technologik:openShop')
end,
},
})
-- Retirer dynamiquement une zone (ex: fermeture de la boutique la nuit)
exports.ox_target:removeZone('open_shop')Résumé
- Le polling manuel reste valide pour des cas simples, mais devient coûteux à grande échelle.
ox_targetcentralise la détection de proximité et évite des dizaines de threads redondants.addBoxZonecible une zone géométrique,addLocalEntitycible une entité précise (ped, véhicule, objet).
Exercices pratiques
Mission : vingt boutiques qui font ramer le serveur
Objectif : Diagnostiquer le coût cumulé de vingt boucles de polling manuel, puis migrer une boutique vers ox_target.
Contexte
Le serveur technologik_rp compte vingt boutiques différentes, chacune développée indépendamment avec sa propre boucle CreateThread de polling de distance, comme montré dans la leçon. Les joueurs signalent des micro-freezes réguliers en jeu, sans qu'aucune boutique individuelle ne semble buguée quand on la teste seule.