archiv:ef:ef2020_2022:minecraft:projekt:maximandrin:start

Tetris in Minecraft

Die Idee Tetris in Minecraft zu erstellen kam ziemlich spontan. Nachdem wir den Auftrag bekommen hatten, ein Projekt in Minecraft zu realisieren, war unsere erste Idee, innerhalb vom Spiel einen sehr simplen Computer zu programmieren, auf dem man ein sehr simples Spiel spielen kann. Da Tetris ein einfaches Konzept hat, und mit der Zeit zu einem Klassiker geworden ist, dachten wir, dass Tetris des perfekte Spiel dafür ist. Um das Projekt etwas einfacher zu machen, liessen wir das mit dem Computer bleiben und erstellten nur das Spiel selber.

Das Prinzip von Tetris ist ganz einfach. Vom oberen Rand des Bildschirms fallen vorbestimmte Formen, sogenannte Tetrominos, welche liegen bleiben, sobald sie Kontakt mit etwas unter ihnen haben. Das Spielbrett ist 2-dimensional und in beiden Dimensionen räumlich begrenzt. Wenn eine horizontale Reihe vollständig ausgefüllt ist, verschwindet diese, und alle Blöcke darüber senken sich um eine Ebene, um die entstandene Lücke aufzufüllen. Sobald eine vertikale Reihe vollständig ausgefüllt ist, ist das Spiel vorbei, und man hat verloren. Das Ziel ist es, so lange wie möglich im Spiel zu bleiben. Um das zu erreichen, kann man die Formen, welche von oben fallen, horizontal bewegen und drehen, immer jeweils um 90°.

Beim normalen Tetris ist die Kontrolle der Blöcke auf Tasten belegt. Da dies innerhalb von einem anderen Spiel jedoch sehr schwierig umzusetzen war, haben wir die Kontrolle der Blöcke mit den Bewegungen des Spielers verbunden. So bewegen sich die Blöcke nach rechts, wenn der Spieler nach rechts geht und nach links wenn der Spieler nach links geht. Bewegt sich der Spieler nach vorne, dreht sich die Form gegen den Uhrzeigersinn, bewegt man sich nach hinten, mit dem Uhrzeigersinn. Damit sich der Spieler nicht vom Spielbrett entfernt, wird dieser in einem Zaun eingeschlossen, und nach jeder Bewegung zurück zum Startpunkt teleportiert.

Kompletter Quellcode zum Kopieren

Dieser Quellcode muss in den Code-Editor kopiert und gestartet werden. Das Spiel beginnt nicht sofort, es besteht also kein Grund zur Eile. Falls ein Fehler wie „unexpected indent“ oder „inconsistent indentation“ angezeigt wird, haben wir hier den Quellcode ohne Formatierung. Um ihn zu Kopieren kann man in der Seitenleiste auf „Seite bearbeiten“ clicken, dann auf den Text clicken und dann mit „control“ + „A“ und + „C“ auf Windows oder „command“ + „A“ und + „C“ auf Mac alles auswählen und kopieren. Um danach hierher zurückzugelangen, kann man in der auf „Links hierher“ klicken.

Um das optimale Spielerlenis zu geniessen, empfehlen wir den Autojump abzuschalten. Dieser befindet sich in den Einstellungen (Escape Taste) unter „Einstellungen“, „Tastatur und Maus“, „Automatisches Springen“. Ebenfalls empfiehlt es sich das HUD auszublenden, unter „Einstellungen“, „Grafik“, „HUD Ausblenden“, damit der Chat nicht stört. Man kann auch das Blickfeld vergrössern, unter „Einstellungen“, „Grafik“, „Sichtfeld“.

Die Steuerung für unser Spiel lautet wie folgt:

Tastaturbefehl Funktion
W Gegen den Uhrzeigersinn drehen
A Nach links schieben
S Im Uhrzeigersinn drehen
D Nach rechts schieben
Shift Plazieren (ganz nach unten)
„Start“ im Chat Spiel starten
„Stop“ im Chat Spiel anhalten

Das momentane Spielfeld wird in der 2-Dimensionalen Liste Board gespeichert. 1 steht jeweils für einen Block und 0 für keinen. So wird auch das momentane Tetromino in der Liste piece gespeichert. Wenn nun das Tetromino bewegt werden soll, wird zuerst piece bewegt, dann wird überprüft, ob es Überschneidungen gibt, und danach werden erst die Blöcke auf dem Bildschirm verändert. Es werden auch jeweils nur diejenigen Blöcke verändert, bei denen es notwendig ist. Wir haben uns für diese Vorgehensweise entschieden, damit möglichst Wenig Kommunikation zwischen dem Code und der Minecraft Welt stattfinden muss. Diese ist sehr langsam und zu viel davon würde das Spiel unspielbar machen.

