JS Text-Adventure Spiel


Benkho

Grünschnabel
Guten Abend,
ich habe angefangen Medieninformatik zu studieren und wir müssen ein JS Browsergame als Semesterarbeit programmieren.
Wir haben uns für ein Text-Adventure Spiel entschieden. Soweit so gut, ich habe auch die ersten Anfänge von dem Spiel programmiert komme aber nicht weiter, da ich leider nicht weis wie ich Bilder in das Script bekomme. Ich habe wirklich schon sehr viel ausprobiert aber leider ohne Erfolg.

Der HTML Code:
HTML:
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <link href="styles.css" rel="stylesheet">
        <script defer src="game.js"></script>
        <title>Bank robbery</title>
    </head>
    <body style="background-image: url('img/background.png');">
        <div class="container">
            <div id="text">Text</div>
            <div id="option-buttons" class="btn-grid">
                <button class="btn">Option 1</button>
                <button class="btn">Option 2</button>
                <button class="btn">Option 3</button>
                <button class="btn">Option 4</button>
            </div>
        </div>
    </body>
</html>
Der JS Code:
Javascript:
let textElement = document.getElementById('text')
let optionButtonsElement = document.getElementById('option-buttons')

function startGame() {
    showTextNode(1)
}

function showTextNode(textNodeIndex) {
  let textNode = textNodes.find(textNode => textNode.id === textNodeIndex)
  textElement.innerText = textNode.text
  while (optionButtonsElement.firstChild) {
    optionButtonsElement.removeChild(optionButtonsElement.firstChild)
  }

  textNode.options.forEach(option => {
    if (showOption(option)) {
      let button = document.createElement('button')
      button.innerText = option.text
      button.classList.add('btn')
      button.addEventListener('click', () => selectOption(option))
      optionButtonsElement.appendChild(button)
    }
  })
}

function showOption(option) {
  return option.requiredState == null
}

function selectOption(option) {
  let nextTextNodeId = option.nextText
  if (nextTextNodeId <= 0) {
    return startGame()
  }
  showTextNode(nextTextNodeId)
}

let textNodes = [
  {
    id: 1,
    text: 'Wollen Sie Wirklich eine Bank ausrauben?',
    options: [
      {
        text: 'Ja',
        nextText: 2
      },
      {
        text: 'Nein',
        nextText: 3
      }
    ]
  },
  {
    id: 2,
    text: 'You venture forth in search of answers to where you are when you come across a merchant.',
    options: [
      {
        text: 'Trade the goo for a sword',
        nextText: 3
      },
      {
        text: 'Trade the goo for a shield',
        nextText: 3
      },
      {
        text: 'Ignore the merchant',
        nextText: 3
      }
    ]
  },
  {
    id: 3,
    text: 'Sie wollen die Bank nicht ausrauben. Bitte starten Sie das Spiel erneut',
    options: [
      {
        text: 'Neustart',
        nextText: -1
      }
    ]
  }
]

startGame()
Die Bilder sollen passend zu der ID erscheinen, also immer wenn man weiter klickt kommt man ja auf eine neue ID und dort soll dann auch ein neues Bild erscheinen.

Ich hoffe ihr könnt mir weiterhelfen.

Liebe Grüße
Julian
 

basti1012

Erfahrenes Mitglied
könntest du das mal etwas genauer erklären was da passieren soll?
Ich verstehe gerade nicht was du mit id und Bild meinst.

Bis jetzt scheint ja alles zu klappen.
Soll das so weiter gehen ?
Also zb 10 Fragen und bei 10 Fragen wieder mehrere Antworten ?
Falls ja sollte man da vieleicht auch auf andere möglichen zurückgreifen ( zb Php ) falls das mal mehr 100 Fragen oder so werden sollen.
Falls es JS bleiben soll könnte eine externe json datei dann auch den überblick vereinfachen
 
Zuletzt bearbeitet:

ComFreek

Mod | @comfreek
Moderator
Du kannst in deinem Skript übrigens jedes "let" durch "const" ersetzen. Das gilt i. Allg. als besserer Coding Style, weil defensiver gegenüber Veränderungen.
 

Benkho

Grünschnabel
könntest du das mal etwas genauer erklären was da passieren soll?
Ich verstehe gerade nicht was du mit id und Bild meinst.

Bis jetzt scheint ja alles zu klappen.
Soll das so weiter gehen ?
Also zb 10 Fragen und bei 10 Fragen wieder mehrere Antworten ?
Falls ja sollte man da vieleicht auch auf andere möglichen zurückgreifen ( zb Php ) falls das mal mehr 100 Fragen oder so werden sollen.
Falls es JS bleiben soll könnte eine externe json datei dann auch den überblick vereinfachen
Hallo,
kann ich gerne machen.
Ja, es klappt bislang alles so wie ich es möchte. Genau wir haben halt eine Story, wo halt sowas wie Willst du das Spiel wirklich spielen und mann dort Ja oder Nein aussichen kann. Daraufhin wird eine neue Id aufgerufen, wo die Story dann weiter erklärt wird und man wieder weitere auswahl möglichkeiten hat. Sind aber nur 15-20 Schritte die man gehen kann. Wir haben für jede ID einen eigenen Text verfasst und ein Bild angefertig. Der Text und die Antworten ändern sich ja schon, wenn man eine neue Id über die Antworten aufruft. Jetzt muss allerding noch das ich ein Bild jeder ID zuordne und sich dann auch mit verändern. Also ID:2 wird aufgerufen und neuer Text, neue antwort Möglichkeiten und neues Bild.

Ich hoffe, ich konnte es einigermaßen verständlich erklären.

Liebe Grüße
Julian
 

Benkho

Grünschnabel
Guten Tag,

hat keiner eine Lösung für mich? Es wäre wirklich wichtig für mich.

