Liebe Forum-Leser,
ich arbeite derzeit an einem projekt für meine Schule da ich erst seit 1 woche mit python arbeite bin ich grade nicht der beste dabei. Ich soll für die schule ein spiel programmieren meine idee war es ein labyrinth zu überqueren mit einem auto. Da ich zurzeit ein problem habe wollte ich euch nach hilfe bitten. Ich versuche seit längerem bei dem labyrinth ein Kollisionsabfrage zu erstellen aber es klappt nicht so wie ich es will.
import pygame as pg
import random as rnd
BREITE = HÖHE = 800
SPALTEN = ZEILEN = 24
ZE_BH = BREITE // SPALTEN
delta_linien = {'l': [(0,0), (0,ZE_BH)], 'r': [(ZE_BH, 0), (ZE_BH, ZE_BH)],
'o': [(0,0), (ZE_BH, 0)], 'u': [(0, ZE_BH), (ZE_BH, ZE_BH)]}
delta_nachbarn = {'l':(-ZE_BH, 0), 'r': (ZE_BH,0), 'o': (0,-ZE_BH), 'u':(0,ZE_BH)}
richtung_invers = {'l':'r', 'r':'l', 'o':'u', 'u':'o'}
pg.init()
screen = pg.display.set_mode([BREITE, HÖHE])
farbe_hintergrund = pg.Color('Blue')
farbe_linie = pg.Color('White')
raster = {}
for i in range(SPALTEN*ZEILEN):
pos = i % SPALTEN * ZE_BH, i // SPALTEN * ZE_BH
raster[pos] = {b for b in 'lrou'}
def add_pos(pos1, pos2):
return pos1[0]+pos2[0], pos1[1]+pos2[1]
def zeichne_zelle(pos, wände):
for wand in wände:
delta_von, delta_bis = delta_linien[wand]
von = add_pos(pos,delta_von)
bis = add_pos(pos,delta_bis)
pg.draw.line(screen, farbe_linie, von, bis, 2)
def pg_quit():
for ereignis in pg.event.get():
if ereignis.type == pg.QUIT or \
(ereignis.type == pg.KEYDOWN and ereignis.key == pg.K_ESCAPE):
return True
def nachbarn_ermitteln(pos):
nachb = []
for richtung, delta in delta_nachbarn.items():
neue_pos = add_pos(pos, delta)
if neue_pos not in raster: continue
nachb.append((richtung, neue_pos))
rnd.shuffle(nachb)
return nachb
def labyrinth_erstellen(pos_aktuell, richtung_von):
besucht.add(pos_aktuell)
raster[pos_aktuell].remove(richtung_von)
nachb = nachbarn_ermitteln(pos_aktuell)
for richtung_nach, pos_neu in nachb:
if pos_neu in besucht: continue
raster[pos_aktuell].remove(richtung_nach)
labyrinth_erstellen(pos_neu, richtung_invers[richtung_nach])
besucht = set()
labyrinth_erstellen((0,0), 'l')
while not pg_quit():
screen.fill(farbe_hintergrund)
for pos, wände in raster.items():
zeichne_zelle(pos, wände)
pg.display.flip()
pg.quit()
Kollisionsabfrage
- __blackjack__
- User
- Beiträge: 13111
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@lucotheboss: Eingerückt wird in Python vier Leerzeichen pro Ebene, nicht zwei. Und wenn man den Quelltext hier im Forum in Code-Tags setzt, dann bleibt die Eingerückung auch sichtbar.
Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.
Funktionen und Methoden bekommen alles was sie ausser Konstanten benötigen als Argument(e) übergeben. Also keine globalen Variablen.
Konstanten schreibt man KOMPLETT_GROSS.
`random` sollte man nicht abkürzen. Generell sollte man keine kryptischen Abkürzungen verwenden. Wenn man `nachbarn` meint sollte man nicht einfach beim b aufhören und `nachb` schreiben.
``{b for b in "lrou"}`` macht als „comprehension“ nicht wirklich sinn. Da ist ``set("lrou")`` kürzer und schneller erfasst beim lesen.
Beim füllen von `raster` ist es IMHO nicht so toll erst ein `i` zu generieren aus dem man Spalten und Zeilenwert erst umständlich errechnen muss, statt gleich die passenden Werte zu generieren.
`besucht` wird nur in `labyrinth_erstellen()` verwendet ist aber eine globale Variable. Das sollte so nicht. Die Funktion braucht zusätzlich das `raster` als Argument.
Blöcke sollten immer in einer eigenen Zeile geschrieben werden, auch wenn sie nur aus einer Zeile bestehen.
``continue`` sollte man vermeiden. Das ist ein unbedingter Sprung den man nicht an der Eingerückung ablesen kann. Das kann also leichter überlesen werden. Insbesondere zusammen mit dem Punkt im vorherigen Absatz.
Der Name `pg_quit()` ist irreführend weil da nichts verlassen wird. Da wird geprüft ob die Hauptschleife verlassen werden soll. Ausserdem ist das visuell verdammt nah an dem ebenfalls verwendeten ``pg.quit()` dran.
Die Funktion gibt zudem `True` oder `None` zurück. Das sollte `True` oder `False` sein.
Überarbeitet:
Von Kollisionstest ist in dem Quelltext nichts zu sehen. Was ist denn das konkrete Problem? Du hast dann ja wahrscheinlich die Position des Spielers und die Information in welche Richtung er sich bewegen will. Damit kann man leicht prüfen ob in der aktuellen Zelle in der Richtung eine Wand ist oder nicht.
Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.
Funktionen und Methoden bekommen alles was sie ausser Konstanten benötigen als Argument(e) übergeben. Also keine globalen Variablen.
Konstanten schreibt man KOMPLETT_GROSS.
`random` sollte man nicht abkürzen. Generell sollte man keine kryptischen Abkürzungen verwenden. Wenn man `nachbarn` meint sollte man nicht einfach beim b aufhören und `nachb` schreiben.
``{b for b in "lrou"}`` macht als „comprehension“ nicht wirklich sinn. Da ist ``set("lrou")`` kürzer und schneller erfasst beim lesen.
Beim füllen von `raster` ist es IMHO nicht so toll erst ein `i` zu generieren aus dem man Spalten und Zeilenwert erst umständlich errechnen muss, statt gleich die passenden Werte zu generieren.
`besucht` wird nur in `labyrinth_erstellen()` verwendet ist aber eine globale Variable. Das sollte so nicht. Die Funktion braucht zusätzlich das `raster` als Argument.
Blöcke sollten immer in einer eigenen Zeile geschrieben werden, auch wenn sie nur aus einer Zeile bestehen.
``continue`` sollte man vermeiden. Das ist ein unbedingter Sprung den man nicht an der Eingerückung ablesen kann. Das kann also leichter überlesen werden. Insbesondere zusammen mit dem Punkt im vorherigen Absatz.
Der Name `pg_quit()` ist irreführend weil da nichts verlassen wird. Da wird geprüft ob die Hauptschleife verlassen werden soll. Ausserdem ist das visuell verdammt nah an dem ebenfalls verwendeten ``pg.quit()` dran.
Die Funktion gibt zudem `True` oder `None` zurück. Das sollte `True` oder `False` sein.
Überarbeitet:
Code: Alles auswählen
#!/usr/bin/env python3
import random
import pygame
BREITE = HOEHE = 800
SPALTEN = ZEILEN = 24
ZELLEN_KANTENLAENGE = BREITE // SPALTEN
HINTERGRUNDFARBE = pygame.Color("Blue")
LINIENFARBE = pygame.Color("White")
#
# TODO Die leicht kryptischen einbuchstabigen Zeichenketten durch einen
# `enum.Flag`-Typ ersetzen.
#
LINIENKOORDINATEN_DELTA_ZU_RICHTUNG = {
"l": [(0, 0), (0, ZELLEN_KANTENLAENGE)],
"r": [
(ZELLEN_KANTENLAENGE, 0),
(ZELLEN_KANTENLAENGE, ZELLEN_KANTENLAENGE),
],
"o": [(0, 0), (ZELLEN_KANTENLAENGE, 0)],
"u": [
(0, ZELLEN_KANTENLAENGE),
(ZELLEN_KANTENLAENGE, ZELLEN_KANTENLAENGE),
],
}
DELTA_NACHBAR_ZU_RICHTUNG = {
"l": (-ZELLEN_KANTENLAENGE, 0),
"r": (ZELLEN_KANTENLAENGE, 0),
"o": (0, -ZELLEN_KANTENLAENGE),
"u": (0, ZELLEN_KANTENLAENGE),
}
GEGENRICHTUNG_ZU_RICHTUNG = {"l": "r", "r": "l", "o": "u", "u": "o"}
assert (
LINIENKOORDINATEN_DELTA_ZU_RICHTUNG.keys()
== DELTA_NACHBAR_ZU_RICHTUNG.keys()
== GEGENRICHTUNG_ZU_RICHTUNG.keys()
)
def addiere_positionen(position_a, position_b):
return position_a[0] + position_b[0], position_a[1] + position_b[1]
def ermittle_nachbarn(waende_zu_position, position):
nachbarn = list()
for richtung, delta in DELTA_NACHBAR_ZU_RICHTUNG.items():
nachbarposition = addiere_positionen(position, delta)
if nachbarposition in waende_zu_position:
nachbarn.append((richtung, nachbarposition))
#
# TODO Das ist hier eigentlich der falsche Ort für das mischen.
#
random.shuffle(nachbarn)
return nachbarn
def erstelle_labyrinth(
waende_zu_position,
aktuelle_position,
richtung_von,
besuchte_positionen=None,
):
if besuchte_positionen is None:
besuchte_positionen = set()
besuchte_positionen.add(aktuelle_position)
waende_zu_position[aktuelle_position].remove(richtung_von)
for richtung_nach, neue_position in ermittle_nachbarn(
waende_zu_position, aktuelle_position
):
if neue_position not in besuchte_positionen:
waende_zu_position[aktuelle_position].remove(richtung_nach)
erstelle_labyrinth(
waende_zu_position,
neue_position,
GEGENRICHTUNG_ZU_RICHTUNG[richtung_nach],
besuchte_positionen,
)
def soll_beenden():
return any(
ereignis.type == pygame.QUIT
or ereignis.type == pygame.KEYDOWN
and ereignis.key == pygame.K_ESCAPE
for ereignis in pygame.event.get()
)
def zeichne_zelle(screen, position, waende):
for wand in waende:
delta_von, delta_bis = LINIENKOORDINATEN_DELTA_ZU_RICHTUNG[wand]
pygame.draw.line(
screen,
LINIENFARBE,
addiere_positionen(position, delta_von),
addiere_positionen(position, delta_bis),
2,
)
def main():
pygame.init()
screen = pygame.display.set_mode([BREITE, HOEHE])
#
# TODO In dieser Datenstruktur würde man besser logische Koordinaten
# speichern und die beim Zeichnen in Bildschirmkoordinaten umwandeln.
#
richtungen = GEGENRICHTUNG_ZU_RICHTUNG.keys()
waende_zu_position = {
(x * ZELLEN_KANTENLAENGE, y * ZELLEN_KANTENLAENGE): set(richtungen)
for x in range(SPALTEN)
for y in range(ZEILEN)
}
erstelle_labyrinth(waende_zu_position, (0, 0), "l")
#
# FIXME Die Schleife verbrät 100% Prozessorzeit und sollte auf einen
# vernünftigen FPS-Wert gedrosselt werden. Siehe `pygame.Clock`.
#
while not soll_beenden():
screen.fill(HINTERGRUNDFARBE)
for position, waende in waende_zu_position.items():
zeichne_zelle(screen, position, waende)
pygame.display.flip()
pygame.quit()
if __name__ == "__main__":
main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman