Variablen erneut Werte zuweisen

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
Benutzeravatar
Patsche
User
Beiträge: 43
Registriert: Samstag 23. Oktober 2021, 00:17

Hi!

Ich programmiere gerade mit meinem Sohn ein Spiel in Python mit Pygame.
Nun haben wir am Anfang verschiedene Startwerte für Spieler und Gegner in unserem Spiel.
Bepielspielhaft:

Code: Alles auswählen

gameover = 0
reset = 0
spieler1_leben = 3
spieler1_breite = 20
spieler1_hoehe = 20
spieler1_x =5
spieler1_y=10
spieler1_bewegungx=10
spieler2_leben = 3
spieler1_breite = 20
spieler1_hoehe = 20
spieler2_x =25
spieler2_y=50
spieler2_bewegung=10
zombie1_x = 50
zombie1_y =30
.....
Diese Werte verändern sich natürlich im Laufe des Spiels, weil sich die Figuren bewegen.
Nun möchte wir, wenn das Spiel durch den Verlust von Leben beendet wurde, alle Figuren und Werte wieder auf ihre Startwerte zurücksetzen.

Jetzt behelfe ich mir gerade, dass ich einfach den gesamten Block kopiere und an anderer Stelle wieder einfüge.
Beispielhaft:

Code: Alles auswählen

if gameover==1 and reset==1:
	gameover = 0
	reset = 0
	spieler1_leben = 3
	spieler1_breite = 20
	spieler1_hoehe = 20
	spieler1_x =5
	spieler1_y=10
	spieler1_bewegungx=10
	spieler2_leben = 3
	spieler1_breite = 20
	spieler1_hoehe = 20
	spieler2_x =25
	spieler2_y=50
	spieler2_bewegung=10
	zombie1_x = 50
	zombie1_y =30
Geht das auch anders ohne nochmal alle Werte eingeben zu müssen?
Bin noch Programmieranfänger, weswegen ich nicht viel Ahnung von Klassen und Funktionen habe.
Vielleicht kann mir ja jemand auf die Sprünge helfen.
Benutzeravatar
__blackjack__
User
Beiträge: 13122
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Patsche: Grundsätzlich ist die Antwort eine Schleife wenn man etwas wiederholen möchte, wie in diesem Fall das Spiel.

Ich würde aber dringend raten sich mit Funktionen und dann Klassen zu beschäftigen bevor hier zu viel Zeit versenkt wird. Denn das nummerieren von Namen und mehrere zusammengehörende Namen mit einem gemeinsamen Präfix sind beides Sachen die man nicht haben möchte, und die man mit Klassen löst. Da sind auch schon Fehler drin, die durch kopieren, einfügen, und (nicht) anpassen entstanden sind. Einer der Gründe warum man so etwas nicht macht.

Python hat einen eigenen Datentyp für Wahrheitswerte, den man auch verwenden sollte statt 0 und 1. Wobei man die beiden Flags `gameover` und `reset` sehr wahrscheinlich auch gar nicht wirklich braucht. Dafür würde man ”Endlosschleifen” schreiben, die man an entsprechender Stelle mit ``break`` verlässt.

Eingerückt wird mit 4 Leerzeichen pro Ebene, nicht mit Tabulatorzeichen. Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Patsche
User
Beiträge: 43
Registriert: Samstag 23. Oktober 2021, 00:17

__blackjack__ hat geschrieben: Donnerstag 13. Juli 2023, 16:10 @Patsche: Grundsätzlich ist die Antwort eine Schleife wenn man etwas wiederholen möchte, wie in diesem Fall das Spiel.
Das Spiel befindet sich ja auch in einer Schleife. Die kann ich so nicht beenden, weil dann das ganze Spiel ausgeht und das möchte ich nicht.
__blackjack__ hat geschrieben: Donnerstag 13. Juli 2023, 16:10 Ich würde aber dringend raten sich mit Funktionen und dann Klassen zu beschäftigen bevor hier zu viel Zeit versenkt wird. Denn das nummerieren von Namen und mehrere zusammengehörende Namen mit einem gemeinsamen Präfix sind beides Sachen die man nicht haben möchte, und die man mit Klassen löst. Da sind auch schon Fehler drin, die durch kopieren, einfügen, und (nicht) anpassen entstanden sind. Einer der Gründe warum man so etwas nicht macht.
Ansich verstehe ich Klassen, aber selbst dann muss ich doch alle Werte nochmal übergeben.
Das ist meine Problematik.....
__blackjack__ hat geschrieben: Donnerstag 13. Juli 2023, 16:10 Python hat einen eigenen Datentyp für Wahrheitswerte, den man auch verwenden sollte statt 0 und 1.
Werde ich ändern. Mir sind True und False bekannt. Ändert ja aber nichts an meiner Problematik.....
__blackjack__ hat geschrieben: Donnerstag 13. Juli 2023, 16:10 Wobei man die beiden Flags `gameover` und `reset` sehr wahrscheinlich auch gar nicht wirklich braucht. Dafür würde man ”Endlosschleifen” schreiben, die man an entsprechender Stelle mit ``break`` verlässt.
Habe den Code gerade nicht da, aber mit gameover wird Textausgabe auf dem Surface dargestellt, die erst dann erscheinen soll, wenn die Leben leer sind.
reset wird dann durch die Bestätigung mit der ENTER-taste durchgeführt wahr und dann sollen alle Werte auf die Startwerte gesetzt werden.
__blackjack__ hat geschrieben: Donnerstag 13. Juli 2023, 16:10 Eingerückt wird mit 4 Leerzeichen pro Ebene, nicht mit Tabulatorzeichen.
Die Einrückung hat die IDE vorgenommen.....das macht die selbstständig, sobald ich eine Verzweigung oder Schleife einleite.
Hatte aber gerade nochmal nachgeguckt und die Einrückung ist gleich weit.

__blackjack__ hat geschrieben: Donnerstag 13. Juli 2023, 16:10 Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.
Ich bin wie gesagt Neuling und halte mich an die Anleitung von https://www.python-lernen.de/pygame-tutorial.htm
Ich weiß zwar, dass das Hauptprogramm in eine main() gehört, aber ich habe auch noch kein riesen Projekt, weshalb ich darauf verzichtet habe.

Vielen Dank erstmal für deine ausführliche Antwort.
Einige Dinge werde ich umändern.

Das Grundproblem besteht jedoch weiterhin. Ich muss halt verschiedenste Variablen wieder auf Startwerte setzen, aber ich glaube, dass es nicht so einfach ist, wie ich mir das Vorstelle.
Ich hatte gehofft es gäbe etwas in der Richtung einer Funktion, die ich am Anfang des Programmes mache und dann einfach nur nochmal ausführe. Nur dann sind die Variablen ja auch nur innerhalb der Funktion vorhanden und nicht global.
Klar könnte man auch Klassen usw. erstellen, aber für 5 Figuren doch etwas übertrieben und mein Sohn (10) soll das auch noch verstehen.
Dann habe ich lieber mehr Zeilen an Code, der dann aber auch Einsteigerfreundlich ist.
Ich bemerke aber auch gerade, dass das hier wieder eine Grundsatzdiskussion wird und das möchte ich gar nicht......
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@Patsche: Die Idee mit den Klassen besteht darin, jeden Spieler zu abstrahieren. Dann reduziert sich der Code zu:

Code: Alles auswählen

class Player:

    def __init__(self, name):
        self.name = name
        self.lifes = 3
        self.width = 20
        self.height = 20
        ...
        

players = {name: Player(name) for name in "tom", "jerry"}
Immer wenn Du Spieler anlegst, oder neu anlegst, brauchst Du nur eine neue Instanz von Player.

Mit der Einrückung kommt es drauf an: Falls die IDE aus einem Tab vier Leerzeichen macht, dann ist alles in Ordnung. Gute Editoren tun das. Falls nicht, stell den Editor entsprechen ein oder wechsel zu einem, der das kann. So einen Editor brauchst Du – wirklich.
Benutzeravatar
Patsche
User
Beiträge: 43
Registriert: Samstag 23. Oktober 2021, 00:17

kbr hat geschrieben: Donnerstag 13. Juli 2023, 20:17 @Patsche: Die Idee mit den Klassen besteht darin, jeden Spieler zu abstrahieren.
....
Immer wenn Du Spieler anlegst, oder neu anlegst, brauchst Du nur eine neue Instanz von Player.
Genau, das verstehe ich auch so. Wenn ich mehrere Figuren hätte, dann würde ich das auch so machen, auch wenn ich mir das noch genau angucken müsste.
Aber die Startwerte müsste ich später, wenn ich ein Reset mache, auch alle wieder dareinschreiben.
Während des Spiels verändern sich ja noch andere Werte.
Die Geschwindigkeiten ändern sich, je nachdem, was für ein Item man nimmt beispielsweise.
Die Richtungen, in die sie laufen usw.
Bei meinem Reset sollen quasi alle zurück zu ihrem Spawnpoint mit ihrer Laufrichtung usw.

