Lernziele

Es wird nicht erwartet, dass Sie unseren Code oder die verwendeten Befehle auswendig aufschreiben können. Es geht darum, die Logik unserer Lösung und die besprochene Theorie zu verstehen. Insbesondere:

  1. Sie verstehen unseren Code, könnten Schlüsselstellen erklären, und kurze Teile davon reproduzieren, wenn Sie alle nötigen Befehle erhalten. Spezifisch:
  • Sie verstehen, wie wir die Laser mit liste.remove() wieder von den Listen löschen.
  1. Sie verstehen theoretische Konzepte:
  • Sie verstehen, wieso wir die Laser wieder von den Listen entfernen müssen.

Laser kreieren und bewegen

Erklärvideo

Beachten Sie: Die Funktion move_laser() wird beim Refaktorieren noch parametrisiert.

Code

Die Änderungen in main.py.

import turtle
from window import *
from ship import *
import time
import random
 
# Steuerung
ship_direction = 0  # -1 = nach links, 0 = halt, +1 = nach rechts
 
 
def quit():
    global running
    running = False
 
 
def move_left():
    global ship_direction
    ship_direction = -1
 
 
def move_right():
    global ship_direction
    ship_direction = 1
 
 
def stop_moving():
    global ship_direction
    ship_direction = 0
 
 
window.onkeypress(quit, "q")
window.onkeypress(move_left, "Left")
window.onkeypress(move_right, "Right")
window.onkeyrelease(stop_moving, "Left")
window.onkeyrelease(stop_moving, "Right")
window.listen()
 
# Turtle invaders
invader_liste = []
invader_time = time.time()
INVADER_INTERVALL = 0.5
INVADER_SPEED = 2
 
def create_invader():
    t = turtle.Turtle()
    t.penup()
    t.shape("turtle")
    t.shapesize(1.5)
    t.color("white")
    # Zufallsposition
    t.setposition(random.randint(int(LEFT), int(RIGHT)), TOP)
    t.setheading(-90)
    # Zufallsfarbe
    t.color(random.random(), random.random(), random.random())
    invader_liste.append(t)
 
# Laser-Logik
laser_liste = [] 
LASER_SPEED = 10
LASER_LENGTH = 200

def create_laser(): 
    l = turtle.Turtle() 
    l.penup() 
    l.color(1,0,0) 
    l.hideturtle() 
    l.setheading(90) 
    l.setposition(ship.xcor(), ship.ycor() + 20) 
    l.pendown() 
    l.pensize(5) 
    laser_liste.append(l) 

def move_laser(): 
    laser.clear() 
    laser.forward(LASER_SPEED) 
    laser.forward(LASER_LENGTH) 
    laser.back(LASER_LENGTH) 
 
window.onkeypress(create_laser, "space") 
 
running = True
while running:
    new_x = ship.xcor() + SHIP_STEP * ship_direction
    if LEFT < new_x < RIGHT:
        ship.setx(new_x)
    if (time.time() - invader_time) > INVADER_INTERVALL:
        create_invader()
        invader_time = time.time()
    for invader in invader_liste:
        invader.forward(INVADER_SPEED)
    for laser in laser_liste: 
        move_laser() 
 
    window.update()
    time.sleep(0.001)  # Temporäre Lösung, um die Animation zu verlangsamen

Unnötige Laser und Invader wieder löschen

Wieso wird alles so langsam?

Wir fügen aktuell ständig Invaders und Lasers den Listen hinzu. Auch wenn diese nicht mehr auf dem Bildschirm sind, verweilen sie weiterhin in den Listen und werden bei unseren Iterationen bewegt und verarbeitet - ohne dass wir das sehen!

Weil unsere Ressourcen knapp sind, müssen wir unnötige Turtle-Objekte wieder von den Listen entfernen. Sobald diese Objekte aus den Listen entfernt werden, gibt es keine Referenzen mehr auf sie, und sie werden als “unreferenziert” betrachtet. Der Garbage Collector von Python (die Müllabfuhr, quasi) erkennt diese unreferenzierten Objekte und entfernt sie automatisch aus dem Speicher, um Ressourcen freizugeben.

Neben unseren eigenen Listen invader_liste und laser_liste betreibt auch das turtle-Modul eine eigene Liste. Deswegen schaut unsere Funktion, um eine Turtle von einer unserer Listen zu entfernen, letztlich so aus:

def destroy_turtle(sprite, liste):
    sprite.clear() # alles Gezeichnete der Turtle löschen
    sprite.hideturtle() # die Turtle verstecken
    liste.remove(sprite) # von unserer Liste löschen
    turtle.turtles().remove(sprite) # von der internen turtle-Liste löschen

Laser nach Verlassen des Bildschirms löschen

Änderungen in main.py

main.py
 
# ...bisheriger Code...
 
def destroy_turtle(sprite, liste): 
    sprite.clear() 
    sprite.hideturtle() 
    liste.remove(sprite) # unsere Liste
    turtle.turtles().remove(sprite) # interne turtle-Liste
 
running = True
while running:
 
    # ...Bisheriger Code der while-Schleife...
    
    for laser in laser_liste:
        move_laser()
        if laser.ycor() > TOP: 
            destroy_turtle(laser, laser_liste) 
 
    window.update()
    time.sleep(0.001)  # Temporäre Lösung, um die Animation zu verlangsamen

Bei Treffer die Laser und Invader zerstören

Game Over