PYTHON Snake-Game

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
xAMIx
User
Beiträge: 4
Registriert: Freitag 18. März 2022, 14:21

Hallo,

ich hoffe jmd kann mir hier weiterhelfen. Bin noch eine neuling und neu in diesem Forum. Versuche gerade Snake zu programmieren. Sitze seit zwei Tagen am selben Problem. Ich kriege es irgendwie nicht hin dass der Körper von der Schlange den Kopf hinterhergeht. Hab irgendwie alles ausprobiert, aber es funktioniert nicht.

Bitte helft mit ich bin, verzweifelt :)

import pygame

pygame.init()
screen = pygame.display.set_mode((400, 450))

Snake = [[200, 200,20,20], [178, 200,20,20]]
speedx = 0
speedy = 0

def draw():
for i in range(len(Snake)):
pygame.draw.rect(screen, pygame.Color(255,0,0), (Snake))

for i in range(len(Snake)-1,0,-1):
Snake = Snake[i-2]

while True:
screen.fill((0,0,0))

for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
speedx = -0.03
speedy = 0
if event.key == pygame.K_RIGHT:
speedx = 0.03
speedy = 0
if event.key == pygame.K_DOWN:
speedy = 0.03
speedx = 0
if event.key == pygame.K_UP:
speedy = -0.03
speedx = 0

Snake[0][0] += speedx
Snake[0][1] += speedy


draw()
pygame.display.flip()
Benutzeravatar
pillmuncher
User
Beiträge: 1530
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Ohne dass ich jetzt dein Programm angesehen hätte: Der Trick ist üblicherweise, dass man das Feld am hinteren Ende der Schlange löscht und am vorderen Ende ein neues zeichnet. Am einfachsten verwendet man dazu einen Ring Buffer. Dabei muss man nur das hinterste Feld mit den neuen "Kopf"-Koordinaten überschreiben und den "Kopf"-Zeiger auf diesen Index setzen. Wenn die Schlange "Futter" gefressen hat, setzt man das Löschen der hinteren Felder für soundsoviele Ticks aus und fügt statt dessen jedes neue "Kopf"-Feld zusätzlich in den Ring Buffer ein, bis die gewünschte Länge erreicht ist. Danach macht man wie oben weiter.
In specifications, Murphy's Law supersedes Ohm's.
dirk009
User
Beiträge: 27
Registriert: Donnerstag 3. Juni 2021, 21:49

Hallo @xAMIx,

bitte code immer mit dem entsprechenden Tag markieren:

Code: Alles auswählen

import pygame

pygame.init()
screen = pygame.display.set_mode((400, 450))

Snake = [[200, 200,20,20], [178, 200,20,20]]
speedx = 0
speedy = 0

def draw():
    for i in range(len(Snake)):
        pygame.draw.rect(screen, pygame.Color(255,0,0), (Snake))

    for i in range(len(Snake)-1,0,-1):
        Snake = Snake[i-2]

while True:
    screen.fill((0,0,0))

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                speedx = -0.03
                speedy = 0
            if event.key == pygame.K_RIGHT:
                speedx = 0.03
                speedy = 0
            if event.key == pygame.K_DOWN:
                speedy = 0.03
                speedx = 0
            if event.key == pygame.K_UP:
                speedy = -0.03
                speedx = 0

        Snake[0][0] += speedx
        Snake[0][1] += speedy


        draw()
        pygame.display.flip()
Dann ist es leichter den Code zu lesen.

Code: Alles auswählen

  pygame.draw.rect(screen, pygame.Color(255,0,0), (Snake))
erwartet ein rectangle Objekt (https://pygame.readthedocs.io/en/latest/rect/rect.html) was (Snake) nicht ist.

Code: Alles auswählen

rect = Rect(200, 200,20,20)
pygame.draw.rect(screen, pygame.Color(255,0,0), rect)
zeichnet ein rotes Rechteck (nach Hinzufügen von "from pygame.locals import Rect" zu den Imports).

Kannst Du mir erklären, was folgender Code machen soll?

Code: Alles auswählen

    for i in range(len(Snake)-1,0,-1):
        Snake = Snake[i-2]
   
Cheers,

DIrk

PS: https://ichi.pro/de/wie-implementiere-i ... 0187419306 ist ein Tutorial für die Programmierung von Snake mit Pygame.
xAMIx
User
Beiträge: 4
Registriert: Freitag 18. März 2022, 14:21

Ich habe versucht an der Methode Apfel den Kopf mit insert in Körper hinzuzufügen. Aber wegen pop löscht sich der komplette Körper. WO IST DAS Problem? DANKE im voraus.

import pygame
import random

pygame.init()
screen = pygame.display.set_mode((400,450))
KOPF = [200, 200]
KÖRPER = [[200, 200],[180, 200],[160,200]]
speedx = 0
speedy = 0
A = [random.randint(15,385), random.randint(15,435)]
punkt = 0
länge = 0


def draw():
for i in KÖRPER:
pygame.draw.rect(screen, pygame.Color(255, 0, 0), pygame.Rect(i[0], i[1],19,19))

def score():

font = pygame.font.SysFont("Arial Rounded MT Bold", 25)
img = font.render("SCORE: ", True, pygame.Color(47, 79, 79))
screen.blit(img, (25, 20))

font = pygame.font.SysFont("Arial Rounded MT Bold", 25)
img = font.render(str(punkt), True, pygame.Color(47, 79, 79))
screen.blit(img, (100, 20))

def Apfel():
global punkt, länge
pygame.draw.rect(screen, pygame.Color(0, 0, 255), (A[0], A[1], 15, 15))

KÖRPER.insert(0,list(KOPF))
if KOPF[0] + 19 >= A[0] and KOPF[0] - 19 <= A[0] and KOPF[1] + 19 >= A[1] and KOPF[1] - 19 <= A[1]:
punkt += 1
A[0] = random.randint(15, 385)
A[1] = random.randint(15, 435)
länge += 1
else:
KÖRPER.pop()


while True:
#
screen.fill((0, 0, 0))
KOPF[0] += speedx
KOPF[1] += speedy
#-KEY_BEWEGNUG
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
speedx = -0.3
speedy = 0
if event.key == pygame.K_RIGHT:
speedx = 0.3
speedy = 0
if event.key == pygame.K_UP:
speedy = -0.3
speedx = 0
if event.key == pygame.K_DOWN:
speedy = +0.3
speedx = 0
#-METHODEN
draw()
Apfel()
score()

pygame.display.flip()
Benutzeravatar
__blackjack__
User
Beiträge: 14078
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@xAMIx: Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (PascalCase).

Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.

``global`` bitte gleich wieder vergessen. Funktionen (und Methoden) sollten alles was sie ausser Konstanten benötigen, als Argument(e) übergeben bekommen. Ergebnisse werden als Rückgabewerte an den Aufrufer zurückgegeben.

Sowohl `punkt`, was wohl eher `punkte` heissen sollte, als auch `länge` sind überflüssig weil sie a) immer den gleichen Wert haben, und b) aus der Länge des Schlangenkörpers trivial berechenbar sind.