Ich dachte nur, es gäbe irgend eine einfache Möglichkeit zu sagen, dass alles zurück zum Start soll.
So eine Art Bauplan für alle Figuren unterschiedlicher Klassen.

ACHTUNG FALSCH !!!!!! DAS IST NUR EIN GEDANKE!!! MIR IST KLAR, DASS DAS SO NICHT FUNKTIONIERT!!!
So was wie eine Art Funktion:

Code: Alles auswählen

#Bauplan 
startwerte()
    a = 10
    b = 12
    c = 3
    d = 8

#An beliebiger Stelle im Programm einsetzen
startwert()
Hoffe ihr versteht was ich meine.......


Und bei alledem Kram muss es auch noch irgendwie so verständlich sein, dass der zehnjährige das versteht.
Dem raucht so schon der Kopf :lol: :lol: :lol:
Benutzeravatar
__blackjack__
User
Beiträge: 13122
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Patsche: Das Spiel ist in einer Schleife. Wenn Du die noch mal wiederholen willst, muss da noch eine Schleife drum. Was Du wiederholen möchtest, kommt in eine Schleife. Die Initialisierung der Spielfiguren ist in einer Schleife und danach kommt, immer noch innerhalb dieser Schleife, die Schleife die das Spiel dann ablaufen lässt. So kann sich nach Spielende und wenn der Benutzer das wünschst, das Spiel noch mal wiederholen.

Python-IDEs verwenden vier Leerzeichen. Ich habe noch keine gesehen die Tabs verwendet. Das macht jeder so. Zum einen weil Tabs schnell zu Problemen führen wenn sich da doch mal ein Leerzeichen rein verirrt und der Code etwas anderes bedeutet als es scheinbar aussieht, und weil man nicht sinnvoll zusammenarbeiten kann wenn da jeder was anderes macht. Zusammenarbeiten ist in dem Zusammenhang dann auch mal Code in einem Forum zeigen den andere mal ausprobieren sollen, zum Beispiel um Fehler zu suchen.

Die Projektgrösse ist nicht ausschlaggebend ob man sauber programmiert. Wie soll man es denn lernen wenn man alle kleinen Projekte unsauber macht, das es bei einem grösseren dann plötzlich automatisch sauber wird. Zumal gerade solche Spielprojekte erfahrungsgemäss mit der Zeit wachsen, und das sowohl schnell, als auch vom Umfang her. Und wenn man dann tatsächlich hart an die Grenzen stösst weil das einfach nicht mehr durchschaubar ist, hilft oft nur noch wegwerfen und neu anfangen.

Die Grenzen merkt man selbst beim schreiben auch nicht so unmittelbar. Das fällt auf wenn *andere* sich den Code anschauen, die nicht wissen wie das so gewachsen ist. Zum Beispiel wenn man dann mit einer Frage in einem Forum landet. Und der ”andere” ist dann aber auch oft der Autor selbst, wenn er da ein oder zwei Monate mal nicht reingeschaut hat, und nicht mehr alles frisch im Kopf hat.

5 Figuren mit 6 Werten sind 30 Namen. Das ist deutlich zu viel. So fünf bis sieben ”Dinge” können Menschen üblicherweise gleichzeitig im Auge behalten. Nimm noch ein paar Hilfsvariablen dazu, dann kommt man so auf 15 Namen die man in einer Funktion maximal haben sollte. Je mehr man da hat, umso wahrscheinlicher macht man Fehler weil man durcheinander kommt. Du hast bei dem Code mit den zwei Spielern ja schon Flüchtigkeitsfehler gemacht. Das wird bei mehr Namen nicht einfacher.

Du kommentierst die Funktion mit ``# Bauplan`` — was darauf hindeutet, dass Du doch irgendwie Klassen willst, denn genau das sind ja Klassen: Baupläne für Objekte. Die beschreiben welche Daten so ein Objekt hat (Attribute), und welche Operationen auf diesen Daten es gibt (Methoden).

Pygame hat da selbst auch schon eine Menge nützlicher Baupläne. Beispielsweise `Rect`-Objekte mit denen Du die Einzelangaben `x`, `y`, `breite`, und `hoehe` der Spielfiguren ersetzen kannst. Die haben Operationen um sich zu verschieben oder Kollisionen mit Punkten oder anderen `Rect`-Objekten festzustellen.