Wir haben uns entschieden diese Variablen als globale Variablen zu speichern. So können sie in jeder Funktion verwendet werden, solange man sie an deren Anfang so deklariert. Dafür verwendet man die Kennzeichnung global und danach den Variabelnamen. Ganz zu Beginn des Quellendes werden alle Globalen Variablen ausserhalb einer Funktion deklariert:

#Globale Variabeln initiieren

#Nach Präferenz ändern:
w = 0
h = 0
playerY = 3
playerZ = 20
buildGlass = True

#Nicht ändern:
board = [[0]]
piece = [[0]]
pieceX = 0
pieceY = 0
color = DIAMOND_BLOCK
isRunning = False
origin = player.position()
score = 0
unusedPieces = range(7)

Um die Spielkonsole zu bauen, wird beim Starten des Spieles die Funktion makeBoard() abgerufen. Sie baut die Plattform, auf der der Spieler steht, und die einzelnen Elemente der Spielkonsole. Weil das Glas nicht komplett durchsichtig ist, kann man das Bauen dieses ausschalten, in dem man am Anfang des Codes buildGlass auf False stellt. Der Boden der Plattform besteht aus dem Block „Scaffolding“, weil darin der Spieler einsinkt, sobald er Schleicht, wodurch wir Schleichen auch für die Steuerung verwenden konnten.

def makeBoard(w, h):
    global playerY
    global playerZ
    global buildGlass
    
    #Plattform bauen
    blocks.fill(GLASS, pos(-1, -2, -1), pos(1, -2, 1))
    blocks.fill(blocks.block_by_name("scaffolding"), pos(-1, -1, -1), pos(1, -1, 1))
    blocks.fill(GLASS_PANE, pos(-1, 0, -1), pos(1, 0, -1))
    blocks.fill(GLASS_PANE, pos(-1, 0, 1), pos(1, 0, 1))
    blocks.place(GLASS_PANE, pos(-1, 0, 0))
    blocks.place(GLASS_PANE, pos(1, 0, 0))
    
    #Bildschirm bauen
    n = Math.round(w / 2)
    o = Math.round(w/2%1)
    blocks.fill(BLACK_CONCRETE, pos(-n, -playerY, playerZ+1), pos(n+o, h-playerY, playerZ+1))
    blocks.fill(POLISHED_ANDESITE, pos(-n-1, -1-playerY, playerZ+1), pos(-n-1, h+1-playerY, playerZ-1))
    blocks.fill(POLISHED_ANDESITE, pos(n+o+1, -1-playerY, playerZ+1), pos(n+o+1, h+1-playerY, playerZ-1))
    blocks.fill(POLISHED_ANDESITE, pos(-n-1, -1-playerY, playerZ+1), pos(n+o+1, -1-playerY, playerZ-1))
    blocks.fill(POLISHED_ANDESITE, pos(-n-1, h+1-playerY, playerZ+1), pos(n+o+1, h+1-playerY, playerZ-1))
    blocks.fill(AIR, pos(-n, -playerY, playerZ-1), pos(n+o, h-playerY, playerZ))
    if buildGlass:
        blocks.fill(GLASS, pos(-n, -playerY, playerZ-1), pos(n+o, h-playerY, playerZ-1))

Die Funktion gameloop() läuft während des Spiels kontinuierlich. Sie führt jedes Mal die Funktion playerMoved() aus, die überprüft, ob sich der Spieler bewegt hat. Wenn dies der Fall ist, leitet sie die Bewegung an die Funktion movePiece() weiter, die dann entscheidet, wie das piece bewegt werden muss. Danach teleportiert sie den Spieler zurück zum Startpunkt origin. Jedes 20. Mal führt sie zusätzlich die Funktion moveDown() aus, die das piece um einen Block nach unten bewegt. So funktioniert sie als Timer für das ganze Spiel.

def gameloop():
    global isRunning
    frame = 0
    
    #Wiederholen bis Spieler "stop" schreibt
    while isRunning:
        #Bei Bewegung den Tetromino bewegen
        movedDirection = playerMoved()
        if movedDirection[0] != "":
            movePiece(movedDirection[0], movedDirection[1])
            player.teleport(origin)
        
        #Alle 20 Durchläufe den Tetromino nach unten bewegen
        if frame % 20 == 0:
            moveDown()
        frame += 1

