TigerJython xx
für Gymnasien

Snake-Game


Snake ist ein bekanntes Computerspiel, bei dem man eine Schlange durch ein Spielfeld so steuert, dass sie Futter finden kann. Die Schlange wird mit jedem Futterhappen länger.

Unsere Implementierung hält sich an folgende Spielregeln:

  • Der Snake kann mit den Cursortasten bewegt werden
  • Die Maus wird automatisch an einer zufälligen Position im Gitter erzeugt
  • Nach jeder gefressenen Maus wird die Schlange um ein Glied länger und es wird eine neue Maus erzeugt
  • Wenn die Schlange mit dem Rand oder ihrem Schwanz kollidiert ist GameOver
  • Ziel: Eine möglichst lange Schlange erzeugen

Die Geschwindigkeit kann angepasst werden, indem man die Simulationsperiode (400) ändert.

 

# SnakeGame.py

from gamegrid import *

# ---------------- class Snake ----------------
class Snake(Actor):
    def __init__(self):
         Actor.__init__(self, True, "sprites/snakehead.gif")
         self.tail = [] 

    def reset(self):
        for i in range(2):
           segment = TailSegment()
           addActor(segment, Location(snake.getX(), snake.getY() + i + 1))
           self.tail.append(segment)      

    def tryToEat(self, lastLocation):
        actor = getOneActorAt(self.getLocation(), Food)
        if actor != None:
            newSegment = TailSegment()
            addActor(newSegment, lastLocation)
            self.tail.append(newSegment)
            actor.removeSelf()
            addActor(Food(), getRandomEmptyLocation())
  
    def act(self): 
        lastIndex = len(self.tail) - 1
        if lastIndex > -1:
            lastLocation = self.tail[lastIndex].getLocation()
            for i in range (lastIndex, 0, -1):
                self.tail[i].setLocation(self.tail[i-1].getLocation())
            self.tail[0].setLocation(self.getLocation())
        
        self.move() 

        a = getOneActorAt(self.getLocation(), TailSegment)
        if not self.isInGrid() or a != None:
             removeAllActors()
             addActor(Actor("sprites/gameover.gif"), Location(9, 9))
             return   

        self.tryToEat(lastLocation)  

# ---------------- class Tailsegment----------------
class TailSegment(Actor):
    def __init__(self):
        Actor.__init__(self, "sprites/snaketail.gif")
 
# ---------------- class Food ----------------
class Food(Actor):
    def __init__(self):
        Actor.__init__(self, "sprites/mouse.gif")
 
def keyCallback(keyCode):
        if keyCode == 38: # UP
            snake.setDirection(270)
        if keyCode == 40: # DOWN
            snake.setDirection(90)
        if keyCode == 39: # RIGHT
            snake.setDirection(0)
        if keyCode == 37: # LEFT
            snake.setDirection(180)  
 
makeGameGrid(20, 20, 20, Color.gray, False, keyRepeated = keyCallback)
snake = Snake()
addActor(snake, Location(10,10))
snake.setDirection(Location.NORTH)
food = Food()
addActor(Food(), getRandomEmptyLocation())
show()
setSimulationPeriod(400)
doRun()
Programmcode markieren (Ctrl+C kopieren, Ctrl+V einfügen)

 

Erklärungen zum Programmcode:

Die Schlange wird mit der Klasse Snake modelliert und besteht aus einem Kopf und einem Schwanz, der aus einer Anzahl Teile (TailSegment) besteht. Mit den Cursortasten wird nur der Kopf gesteuert, die übrigen Teile laufen nach. Dieses Nachlaufen zu programmieren, ist der schwierigste Teil dieser Aufgabe.
Die TeilSegmente werden in einer Liste tail gespeichert. Mit der Liste lässt sich die wachsende Schlange elegant darstellen. Mit der Möglichkeit, über einen Index auf die einzelnen Listenelemente zuzugreifen, werden die einzelnen TailSegments bewegt.

 
self.tail = [] : ist eine leere Liste, sie ist vorgesehen, um die TailSegmente zu speichern. tail ist Instanzvariable der Klasse Snake, deshalb muss self vorangestellt werden
tail.append(segment) : fügt ein segment zu der Liste
reset(self): die Methode reset() wird automatisch aufgerufen, wenn der Actor zum Gamegrid hinzufügt wird
addActor(segment, Location(snake.getX(), snake.getY() + i + 1)) : fügt ein Teilsegmet zum Spielfenster an der Position unterhalb des Snake-Kopfes.
lastIndex = len(tail) - 1
Die Schlange wird bewegt, indem das letze Segment die Position des vorhergehenden Gliedes bekommt, dieses wieder die Position des vorhergehenden usw. Das erste Segment erhält die Position des Snake-Kopfes. Da die Indexnummern einer Liste immer bei 0 beginnen, ist der letzte Index um 1 kleiner als die Anzahl der Listenelemente
lastLocation = tail[lastIndex].getLocation() : Position des letztes Teilsegments (wird verwendet um beim Fressen das neue Segment) zu positionieren

for i in range (lastIndex, 0, -1):
     tail[i].setLocation(tail[i-1].getLocation())
Die Schwanzglieder werden versetzt, beginnend beim letzten Teilsegment

tail[0].setLocation(self.getLocation()): Segment mit dem Index 0 bekommt die Position des Kopfes
not self.isInGrid() führt zum GameOver
a = getOneActorAt(self.getLocation(), TailSegment): wenn sich an der Position des Snake-Kopfes ein Actor TailSegment befindet, ist die Schlange über den Schwanz gelaufen, was ebenfalls zu GameOver führt