Man kann die auch als Bestandteil von `pygame.sprite.Sprite`-Objekten verwenden. Die sich wiederrum zu einer Gruppe zusammenfassen lassen.

Und noch mal zur eigentlichen Frage: Unabhängig von Klassen oder nicht, die Lösung für so etwas ist eine Schleife. Wenn man Code hat, der einen kompletten Spieldurchlauf darstellt, dann macht man da eine Schleife drum, und schon wiederholt der sich nach Spielende. Wenn man das nicht bedingungslos will, kommt am Ende noch eine Abfrage ob wiederholt werden soll — falls nicht wird die Schleife mit ``break`` verlassen. Denn den Code das Spiel zu initialisieren hat man ja bereits am Anfang stehen, und eine Schleife wiedeholt den dann natürlich.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Patsche
User
Beiträge: 43
Registriert: Samstag 23. Oktober 2021, 00:17

__blackjack__ hat geschrieben: Donnerstag 13. Juli 2023, 23:56 Pygame hat da selbst auch schon eine Menge nützlicher Baupläne. Beispielsweise `Rect`-Objekte mit denen Du die Einzelangaben `x`, `y`, `breite`, und `hoehe` der Spielfiguren ersetzen kannst. Die haben Operationen um sich zu verschieben oder Kollisionen mit Punkten oder anderen `Rect`-Objekten festzustellen.
Genau das tue ich. Beispielsweise so:

Code: Alles auswählen

#Importieren von genutzten Bibliotheken
import pygame, random


#Fenster öffnen
aufloesung = pygame.display.Info() 
screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)


#Spielfarben
rot     = ( 255, 0, 0 )
lila    = ( 200, 80, 200 )
blau    = ( 80, 80, 200 )



#Startvariablen
# -- Spielfigur 1
spielfigur_1_farbe = blau
spielfigur_1_x = 20
spielfigur_1_y = aufloesung.current_h /2 - 50
spielfigur_1_bewegung = 0
schlaegerbreite_spieler1 = 20
schlaegerhoehe_spieler1 = 100
punktespieler1 = 0
leben = 3

# -- Spielfigur 2
spielfigur_2_farbe = lila
spielfigur_2_x = aufloesung.current_w - 40
spielfigur_2_y = aufloesung.current_h / 2 - 50
spielfigur_2_bewegung = 0
schlaegerbreite_spieler2 = 20
schlaegerhoehe_spieler2 = aufloesung.current_w
punktespieler2 = 0
schlaegerhoehe_spieler2_save = schlaegerhoehe_spieler2

# -- Spielmodus
mehrspieler = False

# -- Ball
ball_farbe = rot
ball_durchmesser = 40
ballpos_x = 50
ballpos_y = random.randint(50, aufloesung.current_h - 50)
ballwechsel = 0
bewegung_x = 5
bewegung_x_save = 0
bewegung_y = 5
bewegung_y_save = 0
ballgeschw = 0

#Spielfeld/Figuren zeichnen
# -- Spielfigur 1
spieler1 = pygame.draw.rect(screen, spielfigur_1_farbe, [spielfigur_1_x, spielfigur_1_y, schlaegerbreite_spieler1, schlaegerhoehe_spieler1])

# -- Spielfigur 2
spieler2 = pygame.draw.rect(screen, spielfigur_2_farbe, [spielfigur_2_x, spielfigur_2_y, schlaegerbreite_spieler2, schlaegerhoehe_spieler2])

# -- Ball
ball = pygame.draw.ellipse(screen, ball_farbe, [ballpos_x, ballpos_y, ball_durchmesser, ball_durchmesser])

.
.
.
.

#Kollisionsabfragen
# -- Spielfigur 1
if spieler1.colliderect(ball):
    print("Zusammenstoß P1")
    bewegung_x = bewegung_x * -1
    ballpos_x = schlaegerbreite_spieler1 + ball_durchmesser/2
    ballwechsel+=1
    if pygame.joystick.get_count() == 1:
        joystick_0.rumble(0, 1, 200) == 1

# -- Spielfigur 2
if spieler2.colliderect(ball):
    print("Zusammenstoß P2")
    bewegung_x = bewegung_x * -1
    ballpos_x = aufloesung.current_w - schlaegerbreite_spieler2*2 - ball_durchmesser - 1
    ballwechsel+=1
    if pygame.joystick.get_count() >= 1:
        joystick_1.rumble(0, 1, 200) == 1