Die Funktion playerMoved() wird bei jedem Durchlauf von gameloop abgerufen. Sie vergleicht die momentane Position des Spielers mit der Startposition, die in der Variable origin abgespeichert ist. Um die zwei Positionen zu vergleichen, werden sie zuerst in ein String umgewandelt. Damit werden sie automatisch auf den vollen Block gerundet. Wenn sie nicht übereinstimmen, wird die Bewegung des Spielers als Liste zurückgeschickt. Das erste Element beschreibt die Richtung (x, y oder z), und das zweite Element zeigt an, ob sich der Spieler in die positive oder die negative Richtung bewegt.

def playerMoved():
    
    #neue und alte Position vergleichen
    cPos = player.position()
    if origin.to_string() == cPos.to_string():
        return ["", ""]
    else:
        #Richtung bestimmen
        x = origin.get_value(Axis.X) - cPos.get_value(Axis.X)
        y = origin.get_value(Axis.Y) - cPos.get_value(Axis.Y)
        z = origin.get_value(Axis.Z) - cPos.get_value(Axis.Z)
        if x < 0:
            return ["x", "+"]
        elif x > 0:
            return ["x", "-"]
        elif y != 0:
            return ["y", "+"]
        elif z < 0:
            return ["z", "+"]
        else:
            return ["z", "-"]

Die Funktion movePiece() wird con gameloop ausgeführt, und erhält dabei auch den Inhalt der Liste, die von playerMoved() zurückgeschickt wurde. Sie entziffert diesen und führt die entsprechende Funktion aus, die dann das piece bewegt.

def movePiece(direction, sign):
    global piece
    
    #Je nach Richtung richtige Bewegung ausführen
    if direction == "x" and sign == "-":
        move(-1)
    elif direction == "x" and sign == "+":
        move(1)
    elif direction == "y":
        moveToBottom()
    elif direction == "z" and sign == "-":
        rotateLeft()
    else:
        rotateRight()

Zum bewegen des piece in der Horizontalen, wird zuerst die X-Position pieceX verändert, und danach das piece mit der neuen Position an checkCollisions() weitergeleitet.

def move(n):
    global piece
    global pieceX
    global pieceY
    
    #X Wert des Tetrominos ändern
    newX = pieceX + n
    if not checkCollisions(piece, newX, pieceY, False):
        checkCollisions(piece, newX, pieceY, True)

def moveDown():
    global piece
    global pieceX
    global pieceY
    
    #Y Wert des Tetrominos ändern
    newY = pieceY - 1
    checkCollisions(piece, pieceX, newY, True)

Zum direkten Plazieren des piece, wird es Block für Block nach unten bewegt, und jeweils mit der Funktion checkCollisions() überprüft, ob es Überlagerungen gibt. Wenn es diese gibt, wird das piece mit der Funktion placePiece() am letzten überlagerungsfreien Ort plaziert. Damit die vorherigen Blöcke nicht auf dem Bildschirm zurückbleiben, werden diese zuvor noch mit dem Befehl player.execute(„fill ~“ + str(-w/2-1) + „ ~“ + str(-playerY) + „ ~“ + str(playerZ) + „ ~“ + str(w/2+1) + „ ~“ + str(h-playerY) + „ ~“ + str(playerZ) + „ air 0 replace wool “ + id(color)) entfernt. Hier haben wir den Befehl player.execute() anstatt blocks.fill() verwenden, weil man bei diesem auch einstellen kann, dass es nur Blöcke eines bestimmten Types löschen soll.

def moveToBottom():
    global piece
    global pieceX
    global pieceY
    global board
    global playerY
    global playerZ
    
    #Y Wert des Tetrominos senken bis Kollision stattfindet
    newY = pieceY
    while not checkCollisions(piece, pieceX, newY, False):
        newY = newY - 1
    player.execute("fill ~" + str(-w/2-1) + " ~" + str(-playerY) + " ~" + str(playerZ) + " ~" + str(w/2+1) + " ~" + str(h-playerY) + " ~" + str(playerZ) + " air 0 replace wool " + id(color))
    pieceY = newY + 1
    placePiece()

