Retour au cours

games / fivem

NUI : interface HTML/JS embarquée

Leçon 61 exercice

Explication

Ce que vous allez apprendre

  • Comprendre ce qu'est la NUI et pourquoi c'est une vraie page web classique
  • Déclarer une page NUI dans le fxmanifest.lua (ui_page, files)
  • Envoyer des données du Lua vers le JavaScript avec SendNUIMessage
  • Recevoir ces données côté JavaScript via window.addEventListener('message', ...)
  • Donner le contrôle du curseur/clavier au joueur avec SetNuiFocus

Dans quel contexte ?

Un serveur RP veut proposer un menu de boutique avec des articles cliquables, des images et une mise en page soignée — quelque chose que les éléments d'interface natifs du jeu ne permettent tout simplement pas de construire facilement. La NUI répond exactement à ce besoin en embarquant un vrai moteur de navigateur web par-dessus le jeu, avec toutes les compétences HTML/CSS/JS habituelles directement réutilisables.

Élément du manifestRôle
ui_page 'html/ui.html'Déclare la page NUI de la ressource
files { ... }Rend les fichiers web accessibles au moteur NUI

Piège fréquent

Oublier SetNuiFocus(true, true) après avoir affiché une interface NUI laisse le joueur incapable de cliquer ou de taper dans cette interface, tout en continuant de contrôler son personnage normalement : l'UI est visible mais totalement inutilisable, un oubli très courant chez les débutants.

Sortir des limites du jeu lui-même

Le moteur de GTA V sait dessiner des éléments d'interface basiques (texte, jauges), mais reste très limité pour construire des interfaces modernes comme un menu de boutique avec des boutons cliquables, des listes déroulantes ou des animations fluides. FiveM contourne cette limite en embarquant un véritable moteur de navigateur web (basé sur la même technologie que Chrome), ce qui permet à n'importe quelle ressource d'afficher sa propre page web par-dessus le jeu. C'est ce qu'on appelle la NUI (New/Native User Interface).

Une vraie page web, avec ses propres règles

C'est le point essentiel à intégrer : une interface NUI, ce n'est ni plus ni moins qu'une page HTML/CSS/JavaScript classique, comme n'importe quel site web. Toutes les compétences de développement web habituelles s'appliquent directement — mise en page CSS, manipulation du DOM en JavaScript. La seule vraie nouveauté est la façon dont cette page communique avec le code Lua du jeu.

Lua parle à JavaScript : SendNUIMessage

Le Lua ne peut pas manipuler directement les éléments de la page web. Il envoie plutôt un message structuré (SendNUIMessage) que la page JavaScript reçoit via un mécanisme standard du navigateur (window.addEventListener('message', ...)), et c'est le JavaScript qui se charge ensuite de mettre à jour l'affichage en fonction de ce message reçu.

Rendre le contrôle au joueur

Par défaut, la page NUI est invisible et ne capte ni le clavier ni la souris : le joueur continue de contrôler son personnage normalement. SetNuiFocus(true, true) doit être appelé explicitement pour "donner" le curseur et le clavier à l'interface — un oubli fréquent chez les débutants, qui se retrouvent avec une interface visible mais totalement impossible à utiliser.

Commandes & code

NUI : interface HTML/CSS/JS embarquée

FiveM embarque un moteur CEF (type Chromium) : chaque ressource peut afficher sa propre page web par-dessus le jeu.

lua
-- fxmanifest.lua (rappel de la leçon 2)
ui_page 'html/ui.html'

files {
    'html/ui.html',
    'html/ui.js',
    'html/ui.css',
}
html
<!-- html/ui.html -->
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="ui.css">
</head>
<body>
    <div id="shop" class="hidden">
        <h2>Boutique</h2>
        <ul id="shop-items"></ul>
        <button id="close-btn">Fermer</button>
    </div>
    <script src="ui.js"></script>
</body>
</html>
css
/* html/ui.css */
.hidden {
    display: none;
}

#shop {
    position: absolute;
    top: 20%;
    left: 50%;
    transform: translateX(-50%);
    width: 320px;
    background: rgba(20, 20, 20, 0.9);
    color: white;
    border-radius: 8px;
    padding: 16px;
    font-family: sans-serif;
}
lua
-- CLIENT (client/nui.lua) : ouvrir l'interface et lui envoyer des données
local function OpenShopMenu()
    SetNuiFocus(true, true) -- (hasFocus, hasCursor) : rend le curseur/clavier à la page NUI
    SendNUIMessage({
        action = 'openShop',
        items = {
            { name = 'bread', price = 5 },
            { name = 'water', price = 3 },
        }
    })
end

RegisterNetEvent('technologik:openShop', OpenShopMenu)
javascript
// html/ui.js : réception des messages envoyés par Lua via SendNUIMessage
window.addEventListener('message', (event) => {
    const data = event.data;

    if (data.action === 'openShop') {
        const shop = document.getElementById('shop');
        const list = document.getElementById('shop-items');
        list.innerHTML = '';

        data.items.forEach(item => {
            const li = document.createElement('li');
            li.textContent = `${item.name} - $${item.price}`;
            list.appendChild(li);
        });

        shop.classList.remove('hidden');
    }
});

Résumé

  • ui_page + files dans le manifest exposent la page au moteur NUI.
  • SendNUIMessage (Lua → JS) envoie des données via window.addEventListener('message', ...).
  • SetNuiFocus(true, true) est indispensable pour que le joueur puisse cliquer/taper dans l'UI.

Exercices pratiques

1 disponible
1

Mission : le menu boutique figé à l'écran

Objectif : Corriger une interface NUI visible mais totalement inutilisable, puis raisonner sur la synchronisation entre chargement de page et envoi de messages.

Contexte

Un joueur signale que le menu de boutique s'affiche bien à l'écran après avoir tapé /shop, mais qu'il est impossible de cliquer sur quoi que ce soit ni de bouger la souris pour interagir : le personnage continue de courir normalement pendant ce temps. Le code client de la commande /shop se limite à SendNUIMessage({ action = 'openShop', items = items }), sans rien d'autre.

Résoudre l’exercice →