Durch die vielen Variablen bleibe ich halt sehr flexibel.
Ich könnte Items verwende, die die Form der Figur verändert, ihre Bewegungsgeschwindigkeit erhöht oder Leben auffüllt.
Das ist nur ein Auszug
Ich halte mich da wie gesagt, an die Anleitung von https://www.python-lernen.de/pygame-tutorial.htm.

Ich weiß eure Antworten sehr zu schätzen. Vielen Dank für eure Hilfe!
Vielleicht traue ich mich ja irgendwann mal den Code des Spiels hier zu veröffentlichen. Den werdet ihr Profis wahrscheinlich zerfetzen.
Allgemein ist der Ton meist sehr grob in IT-Affinen Foren.
Da werden Anfänger eher belächelt, als konstruktiv geholfen.
Dabei haben alle mal klein angefangen. :)
Benutzeravatar
__blackjack__
User
Beiträge: 13122
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Patsche: Du sagst genau das machst Du und zeigst dann Code in dem Du genau das *nicht* machst. 🤓

Da gibt es `spielfigur_1_x`, `spielfigur_1_y`, `schlaegerbreite_spieler1`, und `schlaegerhoehe_spieler1` und das ganze noch mal für Spieler 2, statt jeweils nur 1 `Rect` mit den ganzen Informationen pro Spieler.

Durch die vielen Variablen bleibt nichts flexibel. Was wird denn unflexibel wenn man die sinnvoll zusammenfasst? Es wird übersichtlicher. Und verständlicher wenn man nicht mit Einzelwerten rechnet, wo man sich erst klar machen muss welchen Punkt an oder in einem Rechteck man da letztlich anspricht. Die Zusammenhänge muss man sich ja im Moment aus den Zahlen zusammenreimen. Übrigens auch ein Punkt: Vermeiden von ”magischen” Zahlen die dann auch noch voneinander abhängen. Die 50 ist ja 50 weil es die Hälfte von 100 ist, die wiederum die Schlägerhöhe. Dann sollte da aber nicht 50 stehen, sondern Schlägerhöhe durch zwei. Das ist verständlicher, und wenn man mal die Schlägerhöhe ändert, muss man nicht von Hand daraus abegleitete Zahlen ändern.

Aus:

Code: Alles auswählen

    spielfigur_1_farbe = BLAU
    spielfigur_1_x = 20
    spielfigur_1_y = aufloesung.current_h / 2 - 50
    spielfigur_1_bewegung = 0
    schlaegerbreite_spieler1 = 20
    schlaegerhoehe_spieler1 = 100
    punktespieler1 = 0
    leben = 3

    spielfigur_2_farbe = LILA
    spielfigur_2_x = aufloesung.current_w - 40
    spielfigur_2_y = aufloesung.current_h / 2 - 50
    spielfigur_2_bewegung = 0
    schlaegerbreite_spieler2 = 20
    schlaegerhoehe_spieler2 = aufloesung.current_w
    punktespieler2 = 0
Wird dann:

Code: Alles auswählen

    spielfigur_1_farbe = BLAU
    spielfigur_1_rect = pygame.Rect(0, 0, SCHLAEGERBREITE, SCHLAEGERHOEHE)
    spielfigur_1_rect.midleft = SCHLAEGERBREITE, screen_rect.centery
    spielfigur_1_bewegung = 0
    punktespieler1 = 0
    leben = 3

    spielfigur_2_farbe = LILA
    spielfigur_2_rect = pygame.Rect(0, 0, SCHLAEGERBREITE, SCHLAEGERHOEHE)
    spielfigur_1_rect.midright = (
        screen_rect.right - SCHLAEGERBREITE,
        screen_rect.centery,
    )
    spielfigur_2_bewegung = 0
    punktespieler2 = 0
Keine ”magischen” Zahlen mehr. Und die `Rect`-Objekte kann man dann im weiteren für die Position, für's Zeichnen, und für Kollisionstests verwenden. Mit dem Ball kann man das gleiche machen und dort auch die Bewegungskomponenten zu einem `pygame.Vector2`-Objekt zusammenfassen. Dann sieht das so aus:

Code: Alles auswählen

#!/usr/bin/env python3
import random

import pygame

ROT = (255, 0, 0)
LILA = (200, 80, 200)
BLAU = (80, 80, 200)

