Jump to content
Unity Insider Forum

Lernspiel: externen Fragenkatalog(XML) integrieren und damit interagieren


Jaimi93
 Share

Recommended Posts

Hallo 😄

Momentan arbeite ich an einem Lernspiel, welches Vokabeln spielerisch abfragen soll. Das Spiel besteht aus Jump´n´Run- und Frageteilen. Der Jump´n´Runteil funktioniert prima und die Menüs auch. Jetzt muss ich nur noch den schwierigsten Teil des Spiel programmieren: den Fragenteil. Ich habe mir überlegt, dass ich das Skript "ImportQuestions" für die Einbindung und Verarbeitung der externen XML-Datei und das Skript "QuestionInteraction" sich um die Darstellung und Interaktion mit dem Gamer kümmern soll. Bin trotzdem aber noch etwas ratlos, wie ich das in C# und Unity umsetzen kann.

Mein bisheriger Code in ImportQuestions:

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

public class ImportQuestions : MonoBehaviour
{
    //Import the txt file and save it in array
   
    //Path
    string sPath = "Assets/Questions/English.txt";
   
    //Array
    public int iQuestions;
    string[,] QuestionArray = new string[iQuestions, 4];

    void Start()
    {
        SetArrayQuestions();
    }
    
    public void SetArrayQuestions()
    {
        //Fill the array with the questions and answers
       
        //Read the file
        StreamReader reader = new StreamReader(sPath);
        
        //Save in arrays
        
        reader.Close();
    }

    public void GetArrayQuestions()
    {
        //Get the questions and anwers for the text field
    }

Das ich das Array nach der Anzahl der Fragen beliebig erweitern möchte, habe ich die Variable iQuestions eingeführt. Jedoch meckert Unity darüber.

 

Geplant ist, dass Fragen und Antworten wie folgt in der XML-Datei deklariert werden:

<Questions>
	<Q>
		<Word>Hello</Word>
		<Correct>Hallo</Correct>
		<Wrong1>Nein</Wrong1>
		<Wrong2>Hase</Wrong2>
	</Q>
</Questions>

 

Ich hoffe, dass ihr mir bei diesem Problem weiterhelfen könnt 😅

Vielen Dank im Voraus 😁

Edited by Jaimi93
XML statt txt-Datei
Link to comment
Share on other sites

vor 13 Stunden schrieb Jaimi93:

Jedoch meckert Unity darüber.

Bitte immer mitposten, was denn genau da steht. Das, was da steht, steht da ja nicht zum Spaß.

Warum hast du ein zweidimensionales Array? Ich hab das Gefühl, du willst eher ein zweites Array haben. Oder dein ursprüngliches Array größer machen. Im Moment machst du aber ein Array mit 4*iQuestion Elementen. Und das Problem, weswegen du Fehlermeldungen hast, ist: Du kannst ein Feld nicht mit einer anderen Variable direkt initialisieren.

Sprich: Statt

public int iQuestions;
string[,] QuestionArray = new string[iQuestions, 4];

void Start()
{
  SetArrayQuestions();
}

musst du das Array in Start() initialisieren, weil dann erst der Wert von iQuestions mit Sicherheit feststeht.

public int iQuestions;
string[,] QuestionArray;

void Start()
{
  QuestionArray = new string[iQuestions, 4];
  SetArrayQuestions();
}

Aber wie gesagt, du willst vermutlich sowieso kein zweidimensionales Array haben.

Link to comment
Share on other sites