Mit freundlichem Gruß
Julian
 

Sempervivum

Erfahrenes Mitglied
Du brauchst nur in deiner Config-Struktur die URL des Bilder hinzuzufügen:
Code:
const textNodes = [
  {
    id: 1,
    text: 'Wollen Sie Wirklich eine Bank ausrauben?',
    options: [
      {
        text: 'Ja',
        nextText: 2
      },
      {
        text: 'Nein',
        nextText: 3
      }
    ],
    img: 'images/img-for-node-1.jpg'
  },
und dann an der geeigneten Stelle anzuzeigen:
Code:
function showTextNode(textNodeIndex) {
  let textNode = textNodes.find(textNode => textNode.id === textNodeIndex)
  textElement.innerText = textNode.text
  while (optionButtonsElement.firstChild) {
    optionButtonsElement.removeChild(optionButtonsElement.firstChild)
  }

  textNode.options.forEach(option => {
    if (showOption(option)) {
      let button = document.createElement('button')
      button.innerText = option.text
      button.classList.add('btn')
      button.addEventListener('click', () => selectOption(option))
      optionButtonsElement.appendChild(button)
    }
  });
  const im = document.createElement('img');
  // usw.
}
 

Benkho

Grünschnabel
Javascript:
function showTextNode(textNodeIndex) {
  const textNode = textNodes.find(textNode => textNode.id === textNodeIndex)
  textElement.innerText = textNode.text
  while (optionButtonsElement.firstChild) {
    optionButtonsElement.removeChild(optionButtonsElement.firstChild)
  }

  textNode.options.forEach(option => {
    if (showOption(option)) {
      const image = document.createElement('image')
      const button = document.createElement('button')
      button.innerText = option.text
      button.classList.add('btn')
      button.addEventListener('click', () => selectOption(option))
      optionButtonsElement.appendChild(button)
    }
  })
}

function showOption(option) {
  return option.requiredState == null
}

function selectOption(option) {
  const nextTextNodeId = option.nextText
  if (nextTextNodeId <= 0) {
    return startGame()
  }
  showTextNode(nextTextNodeId)
}

const textNodes = [
  {
    id: 1,
    image: 'img/Auswahl_2.png',
    text: 'Wollen Sie Wirklich eine Bank ausrauben?',
    options: [
      {
        text: 'Ja',
        nextText: 2
      },
      {
        text: 'Nein',
        nextText: 3
      }
    ]
  },
Guten Tag,
vielen Dank für die schnelle Antwort aber leider klappt das bei mir irgendwie nicht. Ich weis leider nicht wieso.
 

Sempervivum

Erfahrenes Mitglied
Ich hatte angenommen, dass Du das img-Element dynamisch anlegen musst, aber wie ich sehe ist das gar nicht erforderlich:
Im HTML das img-Tag einfügen:
Code:
        <div class="container">
            <img id="image">
            <div id="text">Text</div>
            <div id="option-buttons" class="btn-grid">
                <button class="btn">Option 1</button>
                <button class="btn">Option 2</button>
                <button class="btn">Option 3</button>
                <button class="btn">Option 4</button>
            </div>
        </div>
und im Javascript das src-Attribut zuweisen:
Code:
// zunaechst das Element fuer das Bild bereit stellen:
const imgElement = document.getElementById ('image');
const textElement = document.getElementById('text')
const optionButtonsElement = document.getElementById('option-buttons')

// und dann weiter unten das src-Attribut zuweisen:
function showTextNode(textNodeIndex) {
  const textNode = textNodes.find(textNode => textNode.id === textNodeIndex)
  textElement.innerText = textNode.text
  imgElement.src = textNode.image; // <-- hier
  while (optionButtonsElement.firstChild) {
    optionButtonsElement.removeChild(optionButtonsElement.firstChild)
  }

  textNode.options.forEach(option => {
    if (showOption(option)) {
      const image = document.createElement('image')
      const button = document.createElement('button')
      button.innerText = option.text
      button.classList.add('btn')
      button.addEventListener('click', () => selectOption(option))
      optionButtonsElement.appendChild(button)
    }
  })
}
 

Benkho

Grünschnabel
Guten Abend,

eine Frage habe ich noch. Wie kann ich in der folgenden Stelle ein weiteres kleines Minigame starten? Dabei muss berücksichtigt werden können, wenn das Game gewonnen wurde kommt man weiter und wenn nicht kommt man direkt wieder zum Anfang.

Javascript:
{
        text: 'Ja',
        nextText: 2
      },
 

Sempervivum

Erfahrenes Mitglied
Das würde ich so lösen: Du hast ja diese Struktur
Code:
let textNodes = [
  { // usw.
die die gesamten Daten des Spiels enthält. Lege für jedes Spiel eine eigene Struktur an, z. B. textNodes1 und textNode2 und weise die der allgemeinen Variablen textNodes zu, also vor dem Beginn des ersten Spiels:
Code:
let textNodes = textNodes1;
startGame()
und dann wenn das nächste Spiel gestartet werden soll ebenso:
Code:
let textNodes = testNodes2;
startGame()
Damit das ganze auch mit noch mehr Spielen funktioniert, schlage ich vor, die Referenz des nächsten Spiels jeweils in die Datenstruktur einzutragen, etwa so:
Code:
    id: 10,
    text: 'Sie haben dieses Spiel gewonnen! Möchten Sie es noch einmal spielen oder mit dem nächsten beginnen?',
    options: [
      {
        text: 'Neustart',
        nextText: -1,
        nextGame: textNodes1
      },
      {
        text: 'Nächstes Spiel',
        nextText: -1
        nextGame: textNodes2
      }
    ]
  }
]
ungefähr so.
 
Zuletzt bearbeitet:

Neue Beiträge