SCHLAEGERBREITE, SCHLAEGERHOEHE = 20, 100
BALL_DURCHMESSER = 40


def main():
    screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
    screen_rect = screen.get_rect()

    spielfigur_1_farbe = BLAU
    spielfigur_1_rect = pygame.Rect(0, 0, SCHLAEGERBREITE, SCHLAEGERHOEHE)
    spielfigur_1_rect.midleft = SCHLAEGERBREITE, screen_rect.centery
    spielfigur_1_bewegung = 0
    punktespieler1 = 0

    spielfigur_2_farbe = LILA
    spielfigur_2_rect = pygame.Rect(0, 0, SCHLAEGERBREITE, SCHLAEGERHOEHE)
    spielfigur_2_rect.midright = (
        screen_rect.right - SCHLAEGERBREITE,
        screen_rect.centery,
    )
    spielfigur_2_bewegung = 0
    punktespieler2 = 0

    ball_farbe = ROT
    abstand = BALL_DURCHMESSER + 10
    ball_rect = pygame.Rect(
        abstand,
        random.randint(abstand, screen_rect.width - abstand),
        BALL_DURCHMESSER,
        BALL_DURCHMESSER,
    )
    ball_bewegung = pygame.Vector2(5, 5)
    
    mehrspieler = False
    leben = 3
    ballwechsel = 0

    pygame.draw.rect(screen, spielfigur_1_farbe, spielfigur_1_rect)
    pygame.draw.rect(screen, spielfigur_2_farbe, spielfigur_2_rect)
    pygame.draw.ellipse(screen, ball_farbe, ball_rect)

    ...

    if spielfigur_1_rect.colliderect(ball_rect):
        print("Zusammenstoß P1")
        ball_bewegung.x = -ball_bewegung.x
        ball_rect.left = spielfigur_1_rect.right
        ballwechsel += 1
        if pygame.joystick.get_count() == 1:
            joystick_0.rumble(0, 1, 200)

    if spielfigur_2_rect.colliderect(ball_rect):
        print("Zusammenstoß P2")
        ball_bewegung.x = -ball_bewegung.x
        ball_rect.right = spielfigur_2_rect.left
        ballwechsel += 1
        if pygame.joystick.get_count() >= 1:
            joystick_1.rumble(0, 1, 200)
Immer noch zu viele einzelne Variablen. Zeit die Spieler und den Ball mindestens von den Daten in jeweils einer Klasse zusammenzufassen:

Code: Alles auswählen

#!/usr/bin/env python3
import random

import pygame

ROT = (255, 0, 0)
LILA = (200, 80, 200)
BLAU = (80, 80, 200)

SCHLAEGERBREITE, SCHLAEGERHOEHE = 20, 100
BALL_DURCHMESSER = 40


class Spieler:
    def __init__(self, farbe):
        self.farbe = farbe
        self.rect = pygame.Rect(0, 0, SCHLAEGERBREITE, SCHLAEGERHOEHE)
        self.bewegung = 0
        self.punkte = 0


class Ball:
    def __init__(self, farbe, rect):
        self.farbe = farbe
        self.rect = rect
        self.bewegung = pygame.Vector2(5, 5)


def main():
    screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
    screen_rect = screen.get_rect()

    spieler_a = Spieler(BLAU)
    spieler_a.rect.midleft = SCHLAEGERBREITE, screen_rect.centery

    spieler_b = Spieler(LILA)
    spieler_b.rect.midright = (
        screen_rect.right - SCHLAEGERBREITE,
        screen_rect.centery,
    )

    abstand = BALL_DURCHMESSER + 10
    ball = Ball(
        ROT,
        pygame.Rect(
            abstand,
            random.randint(abstand, screen_rect.width - abstand),
            BALL_DURCHMESSER,
            BALL_DURCHMESSER,
        ),
    )

    mehrspieler = False
    leben = 3
    ballwechsel = 0

    pygame.draw.rect(screen, spieler_a.farbe, spieler_a.rect)
    pygame.draw.rect(screen, spieler_b.farbe, spieler_b.rect)
    pygame.draw.ellipse(screen, ball.farbe, ball.rect)

    ...

    if spieler_a.rect.colliderect(ball.rect):
        print("Zusammenstoß P1")
        ball.bewegung.x = -ball.bewegung.x
        ball.rect.left = spieler_a.rect.right
        ballwechsel += 1
        if pygame.joystick.get_count() == 1:
            joystick_0.rumble(0, 1, 200)

    if spieler_b.rect.colliderect(ball.rect):
        print("Zusammenstoß P2")
        ball.bewegung.x = -ball.bewegung.x
        ball.rect.right = spieler_b.rect.left
        ballwechsel += 1
        if pygame.joystick.get_count() >= 1:
            joystick_1.rumble(0, 1, 200)