  • Jaimi93 changed the title to Lernspiel: externen Fragenkatalog(XML) integrieren und damit interagieren

@Sascha Danke für Deine Antwort 😄

Am 9.6.2022 um 09:27 schrieb Sascha:

Bitte immer mitposten, was denn genau da steht.

Ok, werd ich beim nächsten Mal beachten 🙈

 

Am 9.6.2022 um 09:27 schrieb Sascha:

Warum hast du ein zweidimensionales Array?

Weil ich dachte, dass ich ein Array wie eine Tabelle mache, wo die Frage, richtige Antwort und beiden falschen Antworten drinstehen. Darum sollte es n-Zeilen haben und 4 Spalten. Die Anzahl der Zeilen sollten anhand der Länge des Fragenkataloges definiert werden. Zumindes habe ich mir das so gedacht. Zuerst hab ich mir auch gedacht, dass eine gute Idee wäre, wenn ich eine externe txt-Datei verwende. Hab dann aber festgestellt, dass es mit XML vielleicht einfacher geht. Aber ich glaub, ich denk wieder zu kompliziert... war würdest du anstatt einem Array verwenden?

Link to comment
Share on other sites

vor 23 Minuten schrieb Jaimi93:

Weil ich dachte, dass ich ein Array wie eine Tabelle mache, wo die Frage, richtige Antwort und beiden falschen Antworten drinstehen.

Verstehe, ist nachvollziehbar :)

Theoretisch geht das auch, aber du machst es dir damit schwerer als es sein muss. Arrays sind eher für gleichartige Elemente da. Also auch semantisch. Obwohl du da vier Strings hast, sind das ja eine Frage und drei Antworten.

vor 26 Minuten schrieb Jaimi93:

war würdest du anstatt einem Array verwenden?

Nene, ein Array ist schon gut, aber ein eindimensionales. Da packst du dann z.B. Structs rein.

public struct Question
{
  public string word;
  public string correct;
  public string wrong1;
  public string wrong2;
}

public Question[] questions;

Ist jetzt nur ein ganz stumpfes Beispiel, aber du siehst, wie es deinen XML-Code genau wiederspiegelt. Statt einer Tabelle ohne Überschriften hast du jetzt eine Liste von Fragen (wobei jede "Frage" aus deinen vier Strings besteht).

vor 31 Minuten schrieb Jaimi93:

Zuerst hab ich mir auch gedacht, dass eine gute Idee wäre, wenn ich eine externe txt-Datei verwende. Hab dann aber festgestellt, dass es mit XML vielleicht einfacher geht.

Geht alles. Letztenedes sind auch XML- (oder Json- oder Yaml-)Dateien nur Textdateien mit einem bestimmten Format drin. Ob du dieses Format selber erstellst oder ein Standardformat wie diese drei nimmst, gibt sich nicht viel.

Link to comment
Share on other sites

@Sascha Danke für deine Antwort. Sie hat mir sehr geholfen :D Ein paar Fragen habe ich dann aber noch. Ich hab im Internet einen Code gefunden der ein XML Dokument ausliest und frage mich, ob ich es mit deiner Lösung kombinieren kann:

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

[XmlRoot(ElementName = "Questions")]
public class ImportQuestions : MonoBehaviour
{
    //Import the XML File
    public TextAsset TxmlRawFile;

    [XmlType(TypeName = "Q")]
    public class CXmlItem
    {
        [XmlElement(ElementName = "Word")]
        public string sWord;

        [XmlElement(ElementName = "Correct")]
        public string sCorrect;

        [XmlElement(ElementName = "Wrong1")]
        public string sWrong1;

        [XmlElement(ElementName = "Wrong2")]
        public string sWrong2;
    }
    ...
  }

Wenn ich anstatt der Klasse in der Klasse das Struct verwende und dann ein Array erzeuge, würde es doch dann funktionieren, oder?

    ...
	[XmlType(TypeName = "Q")]
    public struct CXmlItem
    {
        [XmlElement(ElementName = "Word")]
        public string sWord;

        [XmlElement(ElementName = "Correct")]
        public string sCorrect;

        [XmlElement(ElementName = "Wrong1")]
        public string sWrong1;

        [XmlElement(ElementName = "Wrong2")]
        public string sWrong2;
    }

	public CXmlItem [] XmlItem;
	...

Oder erzeugt es automatisch dann ein Array oder Liste, wo alle Elemente gespeichert werden? Da ich diese Art der Deklaration davor noch nicht gesehen habe, verwirrt es mich etwas. (Außer bei der Defintion von einer Range. Aber das ist wahrscheinlich nicht das Gleiche...)

