Fonctionnement des prefabs boutons pour un dialogue a partir d'un fichier XML

Bonjour!
J’ai fait des dialogues pour mon jeu dans un fichier XML.

<?xml version="1.0" encoding="UTF-8" ?>
<!--
<b>TEXT</b> = TEXT en gras
{{X}} = remplire avec la variable X
<i>TEXT</i> = TEXT en italique

-->
<Discussion>
  <CowBoy>
    <Tuto1>
      <Field type="Begining">
        <Phrases>
          <a type="Page">Eh tu ne serais pas le Slime le plus rapide de l'Ouest par hasard?</a>
          <b type="Page">Je suis une pauvre phrase qui sera bientôt supprimer :'(  <b><i>*snif*</i></b></b>
        </Phrases>
        <Answers>
          <a type = "Answer" goto="Mensonge" action="GiveParchemin">Ahah tu m'as reconnu!</a>
          <b type = "Answer" goto="Fail">Euh non pourquoi?</b>
          <c type = "Answer" goto="Obviously">Attends il y d'autres Slimes comme moi dans le monde?</c>
        </Answers>
      </Field>

      <Field type ="Mensonge">
        <Phrases>
          <a type="Page">Ah! Salut {{BESTPLAYER}}! Comment ca va?</a>
          <b type="Page">Attends mais t'es pas {{BESTPLAYER}}!?</b>
          <c type="Page">Comment oses-tu me mentir!!!</c>
          <d type="Page"><b>VIL SLIME!!!</b></d>
          <e type="Page">Bon ça va pour cette fois mais ne t'avises plus de me mentir!</e>
          <f type="Page" action="GiveParchemin">Et si tu veux un jour être le Slime le plus rapide de l'Ouest je te donne ce parchemin.</f>
          <g type="Page">Je ne comprends pas ce qu'il dit mais je suis sur que tu peux y arriver!</g>
        </Phrases>
        <Answers>
          <a type="Answer" action="EndConversation">Merci... ^^'</a>
        </Answers>
      </Field>

      <Field type ="Fail">
        <Phrases>
          <a type="Page">Oh mince j'ai du me tromper alors mais tu peux essayer de le devenir!</a>
        </Phrases>
        <Answers>
          <a type = "Answer" goto="Explications">A bon? Mais comment?</a>
          <b type = "Answer" goto="ComeBackLater">Ca ne m'intéresse pas merci.</b>
          <c type = "Answer" goto="Recompences">Mais pourquoi je ferais çà?</c>
        </Answers>
      </Field>

      <Field type="ComeBackLater">
        <Phrases>
          <a type = "Page">Ah! Euhhh... Ok.</a>
          <b type = "Page" action="EndConversation">Bon! Reviens me voir si jamais tu changes d'avis...</b>
        </Phrases>
      </Field>

      <Field type ="Explications">
        <Phrases>
          <a type="Page" action="GiveParchemin">Et bien c'est très simple tu n'as qu'à suivre les indications de ce parchemin!</a>
        </Phrases>
        <Answers>
          <a type = "Answer" goto="Derien">Merci!</a>
          <b type = "Answer" goto="PasMerci">Au revoir.</b>
          <c type = "Answer" goto="AuRevoir"> Merci! Bonne journée Monsieur!</c>
        </Answers>
      </Field>

      <Field type ="Derien">
        <Phrases>
          <a type="Page">Derien mon p'tit!</a>
        </Phrases>
        <Answers>
          <a type = "Anwser" goto="AuRevoir">Au revoir ^^!</a>
          <b type = "Answer" goto="Bus">A plus dans le bus!</b>
          <c type = "Answer" action="EndConversation"><b>J't'aime pas! Hors de ma vue!!</b></c>
        </Answers>
      </Field>

      <Field type="AuRevoir">
        <Phrases>
          <a type ="Page" action ="EndConversation">Au revoir mon p'tit!</a>
        </Phrases>
      </Field>

      <Field type="Bus">
        <Phrases>
          <a type="Page">Euhhh... C'est quoi un bus?</a>
        </Phrases>
        <Answers>
          <a type = "Answer">Euh... Non rien t'inquietes</a>
          <b type = "Answer">C'est une grosse voiture qui transporte plein de gens en même temps</b>
          <c type = "Answer">Bus? Excuse moi ma langue a fourchée... ^^' Je voulais dire <b>Bar</b></c>
        </Answers>
      </Field>

      <Field type="PasMerci">
        <Phrases>
          <a type = "Page" action="WillRemeber">Pas de merci?!</a>
          <b type = "Page" action="EndConversation">Ah... La jeunesse de nos jours...</b>
        </Phrases>
      </Field>

      <Field type="Recompences">
        <Phrases>
          <a type = "Page">Euhhh... Bonne question...</a>
          <b type = "Page">Et bien tu peux gagner la gloire et la reconnaissance des autres Slimes!</b>
        </Phrases>
      </Field>

      <Field type="Obviously">
        <Phrases>
          <a type ="Page">Mais bien sûr tu n'es pas unique!</a>
        </Phrases>
        <Answers>
          <a type = "Answer">Ce n'est pas très gentil de rabaisser les Slimes comme ça...</a>
          <b type = "Answer">Mais ça remet toute mon existence en question!?</b>
          <c type = "Answer" goto="AucuneReaction">Ah ok.</c>
        </Answers>
      </Field>

      <Field type="AucuneReaction">
        <Phrases>
          <a type ="Page">Attends je viens de te révéler que tu avais des millions de congénères et c'est ta seule réaction?</a>
        </Phrases>
        <Answers>
          <a type = "Answer">Bah ouais ça te pose un problème?</a>
          <b type = "Answer" goto="Serieux">Bah toi t'as des milliards de congénères et tu ne cries pas!</b>
        </Answers>
      </Field>

      <Field type="Serieux">
        <Phrases>
          <a type="Page">Attends tu connais d'autres humains!?</a>
        </Phrases>
        <Answers>
          <a type = "Answer">Euhhh... Oui...</a>
          <b type = "Answer" goto="Humain">Non c'est quoi un humain?</b>
          <c type = "Answer" goto="End">Mais bien sûr tu n'es pas unique!</c>
        </Answers>
      </Field>

      <Field type="Humain">
        <Phrases>
          <a type ="Page">Tu sais, c'est un truc comme moi avec des bras et des jambes</a>
        </Phrases>
        <Answers>
          <a type = "Answer" goto="PasGentil">Tu veux dire un con?</a>
          <b type = "Answer">Ah oui je vois</b>
          <c type = "Answer">C'est quoi des bras et des jambes</c>
        </Answers>
      </Field>

      <Field type="PasGentil">
        <Phrases>
          <a type="Page">C'est pas très très gentil <i>*snif*</i></a>
        </Phrases>
      </Field>

      <Field type="End">
        <Phrases>
          <a type = "Page">Ahah tu m'as eu!</a>
          <b type = "Page" action="GiveParchemin">Bon tout ça pour dire que si tu veux t'amuser avec tes congénères tu n'as qu'à lire ce parchemin...</b>
          <c type = "Page" action="EndConversation">Même si je ne comprends pas ce qu'il dit...</c>
        </Phrases>
      </Field>
    </Tuto1>

    <Retalk>
      <NottheBest>
        <Phrase>Hey petit Slime comment ça va depuis la dernière fois?</Phrase>
        <Answers type= "Answers">
          <a type = "Answer">Ca va et toi?</a>
          <b type = "Answer">Bah j'ai juste envie de m'immoler devant les locaux de Riot</b>
          <c type = "Answer">Je vais te tuer toi et toute ta famille. <b>FDP</b></c>
        </Answers>
      </NottheBest>

      <BestPlayer>
        <Phrase>Eh je te reconnais toi tu ne serais pas {{NAME}}, le Slime le plus rapide {{REGION}}</Phrase>
      </BestPlayer>
    </Retalk>
  </CowBoy>