Eine offensichtliche Methode die man bei beiden Klassen jetzt hinzufügen könnte, wäre das sie sich selbst auf ein `Surface` malen können:

Code: Alles auswählen

class Spieler:
    def __init__(self, farbe):
        self.farbe = farbe
        self.rect = pygame.Rect(0, 0, SCHLAEGERBREITE, SCHLAEGERHOEHE)
        self.bewegung = 0
        self.punkte = 0

    def draw(self, screen):
        pygame.draw.rect(screen, self.farbe, self.rect)


class Ball:
    def __init__(self, farbe, rect):
        self.farbe = farbe
        self.rect = rect
        self.bewegung = pygame.Vector2(5, 5)

    def draw(self, screen):
        pygame.draw.ellipse(screen, self.farbe, self.rect)

...

    spieler_a.draw(screen)
    spieler_b.draw(screen)
    ball.draw(screen)
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Patsche hat geschrieben: Freitag 14. Juli 2023, 22:17 Allgemein ist der Ton meist sehr grob in IT-Affinen Foren.
Da werden Anfänger eher belächelt, als konstruktiv geholfen.
Dabei haben alle mal klein angefangen. :)
Das ein "Profi" die Geduld verliert und ungehalten wird, kommt eher selten vor. Zumeist gibt es dann einfach keine Antwort mehr. Die "rauen Töne" kommen zumeist von anderen.
Benutzeravatar
__blackjack__
User
Beiträge: 13122
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@kbr: Ist auch eine Frage was jemand als grob empfindet. Nicht wenige Anfänger nehmen nüchterne Kritik am Code auch als persönlichen Angriff wahr. Oder erwarten so ein pädagogisches ”Sandwich”: Was nettes, flauschig formulierte Kritik, und dann wieder was nettes.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Patsche
User
Beiträge: 43
Registriert: Samstag 23. Oktober 2021, 00:17

Ich bleibe mal in diesem Thema und stelle mal eine Frage zu Klassen.
Vorweg:
Das ist ja mal richtig schön damit zu arbeiten. Das erleichtert die Sache wesentlich. Nun möchte ich auch fachgerecht ein main-Funktion verwenden, doch es wird dann einfach nicht durchgeführt.
Wo ist mein Fehler?

Ich folgenden Code in meiner Spielerei:

Code: Alles auswählen

class Auto: 
    def __init__ (self, marke, farbe, geschwindigkeit, kraftstoffart):
        self. marke = marke
        self.farbe = farbe
        self.geschwindigkeit = geschwindigkeit
        self.kraftstoffart = kraftstoffart

    def lackieren (self):
        print("Welche Farbe soll dein Auto haben? ")
        self.farbe = input()  

def main():

    auto1 = Auto("VW", "gelb", 50, "Benzin")
    auto2 = Auto("Opel", "blau", 70, "Diesel")
    auto3 = Auto("Merzedes", "schwarz", 100, "Strom")
    auto4 = Auto("Renault", "grün", 60, "Biogas")
    
    print("Vor der Methode lackieren")
    print(auto1.farbe)
    #auto 1 fährt in die Werkstatt zum Lackieren
    auto1.lackieren()
    print("Nach der Methode lackieren")
    print(auto1.farbe)
Und was ich auch noch nicht weiß ist, ob ich in der main Funktion die 4 Autos instanziere (richtiges Wort?) Oder auch schon vor der Funktion?
Wie muss das richtig heißen? Bin für Tipps und oder Lösung dankbar.
Sirius3
User
Beiträge: 17759
Registriert: Sonntag 21. Oktober 2012, 17:20

Es fehlt der Aufruf der main-Funktion am Ende:

Code: Alles auswählen

if __name__ == "__main__":
    main()
Benutzeravatar
Patsche
User
Beiträge: 43
Registriert: Samstag 23. Oktober 2021, 00:17

Manchmal ist es echt zum Verzweifeln.....
Jetzt bin ich auf die Lösung gekommen. Dabei habe ich die ganze Zeit erstmal selbst überlegt und geforscht.....

