[Résolu] Récupérer et utiliser des données JSON

Questions à propos du scripting. Hors Shader, GUI, Audio et Mobile.
JollyStone
Messages : 33
Inscription : 03 Avr 2019 15:09
Localisation : Liège (B)
Contact :

[Résolu] Récupérer et utiliser des données JSON

Message par JollyStone » 03 Sep 2023 11:14

Bonjour,

Pour un jeu, je cherche à récupérer l’entièreté des données d’un fichier JSON dans une liste.
Ensuite, pouvoir sélectionner aléatoirement l’un des mots (+ sa difficulté et ses définitions) de cette liste en tenant compte que chaque mot ne peut être utilisé qu’une seule fois (donc supprimé de la liste lors de son utilisation unique).

Le fichier JSON à la structure suivante :

Code : Tout sélectionner

{”AllData”:[
	{”word”:MOT-1”, ”difficulty”:1, ”definitions”:[”Définition-1”,”Définition-2”]},
	{”word”:”MOT-2”, ”difficulty”:1,”definitions”:[”Définition-1”,”Définition-2”,”Définition-3”]}
	…
]}
Comment mettre ça en œuvre en C# ?
Dernière édition par JollyStone le 11 Sep 2023 14:24, édité 1 fois.

djulio74
Messages : 682
Inscription : 19 Déc 2009 22:55

Re: Récupérer et utiliser des données JSON

Message par djulio74 » 03 Sep 2023 20:51

bonsoir,

après pas mal de recherche et test, voila une méthode qui fonctionne pour extraire les données d'un JSON avec liste ou array :

- créer une classe avec les éléments pour un mot, par exemple :

Code : Tout sélectionner

[System.Serializable]
public class WordsData
{
    public string word;
    public int difficulty;
    public string[] definitions;
}
attention a ce que les noms de variable soient identiques a celle du JSON (word, difficulty..)
ensuite créer une classe, d'un array de la classe précédente, par exemple :

Code : Tout sélectionner

[System.Serializable]
public class WordsAll
{
    public WordsData[] AllData;
}
idem, attention a l'orthographe des données (AllData)

ensuite, lire le fichier JSON et le stocker dans un string, puis décomposer le string suivant la claasse untilisée, ce qui donnerai :

Code : Tout sélectionner

       
        string path = "C:/Users/Julien/Desktop/test 1.txt"; // Remplacez ceci par le chemin de ton fichier JSON
        string fromJSON = File.ReadAllText(path);
        WordsAll WordsList= JsonUtility.FromJson<WordsAll>(fromJSON);
tu as donc un array de classe "WordsData". et par exemple, pour savoir combien de définitions a le premier mot :

Code : Tout sélectionner

print(WordsList.AllData[0].definitions.Length); // retoure 2 dans l'exemple
le code complet de mon exemple :

Code : Tout sélectionner

using UnityEngine;
using System.IO;


[System.Serializable]
public class WordsData
{
    public string word;
    public int difficulty;
    public string[] definitions;
}

[System.Serializable]
public class WordsAll
{
    public WordsData[] AllData;
}

public class ToJSON : MonoBehaviour
{
    void Start()
    {
        string path = "C:/Users/Julien/Desktop/test 1.txt"; // Remplacez ceci par le chemin de ton fichier JSON
        string fromJSON = File.ReadAllText(path);
        WordsAll WordsList = JsonUtility.FromJson<WordsAll>(fromJSON);
        print(WordsList.AllData[0].definitions.Length); // retoure 2 dans l'exemple
    }
}
ensuite pour sortir au hasard, un random et un stockage des mots déjà sortis par exemple.
j'espere que ça va aider, :super:

PS :
Attention, ton exemple de JSON as des erreur, pas exploitable en l'état (sans compter les ...), il manque un guillement avant Mot-1 et les guillemets ne sont pas les bons une fois que j'ai fait copier collé :

Code : Tout sélectionner

{"AllData":[
	{"word":"MOT-1", "difficulty":1, "definitions":["Définition-1","Définition-2"]},
	{"word":"MOT-2", "difficulty":2, "definitions":["Définition-1","Définition-2","Définition-3"]},
	{"word":"MOT-3", "difficulty":3, "definitions":["Définition-1","Définition-2","Définition-3","Définition-4"]}

]}

______________________________________________________________
\_______________________ Impossible is nothing _______________________/

JollyStone
Messages : 33
Inscription : 03 Avr 2019 15:09
Localisation : Liège (B)
Contact :

Re: Récupérer et utiliser des données JSON

Message par JollyStone » 04 Sep 2023 16:20

Magnifique !

Au fond, mes propres essais n’étaient pas très loin de ce que tu proposes ici.
Il me manquait surtout la classe « WordsAll ».

L’exemple du fichier JSON ci-avant n’est là que pour montrer sa structure générale, du coup il ne faut pas s’étonner d’y trouver quelques erreurs de syntaxe. Mon fichier contient 4389 mots avec jusqu’à 4 ou 5 définitions pour chacun. ;-)

Bon, il reste quelques zones d’ombre dans mon esprit et je repasserai certainement par ici pour les éclaircir au fur et à mesure des petits problèmes que je ne manquerai pas de rencontrer par la suite.

Un tout grand merci djulio74 !
Ça faisait des semaines que j’étais bloqué là-dessus…
(avant de me décider à passer par ce forum de grande utilité :super:).

djulio74
Messages : 682
Inscription : 19 Déc 2009 22:55

Re: Récupérer et utiliser des données JSON

Message par djulio74 » 04 Sep 2023 18:37

Je pensais bien que ce n'était qu'un exemple, j'ai précisé dans le doute car ne connaissant pas les JSON, j'avais bêtement copié collé ton exemple, et évidement je n'arrivais a rien avec. lol.
J'ai d'abord dû chercher comment générer un texte JSON, pour voir sa construction et "grammaire", avant de chercher le chemin inverse de lecture. :)

Quand tu fais des tests même non concluants, hésite pas à poster ton code même non fonctionnel pour demander de l'aide dessus, plutôt qu'une question sans savoir ou tu en es, ça permet de proposer une solution adaptée à ou tu en es plutôt que de proposer du nouveau qu'il n'est pas toujours facile à transposer dans ton projet. ;-)

Et si problème réglé, pense a passer le sujet en [RESOLU] en editant ton premier message :super:

______________________________________________________________
\_______________________ Impossible is nothing _______________________/

JollyStone
Messages : 33
Inscription : 03 Avr 2019 15:09
Localisation : Liège (B)
Contact :

Re: Récupérer et utiliser des données JSON

Message par JollyStone » 09 Sep 2023 12:19

Désolé pour le JSON qui t’a compliqué la tâche.
D’ailleurs, voici le lien pour télécharger mon fichier, ça peut être utile ici et ça peut intéresser quelqu’un. C’est une liste de 4389 mots de 8 lettres et leur(s) définition(s) que j’utilise pour un jeu du pendu :
https://drive.google.com/file/d/1sGnaXq ... sp=sharing

Je suis arrivé à mettre tout ça en place et à atteindre aléatoirement un des mots.
Par contre, je n’arrive pas à placer tous les mots extraits du JSON dans une liste.
Mon idée est que chaque fois qu’un mot est utilisé il doit être supprimé de cette liste pour éviter qu’il ne soit tiré une seconde fois. À ce que je comprends, une liste est dynamique contrairement à un tableau.
Ce qui corse peut-être les choses c’est que les définitions doivent bien sûr rester liées à leur mot. D’où la question : peut-on mettre un tableau de définitions dans une liste ? Je m’y perds un peu là-dedans.

Voici mes scripts en l’état actuel (un peu brouillons) :

La classe ‘WordsData :

Code : Tout sélectionner

[System.Serializable]
public class WordsData {

    public string word;
    public int difficulty;   // '1' ==> sans accent / '2' ==> avec accent
    public string[] definitions;
}
La classe WordsAll :

Code : Tout sélectionner

[System.Serializable]
public class WordsAll {

    public WordsData[] allData;
}
La classe ’TotalData’ :

Code : Tout sélectionner

using UnityEngine;
using System.Collections.Generic;
using System.IO;

public class TotalData : MonoBehaviour {

    string dataFileName = "data.json";
    WordsData wordsData;
    WordsAll wordsList;
    List<WordsData> unusedWords = new List<WordsData>();

    public string currentWord;
    public string[] currentDefinition;
    public int nbWords;
    public int index;

    void Start() {
        LoadData();
    }

    void Update() {
        if (Input.GetKeyDown(KeyCode.Space)) {
            RandomIndex();
            GetWord();
        }
    }

    void LoadData() {
        string filePath = Path.Combine(Application.streamingAssetsPath, dataFileName);  // Chemin du fichier contenant les données
        if (File.Exists(filePath)) {
            Debug.Log("Le fichier existe");
            string json = File.ReadAllText(filePath);   // String contenant tout le texte du fichier
            wordsList = JsonUtility.FromJson<WordsAll>(json);

            foreach (WordsData wordTemp in wordsList.allData) {
                unusedWords.Add(wordsData); // Liste des mots inutilisés
            }

            //nbWords = unusedWords.Count;  // -> Retourne bien 4389 <-
            nbWords = wordsList.allData.Length;
            Debug.Log("Nb words = " + nbWords); // -> Retourne bien 4389 <-
        }
        else {
            Debug.LogError("Le fichier n'existe pas");
        }
    }

    public string GetWord() {   // Appelé depuis le script 'Game'
        currentWord = wordsList.allData[index].word;  // -> Fonctionne ! <-
        //currentWord = unusedWords[index].word;  // -> Ne fonctionne pas (NullReferenceException) ! <-
        return currentWord.ToString();
    }

    public string GetDefinition() {   // Appelé depuis le script 'Game'
        currentDefinition = wordsList.allData[index].definitions;
        return currentDefinition.ToString();
    }

