Seite 1 von 1

Klasse wird nicht "gefunden" obwohl vorhanden

Verfasst: Freitag 13. Januar 2023, 14:03
von DerKian
Moin,
ich bin derzeit dabei ein Pacman Spiel zu programmieren und will das ganze Objektorientiert Programmieren. Nun habe ich meine gesamten Klassen in eine andere Datei ausgelagert um aus verschiedenen Punkten darauf zugreifen zu können. Leider wird die Klasse aber nicht gefunden.

Könnt ihr mir sagen woran es liegt ?

classes.py Code

Code: Alles auswählen

#Datei in der alle vorhandenen Klassen gespeichert werden
#KEIN AUSFÜHRBAREN CODE EINFÜGEN#

import pygame
from pacman import screen
from pacman import world
pygame.init()

#Erstellung von Sprite Gruppen
ghost_group = pygame.sprite.Group()
key_group = pygame.sprite.Group()

#Festlegung von Größen der Blöcke
tile_size = 50

#Variablen Festlegung für Klassen
game_over = 0

class Button():
    def __init__(self, x, y, image):
        self.image = image
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.clicked = False

    def draw(self):
        action = False

        #Mausposition
        pos = pygame.mouse.get_pos()

        #
        if self.rect.collidepoint(pos):
            if pygame.mouse.get_pressed()[0] == 1 and self.clicked == False:
                action = True
                self.clicked = True

        if pygame.mouse.get_pressed()[0] == 0:
            self.clicked = False


        #
        screen.blit(self.image, self.rect)

        return action

class Player():
    def __init__(self, x, y):
        self.reset(x, y)



    def update(self, game_over):
        dx = 0
        dy = 0

        if game_over == 0:
            #"Einagbe"
            key = pygame.key.get_pressed()
            if key[pygame.K_LEFT]:
                dx -= 5
                self.counter += 1
                self.direction_x = -1
            if key[pygame.K_RIGHT]:
                dx += 5
                self.counter += 1
                self.direction_x = 1
            if key[pygame.K_UP]:
                dy -= 5
                self.direction_y = 1
            if key[pygame.K_DOWN]:
                dy += 5
                self.direction_y = -1
            if key[pygame.K_LEFT] == False and key[pygame.K_RIGHT] == False:
                self.counter = 0
                self.index = 0
                if self.direction_x == 1:
                    self.image = self.images_right[self.index]
                if self.direction_x == -1:
                    self.image = self.images_left[self.index]
                if self.direction_y == 1:
                    self.image = self.images_up[self.index]
                if self.direction_y == -1:
                    self.image = self.images_down[self.index]



            #Berührungen mti Gefahr
            for tile in world.tile_list:
                #X-Richtung
                if tile[1].colliderect(self.rect.x + dx, self.rect.y, self.width, self.height):
                    dx = 0
                #Y-Richtung
                if tile[1].colliderect(self.rect.x, self.rect.y + dy, self.width, self.height):
                    dy = 0
    
            if pygame.sprite.spritecollide(self, ghost_group, False):
                game_over = -1

            #Spieler Koordinaten Bewegung
            self.rect.x += dx
            self.rect.y += dy

        elif game_over == -1:
            self.image = self.dead_image
            if self.rect.y > 200:
                self.rect.y -= 5

        #Spieler auf dem Bildschirm
        screen.blit(self.image, self.rect)
        pygame.draw.rect(screen, (255, 255, 255), self.rect, 2)

        return game_over

    def reset(self, x, y):
        self.images_right = []
        self.images_left = []
        self.images_up = []
        self.images_down = []
        self.index = 0
        self.counter = 0
        for num in range(1, 5):
            bilder_right = pygame.image.load("bilder/pacman.png")
            bilder_right = pygame.transform.scale(bilder_right, (50, 50))
            bilder_left = pygame.transform.flip(bilder_right, True, False)
            bilder_up = pygame.transform.rotate(bilder_right, 90)
            bilder_down = pygame.transform.rotate(bilder_right, 270)
            self.images_right.append(bilder_right)
            self.images_left.append(bilder_left)
            self.images_up.append(bilder_up)
            self.images_down.append(bilder_down)
        self.dead_image = pygame.image.load("bilder/geist.png")
        self.image = self.images_right[self.index]
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.width = self.image.get_width()
        self.height = self.image.get_height()
        self.vel_y = 0
        self.direction_x = 0
        self.direction_y = 0