Link to comment
Share on other sites

Also langsam verzweifel ich ein bisschen. Ich hab ein Attribut (index) hinzugefügt und den kompletten Code von einem Tutorial auf YT übernommen (siehe ganz unten). Trotzem beschwert sich Unty: "'ImportQuestions' does not contain a definition for 'Questions' and no accessible extension method 'Questions' accepting a first argument of type 'ImportQuestions' could be found (are you missing a using directive or an assembly reference?)" und "'QuestionsStructure' does not contain a definition for 'index' and no accessible extension method 'index' accepting a first argument of type 'QuestionsStructure' could be found (are you missing a using directive or an assembly reference?)" Ich hab keine Ahnung, warum Unity die beiden Klassen nicht erkennt. Mit der foreach-Schleife möchte ich eigentlich nur prüfen, ob das Einbinden der Datei funktioniert hat 😓

Der Code, wo Unity ein Probelm damit hat:

public class QuestionInteraction : MonoBehaviour
{
	...
    //String for the XML document ele Q
    public const string sPath = "Questions";

    // Start is called before the first frame update
    void Start()
    {
        ImportQuestions IQ = ImportQuestions.Load(sPath);
        foreach(QuestionsStructure Q in IQ.Questions)
        {
            UnityEngine.Debug.Log(Q.index);        }
    }
  ...
}

Die Klassen ImportQuestions und QuestionStructure sind in jeweils seperaten Dateien definiert:

[XmlRoot(ElementName = "QuestionCollector")]
public class ImportQuestions
{
    [XmlArray("Questions")]
    [XmlArrayItem("Q")]
    public List<QuestionsStructure> items = new List<QuestionsStructure>();

    public static ImportQuestions Load(string sPath)
    {
        TextAsset _xmlFile = AssetDatabase.LoadAssetAtPath<TextAsset>("Assets/XML/Questions.xml");
        XmlSerializer serializer = new XmlSerializer(typeof(ImportQuestions));
        StringReader reader = new StringReader(_xmlFile.text);
        ImportQuestions item = serializer.Deserialize(reader) as ImportQuestions;
        reader.Close();
        return item;
    }
}

 

public class QuestionsStructure
{
        [XmlAttribute("index")]
        public int iIndexQuestion;

        [XmlElement("Word")]
        public string sWord;

        [XmlElement("Correct")]
        public string sCorrect;

        [XmlElement("Wrong1")]
        public string sWrong1;

        [XmlElement("Wrong2")]
        public string sWrong2;
}

Quelle des YT Videos:

 

Link to comment
Share on other sites

Hab den Fehler gefunden. Weil im Tutorial viele Variablen, Datentypen und Dateinnamen gleich sind, hab ich ein paar Dinge verwechselt. Das Verküpfen und Einlesen der XML Datei funktionieren jetzt 🥳

 void Start()
    {
        ImportQuestions IQ = ImportQuestions.Load(sPath);

        //For each item in the List "item"
        foreach(QuestionsStructure Q in IQ.items)
        {
            //UnityEngine.Debug.Log(Q.index);
            print(Q.iIndexQuestion);
        }
    }

 

[XmlRoot("QuestionCollector")]
public class ImportQuestions
{
    [XmlArray("Questions")]
    [XmlArrayItem("Q")]
    public List<QuestionsStructure> items = new List<QuestionsStructure>();

    public static ImportQuestions Load(string sPath)
    {
        TextAsset _xmlFile = AssetDatabase.LoadAssetAtPath<TextAsset>("Assets/XML/Questions.xml");
        XmlSerializer serializer = new XmlSerializer(typeof(ImportQuestions));
        StringReader reader = new StringReader(_xmlFile.text);
        ImportQuestions item = serializer.Deserialize(reader) as ImportQuestions;
        reader.Close();
        return item;
    }
}

 

  • Like 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

×
×
  • Create New...