Zum drehen des piece wird dessen Liste an der X-Achse und an der Diagonale gespiegelt. Zuerst wird piece Element für Element gespiegelt in die temporäre Liste tempPiece gespeichert, danach dasselbe aber an der Diagonalen gespiegelt und in die Liste newPiece gespeichert. Hier ist wahrscheinlich irgendwo ein kleiner Fehler verborgen, weil beim anschliessenden Bewegen des piece auf dem Bildschirm unlogische weitere Fehler auftraten. Dieser hat jedoch keine grosse Auswirkung auf das Spiel, weil wir grösstenteils behoben haben, in dem wir den nicht richtig ausgeführten Code, player.execute(„fill ~“ + str(-w/2) + „ ~“ + str(-playerY) + „ ~“ + str(playerZ) + „ ~“ + str(w/2) + „ ~“ + str(h-playerY) + „ ~“ + str(playerZ+1) + „ air 0 replace wool “ + id(color)), einfach ein zweites Mal ausführten.

def rotateLeft():
    global piece
    global pieceX
    global pieceY
    tempPiece = []
    newPiece = []
    for i in range(piece.length):
        tr = range(piece.length)
        tempPiece[i] = tr
        newPiece[i] = tr
        for j in range(piece.length):
            tempPiece[i][j] = 0
            newPiece[i][j] = 0
    newPiece = piece
    tPiece = piece
    
    #Gedrehtes Tetromino in neue Liste speichern
    for i in range(piece.length):
        for j in range(piece.length):
            tempPiece[i][j] = tPiece[i][piece.length-1-j]
    for i in range(piece.length):
        for j in range(piece.length):
            newPiece[j][i] = tempPiece[i][j]
    player.execute("fill ~" + str(-w/2) + " ~" + str(-playerY) + " ~" + str(playerZ) + " ~" + str(w/2) + " ~" + str(h-playerY) + " ~" + str(playerZ+1) + " air 0 replace wool " + id(color))
    checkCollisions(newPiece, pieceX, pieceY, True)

def rotateRight():
    global piece
    global pieceX
    global pieceY
    tempPiece = []
    newPiece = []
    for i in range(piece.length):
        tr = range(piece.length)
        tempPiece[i] = tr
        newPiece[i] = tr
        for j in range(piece.length):
            tempPiece[i][j] = 0
            newPiece[i][j] = 0
    newPiece = piece
    
    #Gedrehtes Tetromino in neue Liste speichern
    for i in range(piece.length):
        for j in range(piece.length):
            tempPiece[j][i] = piece[i][j]
    for i in range(tempPiece.length):
        for j in range(tempPiece.length):
            newPiece[i][tempPiece.length-1-j] = tempPiece[i][j]
    player.execute("fill ~" + str(-w/2) + " ~" + str(-playerY) + " ~" + str(playerZ) + " ~" + str(w/2) + " ~" + str(h-playerY) + " ~" + str(playerZ-1) + " air 0 replace wool " + id(color))
    checkCollisions(newPiece, pieceX, pieceY, True)

Zum Verhindern von Überlagerungen wird von den Funktionen zum Bewegen jeweils die Funktion checkCollisions, mit dem neuen Tetromino newPiece und dessen Position abgerufen. Diese überprüft dann, ob das newPiece mit Blocken im Board, mit den Wänden oder mit dem Boden kollidiert. Wenn es mit dem Boden oder dem Board kollidiert, wird das ursprüngliche piece mit der Funktion placePiece() am vorherigen Ort plaziert. Wenn newPiece mit den Wänden kollidiert, wird die Bewegung ignoriert, es passiert also nichts, und wenn es nirgends kollidiert, wird die Bewegung mit der Funktion updatePiece ausgeführt, und der Bildschirm aktualisiert. Falls nur überprüft werden soll, ob es Überlagerungen gibt, aber danach nicht schon alles aktualisiert werden soll, kann man als Input proceed „False“ schicken. Dann wird, falls eine Kollision stattfindet, „True“ und sonst „False“ zurückgeschickt.

def checkCollisions(newPiece, newX, newY, proceed):
    global board
    
    #Kollisionen finden und testen ob Tetromino zuunterst ist
    #Ohne tempPiece entsteht Error, weil type von newPiece nicht bekannt ist
    tempPiece = [[0]]
    tempPiece = newPiece
    collided = False
    bottom = False
    walls = False
    for i in range(newPiece.length):
        for j in range(newPiece.length):
            if newPiece[i][j] == 1:
                if i + newX >= board.length or i + newX < 0:
                    walls = True
                elif board[i + newX][j + newY] == 1:
                    collided = True
                elif j + newY < 0:
                    bottom = True
    if proceed and not walls :
        if bottom:
            placePiece()
        elif not collided:
            updatePiece(newPiece, newX, newY)
        else:
            placePiece()
    elif bottom or collided or walls:
        return(True)
    return(False)