`kopf` ist im Grunde auch redundant, denn dafür könnte man einfach das erste Element von `KÖRPER` verwenden.

Du solltest Dir auch nicht angewöhnen so viel an Listen zu verändern. Statt beispielsweise die Elemente von `A` neu zu setzen, einfach ein neues Tupel mit Koordinaten für einen Apfel erstellen. Und das am besten in einer Funktion, weil der Code dafür im Moment an *zwei* Stellen im Code steht und sich auch noch unterscheidet.

Funktionen werden üblicherweise nach der Tätigkeit benannt, die sie ausführen. `apfel` ist ein guter Name für einen Wert der den/einen Apfel repräsentiert, nicht für eine Funktion die etwas tut. Und auch wenn `score()` auch eine Tätigkeit sein kann, es ist nicht das was die Funktion mit diesem Namen macht.

`exit()` muss man eigentlich aus `sys` importieren, aber man sollte das Programm an der Stelle nicht auf diese Art hart beenden. Ausserdem fehlt ein `pygame.quit()`-Aufruf.

Zwischenstand:

Code: Alles auswählen

#!/usr/bin/env python3
import random

import pygame


def erzeuge_apfel():
    return (random.randint(15, 385), random.randint(15, 435))


def zeichne_schlange(screen, koerper):
    for x, y in koerper:
        pygame.draw.rect(screen, (255, 0, 0), pygame.Rect(x, y, 19, 19))


def bewege_schlange(screen, apfel, speed_x, speed_y, koerper):
    pygame.draw.rect(screen, (0, 255, 0), (apfel[0], apfel[1], 15, 15))

    koerper.insert(0, (koerper[0][0] + speed_x, koerper[0][1] + speed_y))
    if (
        koerper[0][0] + 19 >= apfel[0]
        and koerper[0][0] - 19 <= apfel[0]
        and koerper[0][1] + 19 >= apfel[1]
        and koerper[0][1] - 19 <= apfel[1]
    ):
        return erzeuge_apfel()
    else:
        koerper.pop()
        return apfel


def zeichne_punktestand(screen, punkte):
    font = pygame.font.SysFont("Arial Rounded MT Bold", 25)
    color = (47, 79, 79)
    screen.blit(font.render("SCORE: ", True, color), (25, 20))
    screen.blit(font.render(str(punkte), True, color), (100, 20))


def main():
    try:
        pygame.init()
        screen = pygame.display.set_mode((400, 450))

        koerper = [(200, 200), (180, 200), (160, 200)]
        start_laenge = len(koerper)
        speed_x, speed_y = 0, 0

        apfel = erzeuge_apfel()

        while True:
            screen.fill((0, 0, 0))

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    return

                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_LEFT:
                        speed_x = -0.3
                        speed_y = 0
                    if event.key == pygame.K_RIGHT:
                        speed_x = 0.3
                        speed_y = 0
                    if event.key == pygame.K_UP:
                        speed_x = 0
                        speed_y = -0.3
                    if event.key == pygame.K_DOWN:
                        speed_x = 0
                        speed_y = 0.3

            zeichne_schlange(screen, koerper)
            apfel = bewege_schlange(screen, apfel, speed_x, speed_y, koerper)
            zeichne_punktestand(screen, len(koerper) - start_laenge)

            pygame.display.flip()
    
    finally:
        pygame.quit()


if __name__ == "__main__":
    main()
Dein Problem liegt nicht am `pop()`, denn die Länge des Körpers stimmt. Aber die Koordinaten nicht. Selbst wenn Du grundsätzliche Problem korrigierst. geht das mit 0.3 nicht wirklich, denn dadurch entstehen Koordinaten die weder zu den Spielweltkoordinaten passen (einzelne Schlangenglieder), noch zu den Koordinaten in denen gezeichnet wird (ganze Pixel).
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Antworten