</Discussion>

J’essaye maintenant de faire un système de bouton pour passer d’une ligne de dialogue a l’autre.
Mais jusque la je me servais juste du bouton ‘f’ du clavier mais pour les réponses multiples j’ai essayer
de faire dans un for(int i = 0; i < NombreDeReponses; i++) puis de, dans un premier temps Instantiate() mon bouton dans le canvas de mettre le texte que je veux ect…
puis de faire AnswerButton_Clone.GetComponent<Button>().onClick.AddListener(() => AnswerButtonClicked(Node.LastChild.ChildNodes, ((XmlElement)Node.LastChild.ChildNodes[NofAnswers - i - 1]), NofAnswers)) mais quand je fais ca le XmlElement est null dans ma fonction, et surtout peu importe sur quel boutons je clique ca me renvoie la même chose (le Deuxième Node) puis l’erreur NullReferenceException puisque le XmlElement et vide.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using System.Xml;

public class DialogueManager : MonoBehaviour
{
    public bool InDialogue = false;
    public GameObject Button;
    public TextReader TextReaderScript;
    XmlElement Node;
    int i;
    GameObject Clone_Button;
    public GameObject AnswerButton;
   
    void Update()
    {
        if (InDialogue == false && Input.GetKeyDown(KeyCode.F))
        {
            Node = TextReaderScript.TextGiver("Field", "type", "Begining");
            i = 0;
            InDialogue = true;
            DialogueBoxCreator(false);
            i++;
            return;
        }
        if (InDialogue == true && Input.GetKeyDown(KeyCode.F))
        {
            XmlElement xmlElement = (XmlElement)Node.FirstChild.ChildNodes[i-1];
            if (xmlElement.HasAttribute("goto"))
            {
                Node = TextReaderScript.TextGiver("Field", "type", xmlElement.GetAttribute("goto"));
            }
            if (xmlElement.HasAttribute("action"))
            {
                Action(xmlElement.GetAttribute("action"));
            }
            if (xmlElement == (XmlElement)Node.FirstChild.LastChild && Node.FirstChild != Node.LastChild)
            {
                Destroy(Clone_Button);
                DialogueBoxCreator(true, Node.LastChild.ChildNodes.Count);
                Debug.Log("Reponses");
                return;
            }
            if (xmlElement != (XmlElement)Node.FirstChild.ChildNodes[i])
            {
                Clone_Button.GetComponentInChildren<TextMeshProUGUI>().text = Node.FirstChild.ChildNodes[i].InnerXml;
                i++;
            }
        }
    }
    public void DialogueBoxCreator(bool Answer, int NofAnswers = 3)
    {
        if (Answer)
        {
            for (int i = 0; i < NofAnswers; i++)
            {
                GameObject AnswerButton_Clone = Instantiate(AnswerButton, FindObjectOfType<Canvas>().transform);
                RectTransform AnswerButton_RT = AnswerButton_Clone.GetComponent<RectTransform>();
                AnswerButton_Clone.GetComponentInChildren<TextMeshProUGUI>().text = Node.LastChild.ChildNodes[NofAnswers - i - 1].InnerXml;
                AnswerButton_RT.sizeDelta = new Vector2(AnswerButton_RT.rect.width, 200 / NofAnswers);
                AnswerButton_RT.anchoredPosition += new Vector2(0, 200 / NofAnswers * i);
                AnswerButton_Clone.name = "Answer " + Node.LastChild.ChildNodes[NofAnswers - i - 1].Name;
                AnswerButton_Clone.tag = "Answer";
                Debug.Log(NofAnswers - i - 1);
                Debug.Log(((XmlElement)Node.LastChild.ChildNodes[NofAnswers - i - 1]).GetAttribute("goto"));
                AnswerButton_Clone.GetComponent<Button>().onClick.AddListener(() => AnswerButtonClicked(Node.LastChild.ChildNodes, ((XmlElement)Node.LastChild.ChildNodes[NofAnswers - i - 1]), NofAnswers)) ;
            }
        }
        else
        {
            Clone_Button = Instantiate(Button, FindObjectOfType<Canvas>().transform);
            Clone_Button.GetComponentInChildren<TextMeshProUGUI>().text = Node.FirstChild.ChildNodes[i].InnerXml;
        }
    }
    void AnswerButtonClicked(XmlNodeList nodes, XmlElement element, int Answers)
    {
        for(int j = 0; j < Answers; j++)
            Destroy(GameObject.Find("Answer " + nodes[j].Name));
        if (element.HasAttribute("action"))
        {
            Action(element.GetAttribute("action"));
            Debug.Log("Done");
        }
        if (element.HasAttribute("goto"))
        {
            Debug.Log(element.GetAttribute("goto"));
            Node = TextReaderScript.TextGiver("Field", "type", element.GetAttribute("goto"));
            DialogueBoxCreator(false);
        }
    }

    void Action(string actionName)
    {
        switch (actionName)
        {
            case "EndConversation":
                InDialogue = false;
                Transform[] ListADetruire = FindObjectOfType<Canvas>().GetComponentsInChildren<Transform>();
                for (int i = 0; i < ListADetruire.Length; i++)
                    Destroy(ListADetruire[i]);
                break;
            case "GiveParchemin":
                Debug.Log("Parchemin");
                break;
        }
    }

}

Merci d’avance si vous répondez! ^^
Et si des choses vous choque dans mon code n’hésitez pas a me le dire! (je débute en code)

Ps: Merci de ne pas voler mes supers dialogues :')

Not sure what you’re trying to do exactly but I do recommend staying away from XML. In the year 2021 we traditionally use far simpler and robust data structures such as JSON.

You can use NewtonSoft JSON .NET to parse JSON reliably, and there are websites like JSON2CSharp and CSharp2JSON and JSONLint to help you shape your data appropriately.

Thx for the answer :slight_smile:

The probleme isn’t with the XML but the buttons
I’m trying to Instantiate buttons and listen to when they are clicked but I’m using a “for”
so when I’m trying to do this with more than one button that’s not working

Your code is very hard to process.

It’s not XML that’s the problem, but the fact that you’re mixing the XML parsing so tightly in with your game logic.

You should parse the XML out to some easy-to-digest objects that will be simpler for your game logic code to interact with.

Pardon moi, je ne parle pas tres bien français.

Ah so!

The above line is a problem: C# uses variable capture, not value capture. This means ALL your buttons will use the final value of i, not 0,1,2,3,4, etc.

Here is some writings about this phenomenon:

Delegate / Action variable capture / value capture:

https://discussions.unity.com/t/809602/2

I tried

int i2 = i;
AnswerButton_Clone.GetComponent<Button>().onClick.AddListener(() => AnswerButtonClicked(Node.LastChild.ChildNodes, ((XmlElement)Node.LastChild.ChildNodes[NofAnswers - i2 -1]), NofAnswers)) ;

but It’s working only for one button. Did I need to make i2 i3 i4? or I didn’t understand ?
Edit: Never Mind it’s working I just forgot to reset my global i x)

1 Like