Um das piece zu bewegen, wird die Funktion updatePiece() eingesetzt. Sie löscht das momentane piece, baut das newPiece Block für Block auf dem Bildschirm auf, und speichert dann newPiece in die Variable piece, um die Bewegung abzuschliessen.

def updatePiece(newPiece, newX, newY):
    global board
    global piece
    global pieceX
    global pieceY
    global h
    global playerY
    global playerZ
    global color
    player.execute("fill ~" + str(-w/2-1) + " ~" + str(-playerY) + " ~" + str(playerZ) + " ~" + str(w/2+1) + " ~" + str(h-playerY) + " ~" + str(playerZ) + " air 0 replace wool " + id(color))
    for i in range(newPiece.length):
        for j in range(newPiece.length):
            if newPiece[i][j] == 1:
                if newY + j < h:
                    blocks.place(color, positions.add(origin, pos(-w/2+newX+i, newY+j-playerY, playerZ)))
    piece = newPiece
    pieceX = newX
    pieceY = newY

Die Funktion placePiece() funktioniert grundsätzlich gleich, wie updatePiece(), aber hat noch einige Additionen. Es wird nähmlich zusätzlich überprüft, ob das piece zu weit oben platziert wurde, also ob das Spiel verloren ist, und wenn nicht führt sie removeRow() aus und generiert dann ein neuer Tetromino mit der Funktion getPiece().

def placePiece():
    global board
    global piece
    global pieceX
    global pieceY
    global score
    global isRunning
    
    #Tetromino zur "board" Liste hinzufügen
    for i in range(piece.length):
        for j in range(piece.length):
            if piece[i][j] == 1:
                board[i + pieceX][j + pieceY] = 1
                if pieceY + j < h:
                    blocks.place(placeColor(color), positions.add(origin, pos(-w/2+pieceX+i, pieceY+j-playerY, playerZ)))
                if pieceY + j >= h:
                    isRunning = False
    
    if isRunning:
        #Komplette Reihen entfernen
        removeRow(i)
        #Neues Tetromino generieren
        score = score + 1
        pieceX = Math.round(w/2) - 2
        pieceY = h - 1
        getPiece()
    else:
        player.say("Zu langsam ☹")
        player.say("score: " + str(score))

Um die vollen Zeilen zu entfernen, wird zuerst von unten nach oben für jede Zeile überprüft, ob sie vollständig ist. Wenn dies der Fall ist, wird sie gelöscht, und jede darüberstehende Zeile wird nach unten kopiert. Auf dem Bildschirm geschieht dies mit dem Befehl blocks.clone(…). Die oberste Zeile wird jeweils mit Luft gefüllt, damit dort nicht die vorherige Zeile zurückbleibt.

def removeRow(j):
    global board
    global w
    global h
    y = 0
    
    for _ in range(h):
        complete = 1
        for i in range(w):
            complete = complete * board[i][y]
        if complete == 1:
            #alles über der Reihe nach unten schieben
            for k in range(w):
                for l in range(y, h):
                    board[k][l] = board[k][l+1]
            for l in range(y, h-1):
                blocks.clone(positions.add(origin, pos(-w/2, l+1-playerY, playerZ)), positions.add(origin, pos(w/2, l+1-playerY, playerZ)), positions.add(origin, pos(-w/2, l-playerY, playerZ)), CloneMask.REPLACE, CloneMode.NORMAL)
            for k in range(w-2):
                board[k][h-1]=0
                blocks.fill(AIR, positions.add(origin, pos(-w/2,h-1-playerY, playerZ)), positions.add(origin, pos(w/2-1, h-1-playerY, playerZ)))
        else:
            y = y + 1

Hier werden alle Werte des Spieles zurückgesetzt, damit es anschliessend neu gestartet werden kann.


def startTetris():
    global w
    global h
    global playerZ
    global board
    global piece
    global pieceX
    global pieceY
    global isRunning
    global origin
    global score
    global unusedPieces
    
    #erstellen einer zweidimensionalen Liste zum Speichern der Spielfläche
    # (0/1) (1/1)
    # (0/0) (1/0)
    board = []
    for i in range(w):
        temparr = range(h)
        board[i] = temparr
        for j in range(h):
            board[i][j] = 0
    
    #erstellen des ersten Tetrominos
    unusedPieces = range(7)
    pieceX = Math.round(w/2) - 2
    pieceY = h - 1
    getPiece()
    
    #Spieler zentrieren und Agenten wegteleportieren
    agent.teleport_to_player()
    player.teleport(agent.get_position())
    origin = player.position()
    player.execute("tp ~ ~ ~ facing ~ ~ ~1")
    agent.teleport(pos(0, -10, 0), SOUTH)
    
    #"Spielkonsole" bauen
    makeBoard(w - 1, h - 1)
    
    #Spiel starten
    isRunning = True
    score = 0
    gameloop()