class World():
    def __init__(self, data):
        self.tile_list = []

        #Bilder laden
        umrandung_bilder = pygame.image.load("bilder/walls.jpg")
        boden_bilder = pygame.image.load("bilder/boden.png")


        row_count = 0
        for row in data:
            col_count = 0
            for tile in row:
                if tile == 1:
                    bilder = pygame.transform.scale(umrandung_bilder, (tile_size, tile_size))
                    bilder_rect = bilder.get_rect()
                    bilder_rect.x = col_count * tile_size
                    bilder_rect.y = row_count * tile_size
                    tile = (bilder, bilder_rect)
                    self.tile_list.append(tile)
                if tile == 2:
                    bilder = pygame.transform.scale(boden_bilder, (tile_size, tile_size))
                    bilder_rect = bilder.get_rect()
                    bilder_rect.x = col_count * tile_size
                    bilder_rect.y = row_count * tile_size
                    tile = (bilder, bilder_rect)
                    self.tile_list.append(tile)
                if tile == 3:
                    ghost = Gegner(col_count * tile_size, row_count * tile_size + 15)
                    ghost_group.add(ghost)
                if tile == 7:
                    key = Key(col_count * tile_size, row_count * tile_size + 15)
                    key_group.add(key)
                col_count += 1
            row_count += 1

    def draw(self):
        for tile in self.tile_list:
            screen.blit(tile[0], tile[1])
            pygame.draw.rect(screen, (255, 255, 255), tile[1], 2)



class Gegner(pygame.sprite.Sprite):
    def __init__(self, x, y):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("bilder/geist1.png")
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.move_direction = 1
        self.move_counter = 0

    def update(self):
        self.rect.x += self.move_direction
        self.move_counter += 1
        if abs(self.move_counter) > 50:
            self.move_direction *= -1
            self.move_counter *= -1

class Key(pygame.sprite.Sprite):
    def __init__(self, x, y):
        pygame.sprite.Sprite.__init__(self)
        bilder = pygame.image.load("bilder/key.png")
        self.image = pygame.transform.scale(bilder, (50, 50))
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
pacman lv1.py Code

Code: Alles auswählen

import pygame
from pygame.locals import *
from pygame import mixer
from time import sleep
from classes import *

pygame.init()

clock = pygame.time.Clock()
fps = 60

tile_size = 50
game_over = 0
main_menu = True

screen_width = 1000
screen_height = 1000

screen = pygame.display.set_mode((screen_width, screen_height))

pygame.display.set_caption("Pacman by Mustafa & Kian")

start_bilder = pygame.image.load("bilder/start_btn.png")
exit_bilder = pygame.image.load("bilder/exit_btn.png")
bg_bilder = pygame.image.load("bilder/bg.jpg")
restart_bilder = pygame.image.load("bilder/restart_btn.png")


#Sound
#pygame.mixer.music.load("bilder/music.wav")
#pygame.mixer.music.play(-1, 0.0, 5000)
#pygame.mixer.pre_init(44100, -16, 2, 512)
#mixer.init()

#game_over_fx = pygame.mixer.Sound("bilder/game_over.wav")
#game_over_fx.set_volume(0.5)

def lv1_sucess():
    print("PICKED")

world_data = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 
[1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 1], 
[1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1], 
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
[1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 5, 1, 0, 1, 1], 
[1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1], 
[1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1], 
[1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1], 
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1], 
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
[1, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 3, 0, 0, 3, 0, 0, 0, 0, 1], 
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 1], 
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
]

spieler = Player(100, 50)

world = World(world_data)

#Erstellung von Buttons
# start_button = Button(screen_width // 2 - 350, screen_height // 2, start_bilder)
# exit_button = Button(screen_width // 2 + 150, screen_height // 2, exit_bilder)
# restart_button = Button(screen_width // 2 - 50, screen_height // 2 + 100, restart_bilder)

run = True
while run:

    clock.tick(fps)

    screen.blit(bg_bilder, (0, 0))

    if main_menu == False:
        print("Menu")
    else:
        world.draw()

        if game_over == 0:
            ghost_group.update()
            key_group.update()

        ghost_group.draw(screen)
        key_group.draw(screen)


        game_over = spieler.update(game_over)

        #im Sterbefall:
        # if game_over == -1:
        #    if restart_button.draw():
        #         spieler.reset(100, screen_height - 130)
        #         game_over = 0


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

    pygame.display.update()

pygame.quit()
Danke im Voraus.
Viele Grüße
Kian

Re: Klasse wird nicht "gefunden" obwohl vorhanden