    public void RandomIndex() { // Tirage aléatoire d'un index de la liste de mots
        index = Random.Range(0, nbWords);
        Debug.Log("Index = " + index);
    }
}

djulio74
Messages : 682
Inscription : 19 Déc 2009 22:55

Re: Récupérer et utiliser des données JSON

Message par djulio74 » 09 Sep 2023 16:00

Salut,
ton script est bon à une erreur près :
Quand tu ajoute à ta liste tes éléments, c'est wordtemp qu'il faut ajouter et non wordsData qui n'est jamais assigné de toute façon.

Code : Tout sélectionner

            foreach (WordsData wordTemp in wordsList.allData) {
                unusedWords.Add(wordTemp ); // Liste des mots inutilisés
            }

Juste ce petit changement et ça devrait rouler! :super:


PS :
Pour info j'avais lu quelque part qu'il fallait éviter les foreach, qui crés un nouvel elément et lui assigne une valeur (wordtemp dans ton cas) pour chaque élément d'une liste ou array. Ca peut devenir gourmand pour les longue liste, ou des appels fréquents.
plutot préférer les for () :

Code : Tout sélectionner

            for ( int i = 0; i< wordsList.allData.Length; i++)
            {
                unusedWords.Add(wordsList.allData[i]);
            }
Dans l'absolu ça revient au même, sauf que pour chaque élément de la liste parcourue, au lieu de créer un nouveau WordData, on lit juste celui qui est en cours dans la liste de base. La seul variable créée une fois est "i" qu'on assigne a chaque index de la liste.

______________________________________________________________
\_______________________ Impossible is nothing _______________________/

JollyStone
Messages : 33
Inscription : 03 Avr 2019 15:09
Localisation : Liège (B)
Contact :

Re: Récupérer et utiliser des données JSON

Message par JollyStone » 11 Sep 2023 14:23

Ça c’est génial !
J’ignorais cette différence entre une boucle « for » et une boucle « foreach » et j’ai appliqué ta suggestion, même si une liste de 4389 éléments n’est peut-être pas si énorme que ça… Va savoir !

Bon, ce système fonctionne maintenant très bien, même si j’ai encore quelques ajustements à faire.
Un tout grand merci djulio74 ! :super:

djulio74
Messages : 682
Inscription : 19 Déc 2009 22:55

Re: [Résolu] Récupérer et utiliser des données JSON

Message par djulio74 » 11 Sep 2023 18:28

super si ça marche ! :super:
par contre en revoyant le code, j'avais pas vu mais il y a plus simple ! lol

au lieu que la classe WordAll soit composé d'un array de allData, autant en faire directement une liste!

Code : Tout sélectionner

public class WordsAll
{
    public List<WordsData> allData;
}
comme ça "wordsList.allData" est directement une liste, plus besoin d'en créer une autre.

ce qui donne :

Code : Tout sélectionner

using UnityEngine;
using System.Collections.Generic;
using System.IO;


[System.Serializable]
public class WordsData
{

    public string word;
    public int difficulty;   // '1' ==> sans accent / '2' ==> avec accent
    public string[] definitions;
}

[System.Serializable]
public class WordsAll
{
    public List<WordsData> allData;
}
public class TotalData : MonoBehaviour
{

    string dataFileName = "data.json";
    WordsAll wordsList;
    List<WordsData> unusedWords = new List<WordsData>();

    public string currentWord;
    public string[] currentDefinition;
    public int nbWords;
    public int index;

    void Start()
    {
        LoadData();
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            RandomIndex();
            GetWord();
            GetDefinition();
        }
    }

    void LoadData()
    {
        string filePath = "C:/Users/Julien/Desktop/test 1.txt";  // Chemin du fichier contenant les données
        if (File.Exists(filePath))
        {
            Debug.Log("Le fichier existe");
            string json = File.ReadAllText(filePath);   // String contenant tout le texte du fichier
            wordsList = JsonUtility.FromJson<WordsAll>(json);
            nbWords = wordsList.allData.Count; ;  // -> Retourne bien 4389 <-
        }
        else
        {
            Debug.LogError("Le fichier n'existe pas");
        }
    }

    public string GetWord()
    {   // Appelé depuis le script 'Game'
        //currentWord = wordsList.allData[index].word;  // -> Fonctionne ! <-
        currentWord = wordsList.allData[index].word;  // -> Ne fonctionne pas (NullReferenceException) ! <-
        return currentWord.ToString();
    }

    public string GetDefinition()
    {   // Appelé depuis le script 'Game'
        //currentDefinition = wordsList.allData[index].definitions;
        currentDefinition = wordsList.allData[index].definitions;
        return currentDefinition.ToString();
    }

    public void RandomIndex()
    { // Tirage aléatoire d'un index de la liste de mots
        index = Random.Range(0, nbWords);
        Debug.Log("Index = " + index);
    }
}

voila, c'état ma petite manie de toujours chercher à faire plus court, simple :super:

______________________________________________________________
\_______________________ Impossible is nothing _______________________/

Répondre

Revenir vers « Scripting »