player.on_chat("start", startTetris)

In dieser Funktion wird nur isRunning auf „False“ gesetzt. Wenn diese Variabel das nächste Mal überprüft wird, wird das Spiel gestoppt.

def stopTetris():
    global isRunning
     
    #Aus gameloop() ausbrechen
    isRunning = False
 
player.on_chat("stop", stopTetris)

Die Funktion getPiece() wählt eines der sieben möglichen Tetrominos aus. Damit nicht zu oft nacheinander die gleichen Tetrominos ausgewählt werden, werden in der Liste unusedPieces alle noch unbenutzten abgespeichert. Wenn eines davon ausgewählt wird, wird dieses mir dem Befehl unusedPieces.remove(n) aus der Liste entfernt. Dieser Befehl scheint nicht immer zu funktionieren, was zu wiederholungen des selben Tetrominos führt. Eine lösung dafür haben wir noch nicht gefunden. Auch unusedPieces.pop() hat Fehler generiert. Wenn eines ausgewählt wurde, wird es in die Liste piece gespeichert.

def getPiece():
    global piece
    global color
    global pieceX
    global unusedPieces
    
    #Eines der Tetrominos wählen
    random = Math.round(Math.random()*unusedPieces.length)
    n = unusedPieces[random]
    if unusedPieces.length < 1:
        unusedPieces = range(7)
    else:
        unusedPieces.remove(n)
    if n < 1:
        #I
        piece = [[0,1,0,0],[0,1,0,0],[0,1,0,0],[0,1,0,0]]
        color = LIGHT_BLUE_WOOL
    elif n < 2:
        #O
        piece = [[1,1],[1,1]]
        color = YELLOW_WOOL
        pieceX = pieceX + 1
    elif n < 3:
        #T
        piece = [[0,1,0],[1,1,0],[0,1,0]]
        color = PURPLE_WOOL
    elif n < 4:
        #S
        piece = [[1,0,0],[1,1,0],[0,1,0]]
        color = RED_WOOL
    elif n < 5:
        #2
        piece = [[0,1,0],[1,1,0],[1,0,0]]
        color = LIME_WOOL
    elif n < 6:
        #L
        piece = [[1,1,0],[0,1,0],[0,1,0]]
        color = ORANGE_WOOL
    elif n < 7:
        #J
        piece = [[0,1,0],[0,1,0],[1,1,0]]
        color = BLUE_WOOL

Die Funktion placeColor() wandelt die Bezeichnung für Wolle in die Bezeichnung für Beton (Concrete auf enlisch) um. Dabei bleibt die Farbe immer die selbe.

def placeColor(color):
    if color == LIGHT_BLUE_WOOL:
        return(LIGHT_BLUE_CONCRETE)
    elif color == YELLOW_WOOL:
        return(YELLOW_CONCRETE)
    elif color == PURPLE_WOOL:
        return(PURPLE_CONCRETE)
    elif color == LIME_WOOL:
        return(LIME_CONCRETE)
    elif color == RED_WOOL:
        return(RED_CONCRETE)
    elif color == ORANGE_WOOL:
        return(ORANGE_CONCRETE)
    else:
        return(BLUE_CONCRETE)

Weil im Code-Editor und in Befehlen im Chat nicht die selben Bezeichnungen für die Blöcke verwendet werden, haben wir ebenfalls eine Funktion geschrieben, die die Bezeichnung aus dem Code-Editor in die der Befehle umwandelt.

def id(color):
    if color == LIGHT_BLUE_WOOL:
        return 3
    elif color == YELLOW_WOOL:
        return 4
    elif color == PURPLE_WOOL:
        return 10
    elif color == LIME_WOOL:
        return 5
    elif color == RED_WOOL:
        return 14
    elif color == ORANGE_WOOL:
        return 1
    else:
        return 11

  • archiv/ef/ef2020_2022/minecraft/projekt/maximandrin/start.txt
  • Zuletzt geändert: 2022/08/27 18:13
  • von lehmannr