Verfasst: Freitag 13. Januar 2023, 14:07
von __deets__
Bitte die vollstaendige Fehlermeldung zeigen.

Re: Klasse wird nicht "gefunden" obwohl vorhanden

Verfasst: Freitag 13. Januar 2023, 15:09
von __blackjack__
@DerKian: Warum hast Du die gesamten Klassen in ein anderes Modul ausgelagert? Das macht man so nicht. Module enthalten Sachen die inhaltlich zusammengehören, nicht alle Klassen weil es Klassen sind.

Sternchen-Importe sind Böse™. Das macht Programme unnötig unübersichtlicher und fehleranfälliger und es besteht die Gefahr von Namenskollisionen.

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

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

Wenn das Programm objektorientiert ist, dann darf es erst recht keine globalen Variablen mehr geben. Sollte es auch ohne Klassen schon nicht, aber mit Klassen gibt es da gar keine Ausrede mehr für.

Edit: Ebenfalls ein Grund gegen die Aufteilung: Es sieht so aus als wenn die Module versuchen gegenseitig Sachen zu importieren. Also das Hauptmodul importiert die Klassen, aber das Modul mit den Klassen versucht `screen` und `world` aus dem Hauptmodul zu importieren. Wenn zwei Module sich gegenseitig brauchen, dann sind das offensichtlich nicht zwei getrennte Module. Oder die Aufteilung ist falsch.

Es sollte auch kein Code und keine Daten wiederholt werden müssen. Da darf zum Beispiel nicht in beiden Modulen `pygame.init()` stehen und die Konstante `tile_size` sollte auch nur *einmal* im gesamten Quelltext definiert werden.

Edit2: Die ganzen Vergleiche mit literalen Wahrheitswerten (oder dafür missbrauchten 0en und 1) sollten nicht sein. Wenn man einen Wahrheitswert mit ``== True`` vergleicht kommt da nur wieder `True` bei heraus wenn der sowieso schon wahr war und ``False`` wenn der sowieso schon unwahr war. Da kann man auch gleich den Wahrheitswert nehmen mit dem man verglichen hat. Und wenn man das Gegenteil testen will gibt es ``not``. Also alle ``== True``, ``== False``, ``!= True``, ``!= False``-Vergleiche schreibt man so nicht. Das ist entweder ``if bedingung:`` oder ``if not bedingung:``.

Re: Klasse wird nicht "gefunden" obwohl vorhanden

Verfasst: Freitag 13. Januar 2023, 16:05
von Sirius3
pygame.init sollte in der main-Funktion stehen. ghost_group und key_group müssen Attribute von World sein. tile_size ist eine Konstante TILE_SIZE und game_over total überflüssig.
Man vergleicht nicht mit literalen Wahrheitswerten (statt dessen: not self.clicked)

Die ganzen `draw`-Methoden braucht als Argument `screen`, so wie das ja bei Sprite auch der Fall ist.

Warum ist `game_over` in Player.update eine der beiden Zahlen 0 und -1? Das sollte ein Wahrheitswert sein. Außerdem fehlen der Funktion die Argumente world und screen, und eigentlich auch `key`. Die update-Methode macht eigentlich zu viel, da fehlt für mich eine draw-Methode.

Die ganzen pygame.image.load-Aufrufe sollten nicht mit dem aktuellen Arbeitsverzeichnis arbeiten, sondern die Bilder sollten aus einer Stelle relativ zu der Python-Datei geladen werden.
In World.__init__: wenn man noch zusätzlich zu den Werten in einer for-Schleife einen Index braucht, benutzt man enumerate.


*-Importe sind böse. Was ist denn in dem classes-Modul alles drin? Das ist kein sinnvoller Name, weil der nichts über die Verwendung sagt.
(Fast) alles, was in pacman lv1.py steht, sollte in Funktionen aufgeteilt werden. Es bietet sich an, die Initialisierung und Finalisierung in der main-Funktion zu haben, und dann in eine oder mehrer Funktionen zu verzweigen, die den eigentlichen Game-Loop enthalten. Dann kann man diese Funktionen einfach per `return` verlassen und muß keine Verrenkungen mit run-Flags machen.
Ich würde die Loops für Menu, Spiel und den Game-Over-Fall in getrennten Funktionen aufteilen, das macht die Schleifen übersichtlicher.
world_data steht idealerweise nicht direkt in der Pythondatei sondern wird separat geladen, dann ist das einfacher, neue Levels zu gestalten.