{
  "name": "Spielwerkstatt: nach Objektorientierung",
  "settings": {
    "language": "Java",
    "libraries": [
      "scratch",
      "nrw"
    ]
  },
  "modules": [
    {
      "name": "Welt.java",
      "text": "/// Deine Spielwelt. Hier stellst du alles auf, was im Spiel vorkommt.\npublic class Welt extends Spielwelt {\n\n   /// So viele Münzen hat der Spieler schon eingesammelt.\n   private int punkte = 0;\n   /// So viele Münzen liegen insgesamt in der Welt.\n   private int anzahlMuenzen = 0;\n   /// So oft darf ein Gegner den Spieler noch erwischen.\n   private int leben = 3;\n   /// Hier steht der Spieler am Anfang und nach jedem Treffer.\n   private double startX;\n   private double startY;\n   /// So viele Sekunden bleiben noch.\n   private double zeit = 30;\n   /// Solange das true ist, läuft das Spiel noch.\n   private boolean laeuft = true;\n   /// Die Anzeige oben links.\n   private Text anzeige;\n   /// Die Spielfigur. Sie ist eine Variable der Welt, damit run() sie anhalten kann.\n   private Spieler held;\n\n   /// Der Plan der Welt: jede Zeichenkette eine Zeile, jedes Zeichen ein Feld von 48 × 48 Pixeln.\n   /// `#` Stein, `B` Baum, `T` Tanne, `F` Fels, `M` Münze, `G` Gegner, `S` Start, `.` Wiese\n   private String[] plan = {\n      \"################\",\n      \"#S.....M.......#\",\n      \"#..B.......F...#\",\n      \"#......M.......#\",\n      \"#.M.....T....M.#\",\n      \"#.........G....#\",\n      \"#..M..B....M...#\",\n      \"#..G......M....#\",\n      \"################\"\n   };\n\n   public Welt() {\n      held = new Spieler(\"boy\");\n\n      for (int z = 0; z < plan.length; z++) {\n         for (int s = 0; s < plan[z].length(); s++) {\n            char zeichen = plan[z].charAt(s);\n            double x = this.zuX(s);\n            double y = this.zuY(z);\n            if (zeichen == '#') {\n               this.setze(new Stein(), x, y);\n            } else if (zeichen == 'B') {\n               this.setze(new Pflanze(0, 0), x, y);\n            } else if (zeichen == 'T') {\n               this.setze(new Pflanze(32, 0), x, y);\n            } else if (zeichen == 'F') {\n               this.setze(new Pflanze(256, 128), x, y);\n            } else if (zeichen == 'M') {\n               this.setze(new Muenze(), x, y);\n               anzahlMuenzen = anzahlMuenzen + 1;\n            } else if (zeichen == 'G') {\n               this.setze(new Gegner(), x, y);\n            } else if (zeichen == 'S') {\n               startX = x;\n               startY = y;\n               held.setPosition(x, y);\n            }\n         }\n      }\n\n      anzeige = new Text(\"\", 0, 200, 700);\n      anzeige.setTextSize(20);\n      anzeige.setTextColor(255, 255, 255);\n      this.add(anzeige);\n\n      this.add(held);\n   }\n\n   /// Die x-Koordinate der Mitte von Spalte pSpalte. Spalte 0 liegt ganz links.\n   private double zuX(int pSpalte) {\n      return -360 + pSpalte * 48;\n   }\n\n   /// Die y-Koordinate der Mitte von Zeile pZeile. Zeile 0 liegt ganz oben.\n   private double zuY(int pZeile) {\n      return 192 - pZeile * 48;\n   }\n\n   /// Stellt pFigur an die Stelle (pX, pY) auf die Bühne.\n   private void setze(Sprite pFigur, double pX, double pY) {\n      pFigur.setPosition(pX, pY);\n      this.add(pFigur);\n   }\n\n   /// Liefert true, wenn alle Münzen eingesammelt sind.\n   private boolean istGewonnen() {\n      return punkte == anzahlMuenzen;\n   }\n\n   /// Hält das Spiel an und zeigt pMeldung an.\n   private void beende(String pMeldung) {\n      laeuft = false;\n      held.setTempo(0);\n      anzeige.showText(pMeldung);\n   }\n\n   /// Wird jedes Mal ausgeführt, wenn der Spieler eine Münze einsammelt.\n   public void wennMuenzeEingesammelt() {\n      punkte = punkte + 1;\n   }\n\n   /// Wird jedes Mal ausgeführt, wenn ein Gegner den Spieler berührt.\n   public void wennGegnerBeruehrt() {\n      if (laeuft) {\n         leben = leben - 1;\n         held.setPosition(startX, startY);\n         if (leben == 0) {\n            this.beende(\"Kein Leben mehr! \" + punkte + \" von \" + anzahlMuenzen + \" Münzen.\");\n         }\n      }\n   }\n\n   /// Wird immer wieder ausgeführt, etwa 60-mal in der Sekunde.\n   public void run() {\n      if (laeuft) {\n         zeit = zeit - 1.0 / 60;\n\n         if (this.istGewonnen()) {\n            this.beende(\"Gewonnen! Noch \" + (int) zeit + \" Sekunden übrig.\");\n         } else if (zeit <= 0) {\n            this.beende(\"Die Zeit ist um! \" + punkte + \" von \" + anzahlMuenzen + \" Münzen.\");\n         } else {\n            anzeige.showText(\"Münzen: \" + punkte + \" von \" + anzahlMuenzen + \"   Leben: \" + leben + \"   Zeit: \" + (int) zeit);\n         }\n      }\n   }\n}\n"
    },
    {
      "name": "Main.java",
      "text": "/// Startet das Spiel.\nvoid main() {\n   // Pixelgrafik bleibt beim Vergrößern scharf.\n   Window.useTextureSampling(TextureSampling.POINT);\n   Window fenster = new Window(768, 432);\n   fenster.setStage(new Welt());\n}\n"
    },
    {
      "name": "Gegner.java",
      "text": "/// Ein Schleim, der hin und her kriecht. Stößt er an ein Hindernis, kehrt er um.\npublic class Gegner extends AnimatedSprite {\n\n   /// So viele Pixel kriecht der Schleim in jedem Bild, nach rechts positiv, nach links negativ.\n   private int tempo = 2;\n\n   public Gegner() {\n      this.addAnimation(\"kriechen\", \"assets/actor/monster/slime/slime.png\", 4, 16, 16, 0, true);\n      this.setAnimationInterval(200);\n      this.setSize(250);\n      // Nur die Füße zählen: So kann die Figur vor einem Baum stehen, ohne an ihm hängen zu bleiben.\n      this.setHitbox(4, 10, 12, 10, 12, 16, 4, 16);\n   }\n\n   public void run() {\n      this.playAnimation(\"kriechen\");\n      this.changeX(tempo);\n      if (this.getTouchingSprite(Hindernis.class) != null) {\n         this.changeX(-tempo);\n         tempo = -tempo;\n      }\n   }\n}\n"
    },
    {
      "name": "Hindernis.java",
      "text": "/// Fertig für dich: eine Figur, durch die der Spieler nicht hindurchlaufen kann.\n/// Ein Hindernis ist ein Sprite wie jedes andere. Sein Kostüm gibst du ihm selbst.\npublic class Hindernis extends Sprite {\n\n   public Hindernis() {\n      // Die Bilder sind winzig. Dreifach vergrößert passen sie zum Spieler.\n      this.setSize(300);\n   }\n\n   /// Wie addCostume von Sprite. Zusätzlich hält nur die untere Hälfte des Bildes auf,\n   /// also der Stamm eines Baums oder der Fuß eines Felsens. Hinter dem Rest kann man vorbeigehen.\n   public void addCostume(String pName, String pBild, int pX, int pY, int pBreite, int pHoehe) {\n      super.addCostume(pName, pBild, pX, pY, pBreite, pHoehe);\n      this.setHitbox(0, pHoehe / 2.0, pBreite, pHoehe / 2.0, pBreite, pHoehe, 0, pHoehe);\n   }\n}\n"
    },
    {
      "name": "Muenze.java",
      "text": "/// Fertig für dich: eine Münze, die sich dreht, bis der Spieler sie einsammelt.\npublic class Muenze extends AnimatedSprite {\n\n   public Muenze() {\n      // Vier Bilder zu je 10 × 10 Pixeln nebeneinander.\n      this.addAnimation(\"drehen\", \"assets/items/treasure/coin2.png\", 4, 10, 10);\n      this.setAnimationInterval(150);\n      this.setSize(300);\n   }\n\n   public void run() {\n      this.playAnimation(\"drehen\");\n   }\n}\n"
    },
    {
      "name": "Pflanze.java",
      "text": "/// Eine große Pflanze oder ein Felsen, 32 × 32 Pixel aus dem Natur-Kachelbild.\n/// pBildX und pBildY geben die linke obere Ecke im Kachelbild an.\npublic class Pflanze extends Hindernis {\n\n   public Pflanze(int pBildX, int pBildY) {\n      this.addCostume(\"pflanze\", \"assets/backgrounds/tilesets/tileset-nature.png\", pBildX, pBildY, 32, 32);\n   }\n}\n"
    },
    {
      "name": "Spieler.java",
      "text": "/// Die Figur, die du mit den Pfeiltasten steuerst.\n/// Sie bleibt an Hindernissen hängen, sammelt Münzen ein und meldet der Welt, wenn ein Gegner sie erwischt.\npublic class Spieler extends AnimatedSprite {\n\n   /// So viele Pixel geht der Spieler in jedem Bild.\n   private int tempo = 3;\n\n   /// Erzeugt einen Spieler. pFigur ist ein Ordner in assets/actor/character/, zum Beispiel \"boy\".\n   public Spieler(String pFigur) {\n      String bild = \"assets/actor/character/\" + pFigur + \"/sprite-sheet.png\";\n      // Im Bild steht jede Blickrichtung in einer eigenen Spalte,\n      // die vier Schritte untereinander.\n      this.addAnimation(\"unten\", bild, 4, 16, 16, 0, true);\n      this.addAnimation(\"oben\", bild, 4, 16, 16, 1, true);\n      this.addAnimation(\"links\", bild, 4, 16, 16, 2, true);\n      this.addAnimation(\"rechts\", bild, 4, 16, 16, 3, true);\n      this.setAnimationInterval(150);\n      this.setSize(250);\n      // Nur die Füße zählen: So kann die Figur vor einem Baum stehen, ohne an ihm hängen zu bleiben.\n      this.setHitbox(4, 10, 12, 10, 12, 16, 4, 16);\n      this.addSound(\"muenze\", \"assets/audio/sounds/bonus/coin.ogg\");\n   }\n\n   public void run() {\n      double altX = this.getX();\n      double altY = this.getY();\n\n      if (this.isKeyPressed(KeyCode.RIGHT)) {\n         this.changeX(tempo);\n         this.playAnimation(\"rechts\");\n      } else if (this.isKeyPressed(KeyCode.LEFT)) {\n         this.changeX(-tempo);\n         this.playAnimation(\"links\");\n      } else if (this.isKeyPressed(KeyCode.UP)) {\n         this.changeY(tempo);\n         this.playAnimation(\"oben\");\n      } else if (this.isKeyPressed(KeyCode.DOWN)) {\n         this.changeY(-tempo);\n         this.playAnimation(\"unten\");\n      }\n\n      // In ein Hindernis hineingelaufen? Dann zurück auf den alten Platz.\n      if (this.getTouchingSprite(Hindernis.class) != null) {\n         this.setPosition(altX, altY);\n      }\n\n      Muenze m = this.getTouchingSprite(Muenze.class);\n      if (m != null) {\n         m.remove();\n         this.playSound(\"muenze\");\n         Welt welt = (Welt) this.getStage();\n         welt.wennMuenzeEingesammelt();\n      }\n\n      if (this.getTouchingSprite(Gegner.class) != null) {\n         Welt welt = (Welt) this.getStage();\n         welt.wennGegnerBeruehrt();\n      }\n   }\n\n   /// Legt fest, wie viele Pixel der Spieler in jedem Bild geht. Mit 0 bleibt er stehen.\n   public void setTempo(int pTempo) {\n      tempo = pTempo;\n   }\n}\n"
    },
    {
      "name": "Spielwelt.java",
      "text": "/// Fertig für dich: die Wiese als Hintergrund und die Reihenfolge, in der gezeichnet wird.\npublic class Spielwelt extends Stage {\n\n   /// So viele Pixel ist eine Kachel auf der Bühne breit und hoch.\n   public static final int KACHEL = 48;\n\n   public Spielwelt() {\n      // Die Wiese ist ein einziges Bild, so groß wie die Bühne.\n      this.addBackdrop(\"wiese\", \"assets/backgrounds/wiese.png\");\n\n      // Wer weiter unten steht, ist näher am Betrachter: Er wird später gezeichnet\n      // und verdeckt, was hinter ihm steht. So läuft man hinter Bäumen vorbei.\n      this.getSorting().byY();\n   }\n}\n"
    },
    {
      "name": "Stein.java",
      "text": "/// Ein Stein für Mauern, 16 × 16 Pixel aus dem Dungeon-Kachelbild.\npublic class Stein extends Hindernis {\n\n   public Stein() {\n      this.addCostume(\"stein\", \"assets/backgrounds/tilesets/tileset-dungeon.png\", 128, 48, 16, 16);\n   }\n}\n"
    }
  ]
}
