Kollisionsabfrage

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
lucotheboss
User
Beiträge: 1
Registriert: Mittwoch 16. September 2020, 06:53

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()
Benutzeravatar
__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:

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()
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.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten