Seite 1 von 1

pygame code verbessern

Verfasst: Montag 28. Juni 2021, 09:52
von The Hit-Man
Ich habe mir eine Methode geschrieben mit der ich meine Sprites und Animationen lade. Mein Problem ist jetzt, das diese Methode nach einem Mausklick ausgeführt wird um mein Spielfeld neu anzuzeigen ( liegt also in der Hauptschleife des Spiels ). Dabei werden die Spites ja immer neu von der Platte geladen dadurch harkt das Spiel ein klein wenig. Zwar nur ganz minimal aber man merkt es eben. Jetzt stehe ich auf dem Schlauch, die Sache ein wenig eleganter zu lösen. Ich habe schon versucht, die Spites unter __init__ einmal zu laden, sprich:

Code: Alles auswählen

self.diagreen = sprites('gfx/sprites/diagreen.json', 'gfx/sprites/diagreen.png')
und dann einfach zu ersetzen in der Methode:

Code: Alles auswählen

self.spritemap.append(self.diagreen)
es wird dann auch nicht gemeckert, allerdings fehlen mir dann Sprites. sind einfach nicht zu sehen und das Spiel, spielt auch ein wenig verrückt. Kann mir dabei jemand nen Tip geben?
Achja, die Methode self.setFields ist dann dafür da um die Sprites mittig auf den Bildschirm zu setzen.

Code: Alles auswählen

    #
    # Alle Sprites laden ( in richtiger Reihenfolge )
    #
    def makePlayfield(self):
        self.spritemap = []
        for i in range(len(self.playmap)):
            if self.playmap[i] == 0:
                self.spritemap.append(sprites('gfx/sprites/diagreen.json', 'gfx/sprites/diagreen.png'))

            if self.playmap[i] == 1:
                self.spritemap.append(sprites('gfx/sprites/diayellow.json', 'gfx/sprites/diayellow.png'))

            if self.playmap[i] == 2:
                self.spritemap.append(sprites('gfx/sprites/diared.json', 'gfx/sprites/diared.png'))
        self.setFields()



Re: pygame code verbessern