Ich definiere ja nur die main Funktion.

Ich muss sie am Ende natürlich auch aufrufen........
Die Instanzierung der verschiedenen Autos muss dann vor der Definition der main-Funktion passieren.

So funktioniert es, wie gewünscht:

Code: Alles auswählen

class Auto: 
    def __init__ (self, marke, farbe, geschwindigkeit, kraftstoffart):
        self. marke = marke
        self.farbe = farbe
        self.geschwindigkeit = geschwindigkeit
        self.kraftstoffart = kraftstoffart

    def lackieren (self):
        print("Welche Farbe soll dein Auto haben? ")
        self.farbe = input()
        
auto1 = Auto("VW", "gelb", 50, "Benzin")
auto2 = Auto("Opel", "blau", 70, "Diesel")
auto3 = Auto("Merzedes", "schwarz", 100, "Strom")
auto4 = Auto("Renault", "grün", 60, "Biogas")

def main():
    print("Vor der Methode lackieren")
    print(auto1.farbe)
    #auto 1 fährt in die Werkstatt zum Lackieren
    auto1.lackieren()
    print("Nach der Methode lackieren")
    print(auto1.farbe)

main()
Benutzeravatar
Patsche
User
Beiträge: 43
Registriert: Samstag 23. Oktober 2021, 00:17

Sirius3 hat geschrieben: Montag 17. Juli 2023, 21:21 Es fehlt der Aufruf der main-Funktion am Ende:

Code: Alles auswählen

if __name__ == "__main__":
    main()
 
Wozu dient die if-Abfrage? Ist das so "richtiger" oder besser oder sagt es die Konvention?

PS:
Habe gerade noch einen Fehler in der Forenfunktion entdeckt. Wenn ich einen Beitrag zitiere, der Code-Tags enthält, dann wird der Code-Tag nicht geschlossen.
Die ganze Antwort danach wird dann also auch als Code erkannt.
Kann das mal jemand nachprüfen, ob das nur bei mir passiert?
Zuletzt geändert von Patsche am Montag 17. Juli 2023, 21:32, insgesamt 1-mal geändert.
nezzcarth
User
Beiträge: 1638
Registriert: Samstag 16. April 2011, 12:47

Code: Alles auswählen

Die Instanzierung der verschiedenen Autos muss dann vor der Definition der main-Funktion passieren.
Nein, das gehört in dem Fall in die Main-Funktion. Globale Variablen versucht man nach Kräften zu vermeiden, weil man sich damit allerlei Probleme einhandelt.

Für den Aufuf der Main-Funktion benutzt man das Idiom, das Sirius3 gezeigt hatte:

Code: Alles auswählen

if __name__ == '__main__':
    main()
Jedes Python-File kann theoretisch als Modul in anderen Python-Files importiert werden. Das If-Statment sorgt dafür, dass die Main nur dann aufgerufen wird, wenn die Datei explizit ausgeführt wird, nicht jedoch beim Import.


Edit:
Manchmal möchte man Konstanten haben. Die dürfen dann auch global sein. Per Konvention werden sie in Großbuchstaben geschrieben und kommen nach oben, gleich hinter die Imports. In dem konkreten Fall bieten sich Konstanten m.M.n. jedoch nicht an.
Benutzeravatar
Patsche
User
Beiträge: 43
Registriert: Samstag 23. Oktober 2021, 00:17

Aaaaaaah .....vielen Dank für eure Hilfe.

Code: Alles auswählen

class Auto: 
    def __init__ (self, marke, farbe, geschwindigkeit, kraftstoffart):
        self. marke = marke
        self.farbe = farbe
        self.geschwindigkeit = geschwindigkeit
        self.kraftstoffart = kraftstoffart

    def lackieren (self):
        print("Welche Farbe soll dein Auto haben? ")
        self.farbe = input()

def main():
    auto1 = Auto("VW", "gelb", 50, "Benzin")
    auto2 = Auto("Opel", "blau", 70, "Diesel")
    auto3 = Auto("Merzedes", "schwarz", 100, "Strom")
    auto4 = Auto("Renault", "grün", 60, "Biogas")
    print("Vor der Methode lackieren")
    print(auto1.farbe)
    #auto 1 fährt in die Werkstatt zum Lackieren
    auto1.lackieren()
    print("Nach der Methode lackieren")
    print(auto1.farbe)

if __name__ == '__main__':
    main()
Antworten