Verfasst: Montag 28. Juni 2021, 10:15
von Sirius3
Mit Deinem Codeausschnitt kann man die Frage nicht beantworten.
Wenn sich playmap nicht ändert, dann ist es kein Problem, das in __init__ einzubauen.
Methoden schreibt man, wie Variablen und Attribute komplett klein.
Über einen Index iteriert man nicht, weil man direkt über die Liste iterieren kann.
Wenn man sich gegenseitig ausschließende if`s hat, dann benutzt man elif.
Wenn man so eine simple 1:1-Zuordnung hat, dann braucht man gar kein if.

Code: Alles auswählen

    def make_playfield(self):
        self.spritemap = [
            sprites(f'gfx/sprites/{self.SPRITES[sprite_nr]}.json', f'gfx/sprites/{self.SPRITES[sprite_nr]}.png')
        ]
        self.set_fields()
Besser wäre es, die Sprites einmal als Wörterbuch zu speichern und dann nur darauf zu verweisen.

Re: pygame code verbessern

Verfasst: Montag 28. Juni 2021, 10:31
von __deets__
Und eine kleine Offtopic Bemerkung: man harkt seinen Garten. Dabei hakt es mit dem Fortschritt, weil Bier & Grillgut locken.

Re: pygame code verbessern

Verfasst: Montag 28. Juni 2021, 11:02
von Sirius3
Ähm, da hat es einige Zeile nicht mitkopiert:

Code: Alles auswählen

    SPRITES = [
        "diagreen",
        "diayellow",
        "diared",
    ]

    def make_playfield(self):
        self.spritemap = [
            sprites(f'gfx/sprites/{self.SPRITES[sprite_nr]}.json', f'gfx/sprites/{self.SPRITES[sprite_nr]}.png')
            for sprite_nr in self.playmap
        ]
        self.set_fields()

Re: pygame code verbessern

Verfasst: Montag 28. Juni 2021, 11:10
von The Hit-Man
Doch, die playmap ändert sich. Da ist das Spielfeld drin aus dem die Sprites dann neu aufgebaut werden. Ich denke, ich muß das überdenken und in die self.set_fields() rein setzen. In der Methode werden die Sprites ja eigentlich angezeigt. Es war eben nur sehr viel einfacher, komplett alles neu zu bauen. Ich änder das mal lieber gleich, sonst wird es hinterher zu aufwendig. Aber danke ;)

Ich weiß, mein Programmierstiel ist und war nie der beste.

Re: pygame code verbessern

Verfasst: Montag 28. Juni 2021, 13:06
von The Hit-Man
@Sirius3:
leider komme ich mit deinem Code nicht zurecht. Liegt vielleicht da dran, das ich gerade noch Python2.7 nutze?
Hab dann aber weiter probiert. Und Zwar habe ich noch mal so getestet:
Jetzt sollten doch durch die Schleife, 10 Objekte angezeigt werden. Es werden aber nur 3 angezeigt. Wieso denn? Wenn ich die Schleife weg lasse und per Hand jedes einzelne append schreibe, geht es komischer Weise. Was mache ich denn da falsch?

Code: Alles auswählen

        self.counter = 10
        self.spritemap = []
        self.diagreen = sprites('gfx/sprites/diagreen.json', 'gfx/sprites/diagreen.png')
        self.diayellow = sprites('gfx/sprites/diayellow.json', 'gfx/sprites/diayellow.png')
        self.diared = sprites('gfx/sprites/diared.json', 'gfx/sprites/diared.png')
        for i in range(0, self.counter):
            self.spritemap.append(self.diagreen)
            self.spritemap.append(self.diared)
            self.spritemap.append(self.diayellow)
        for i in range(0, self.counter):
            self.spritemap[i].setxy(randrange(800), randrange(600))

Re: pygame code verbessern

Verfasst: Montag 28. Juni 2021, 13:11
von The Hit-Man
ne, Komando zurück. Auch das append per Hand geht nicht :(

Re: pygame code verbessern

Verfasst: Montag 28. Juni 2021, 13:54
von Sirius3
Wie kommst Du nicht zurecht? Was für eine Fehlermeldung bekommst Du?
Zeige den gesamten relevanten Teil Deines Codes. Aus den Codefragementen können wir nichts rauslesen.

Re: pygame code verbessern

Verfasst: Montag 28. Juni 2021, 14:11
von The Hit-Man
Vielleicht sollte ich erstmal den Hintergrund erklären. Ich habe Sprites, mit 3 verschiedenen Farben ( die Dinger sind auch animiert ). Nun habe ich ein 3x3 großes Feld in dem die Sprite mit zufälliger Farbe gesetzt werden sollen und anklickbar sein sollen. Dabei sollen sie die Farbe wechseln. Das ist eigentlich alles. Mit meinem alten Code, wo immer die Sprites neu von der Festplatte geladen und aufgebaut werden funktioniert ja auch so weit alles. Außer eben das es dann hakt ( man sieht es kaum aber man merkt es ) wenn man das Sprite anklickt ( dann wird ja wieder auf die Platte zugegriffen).
Jetzt habe ich leider schon nen Knick im Kopf. Ich habe da bestimmt nur nen kleinen Denkfehler drin. Ist mein erstes Spiel-Projekt. Auf dem C64er in Assembler hätte ich es anders gelöst ;)
Ich schicke mal meine Sprite Klasse mit, die ich mir gebaut hatte.
So weit so gut. Kann mir also meine Sprites anzeigen lassen. Jetzt hänge ich wie gesagt an dem Spielfeld dran und komme irgendwie nicht weiter.

Code: Alles auswählen

#
# sprites einlesen.
# wichtig ist es hier den richtigen Pfad zu bauen damit die Dateien fuer
# die Grafiken und so weiter gefunden werden ( fuer Android ).
#
class sprites(object):
    def __init__(self, jsonfile, spritefile):
        self.screen_x = 0  # screen_x  # x Position vom Sprite auf dem Bildschirm X
        self.screen_y = 0  # screen_y  # y Position vom Sprite auf dem Bildschirm  Y
        self.sprite = []  # komplette Animation
        self.anicounter = 0  # Zaehler der Animation
        self.animax = 0  # maximale Bilder der Animation
        self.timer_range = 60  # Zeit des Timers bis die Animation gestartet wird
        self.timer_stop = \
            datetime.datetime.utcnow() + \
            datetime.timedelta(seconds=randrange(self.timer_range))
        self.sprite_w = 0  # Breite des aktuellen Sprites
        self.sprite_h = 0  # Hoehe des aktuellen Sprites
        self.audio_click = music('/gfx/audio/sfx/click_1.wav')

        with open(os.getcwd() + "/" + jsonfile, 'r') as myfile:
            data = myfile.read()
        obj = json.loads(data)
        # print ("Sprites: " + str((len(obj))))
        sprites_sheet = pygame.image.load(os.getcwd() + "/" + spritefile).convert()

        #
        # einzelne, leere Sprites erstellen in der Groesse der Sprites im .json File
        #
        for images in range(len(obj)):
            self.sprite.append(pygame.Surface((int(obj[images]['width']), int(obj[images]['height']))))

        #
        # die leeren Sprites, aus dem Spritesheet fuellen
        #
        for images in range(len(self.sprite)):
            self.sprite[images].blit(sprites_sheet, (0, 0),
                                     (int(obj[images]['x']), int(obj[images]['y']),
                                      int(obj[images]['width']), int(obj[images]['height'])))
            self.sprite[images].set_colorkey((0, 0, 0))
            self.sprite_w = int(obj[images]['width'])
            self.sprite_h = int(obj[images]['height'])
        self.animax = (len(self.sprite))

    #
    # die Logig der Sprites starten ( Animation usw. )
    #
    def doLogic(self, screen):
        screen.blit(self.sprite[self.anicounter], (self.screen_x, self.screen_y))
        self.rotate()

    #
    # Die Animation einmal abspielen und Timer wieder auf
    # Zufall stellen
    #
    def rotate(self):
        if datetime.datetime.utcnow() > self.timer_stop:
            self.anicounter += 1
            if self.anicounter >= self.animax:
                self.anicounter = 0
                self.timer_stop = datetime.datetime.utcnow() + \
                                  datetime.timedelta(seconds=randrange(self.timer_range))

    def getSize(self):
        return self.sprite_w, self.sprite_h

    #
    # fuer neu berechnete Sprites werden die Koordinaten dann hier wieder gesetzt
    #
    def setxy(self, x, y):
        self.screen_x = x
        self.screen_y = y

    def getxy(self):
        return (self.screen_x, self.screen_y)

    #
    # wurde ein Sprite angeclickt? Wird ueber die Mausposition berechnet und True
    # oder False zurueckgeben. Wenn Sprite angeclickt dann True an sonsten False
    #
    def checkclick(self):
        screen_x, screen_y = self.getxy()
        sprite_w, sprite_h = self.getSize()
        mouse_x, mouse_y = pygame.mouse.get_pos()

        if int(mouse_x) in range(int(screen_x), int(screen_x) + int(sprite_w)):
            if int(mouse_y) in range(int(screen_y), int(screen_y) + int(sprite_h)):
                self.audio_click.doLogic(0)
                return True
        return False

Re: pygame code verbessern

Verfasst: Montag 28. Juni 2021, 14:51
von The Hit-Man
Ich glaube ich habe die Lösung ... muß sie aber noch ausprobieren. Ich sage dann bescheid ...

Re: pygame code verbessern

Verfasst: Montag 28. Juni 2021, 15:50
von Sirius3
Klasse schreibt man mit großem Anfangsbuchstaben.
Für Timer benutzt man kein datetime, sondern time.time() (ab Python3 time.monotonic).
`json.load` lädt direkt aus einer geöffneten Datei, das `my` in `myfile` ist unsinnig, weil es kein ourfile gibt.
Pfade setzt man nicht per + zusammen, os.getcwd zu benutzen ist unsinn, weil Pfade automatisch relativ zum aktuellen Verzeichnis sind.
Wie schon oben geschrieben iteriert man nicht über einen Index. Der Name `images` für einen Index ist sehr verwirrend.
`width` und `height` sind hoffentich schon ints.
Ein Attribut innerhalb einer for-Schleife zu setzten ist selten sinnvoll, und ein Zeichen dafür, dass irgendwas nicht stimmt, denn nur die letzte Zuweisung bleibt erhalten. Wie ist das mit sprite_w und sprite_h?
`screen_x` und `screen_y` werden immer nur zusammen benutzt. Warum nicht gleich ein Tuple?

Ein `x in range(...)` ist seltsam, man vergleich normalerweise mit <.

Code: Alles auswählen

#
# sprites einlesen.
# wichtig ist es hier den richtigen Pfad zu bauen damit die Dateien fuer
# die Grafiken und so weiter gefunden werden ( fuer Android ).
#
class Sprites(object):
    def __init__(self, jsonfile, spritefile):
        self.screen_xy = (0, 0)  # x/y Position vom Sprite auf dem Bildschirm
        self.anicounter = 0  # Zaehler der Animation
        self.timer_range = 60  # Zeit des Timers bis die Animation gestartet wird
        self.timer_stop = time.time() + randrange(self.timer_range))
        self.sprite_w = 0  # Breite des aktuellen Sprites
        self.sprite_h = 0  # Hoehe des aktuellen Sprites
        self.audio_click = music('/gfx/audio/sfx/click_1.wav')

        with open(jsonfile, 'rb') as file:
            images = json.loads(file)
        # print ("Sprites: " + str((len(obj))))
        sprites_sheet = pygame.image.load(spritefile).convert()

        self.sprites = [] # komplette Animation
        for image in images:
            # einzelne, leere Sprites erstellen in der Groesse der Sprites im .json File
            sprite = pygame.Surface((image['width'], image['height']))
            # die leeren Sprites, aus dem Spritesheet fuellen
            sprite.blit(sprites_sheet, (0, 0), (image['x'], image['y'], image['width'], image['height']))
            sprite.set_colorkey((0, 0, 0))
            self.sprites.append(sprite)
            # komisch:
            self.sprite_w = image['width']
            self.sprite_h = image['height']

    #
    # die Logik der Sprites starten ( Animation usw. )
    #
    def do_logic(self, screen):
        screen.blit(self.sprites[self.anicounter], self.screen_xy)
        self.rotate()

    #
    # Die Animation einmal abspielen und Timer wieder auf
    # Zufall stellen
    #
    def rotate(self):
        if time.time() > self.timer_stop:
            self.anicounter += 1
            if self.anicounter >= len(self.sprites):
                self.anicounter = 0
                self.timer_stop = time.time() + randrange(self.timer_range)

    def get_size(self):
        return self.sprite_w, self.sprite_h

    #
    # fuer neu berechnete Sprites werden die Koordinaten dann hier wieder gesetzt
    #
    def set_xy(self, x, y):
        self.screen_x = (x, y)
        self.screen_y = y

    def get_xy(self):
        return self.screen_xy

    #
    # wurde ein Sprite angeclickt? Wird ueber die Mausposition berechnet und True
    # oder False zurueckgeben. Wenn Sprite angeclickt dann True an sonsten False
    #
    def checkclick(self):
        screen_x, screen_y = self.screen_xy
        sprite_w, sprite_h = self.get_size()
        mouse_x, mouse_y = pygame.mouse.get_pos()

        if screen_x <= mouse_x < screen_x + sprite_w:
            if screen_y <= mouse_y < screen_y + sprite_h:
                self.audio_click.do_logic(0)
                return True
        return False
Der Code hat jetzt aber auch nichts mit Deinem ursprünglichen Problem zu tun?

Re: pygame code verbessern

Verfasst: Mittwoch 30. Juni 2021, 13:30
von The Hit-Man
Hatte dann doch die Lösung. Es war einfach besser, Sprites auszuschalten wenn ich sie nicht brauche oder einzuschalten wenn ich sie braucht. Also entweder kamen sie mit in den Blit oder auch nicht. So gehts dann ... Und danke fürs Helfen.