PyGame Surface Moving bug?

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
basti.gtr
User
Beiträge: 7
Registriert: Montag 11. April 2022, 11:08

Hallo,

ich kreiere gerade mein erstes Spiel mit PyGame. Ich habe einen Charakter, ein Objekt einer Sprite Klasse, den ich mit A und D nach links und nach rechts bewegen kann, mit Leertaste kann er springen. Sobald ich den Charakter bewege, werden, denke mal 60, da 60 Frames, Bilder von meinem Charakter in der Sekunde erstellt, an der Position an der er war.

Wer kann mir weiterhelfen? Was mache ich falsch ^^

Bild dazu gäbe es hier:
https://drive.google.com/drive/folders/ ... sp=sharing

Code: Alles auswählen

import pygame
from sys import exit

#Allgemeines
pygame.init()
screen = pygame.display.set_mode((1000, 550))
pygame.display.set_caption("Name of the Game")
clock = pygame.time.Clock()

class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()

        bg = pygame.image.load('gpx/bg.png').convert_alpha()
        background_surface = pygame.transform.rotozoom(bg, 0, 9.3)
        background_rect = background_surface.get_rect(center=(500, 300))
        screen.blit(background_surface, background_rect)


        player_stand = pygame.image.load('gpx/player/player_stand.png').convert_alpha()
        self.image = pygame.transform.rotozoom(player_stand, 0, 4)
        self.rect = self.image.get_rect(midbottom=(80, 450))

        self.movement = 0
        self.anziehungskraft = 0
[img][/img]
    def gravity(self):
        self.anziehungskraft += 0.8
        self.rect.y += self.anziehungskraft

        if self.rect.bottom >= 450:
            self.rect.bottom = 450


    def move(self):
        keys = pygame.key.get_pressed()

        #nach links laufen
        if keys[pygame.K_a]:
            self.movement = -4
            self.rect.x += self.movement

        #nach rechts laufen
        if keys[pygame.K_d]:
            self.movement = 4
            self.rect.x += self.movement


        if self.rect.bottom == 450:
            if keys[pygame.K_SPACE]:
                self.anziehungskraft = -12


        #So das er sobald ich den anderen Knopf (a oder d) drücke er direkt in die Richtung läuft
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_a:
                self.movement = 0
            if event.key == pygame.K_d:
                self.movement = 0



    def update(self):
        self.move()
        self.gravity()




#Gruppe erstellen und Player Objekt hinzufügen
player = pygame.sprite.GroupSingle()
player.add(Player())


#Game Loop
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()


    player.draw(screen)
    player.update()

    #Game Fenster aktualisieren
    pygame.display.update()
    clock.tick(60)
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@basti.gtr: Du malst halt nur *einmal* den Hintergrund, und darauf dann immer wieder den Spieler. Mindestens an den Stellen wo die letzte Sprite-Position war, müsste man den Hintergrund wieder herstellen bevor das Sprite erneut an anderer Stelle malt. Dazu kann man sich entweder den Hintergrund komplett irgendwo merken, oder das Sprite müsste sich den Hintergrund den es übermalt merken und beim nächsten mal wiederherstellen.

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

Wenn man das macht fällt auf, das `Player.__init__()` auf ein globales `screen` und `Player.move()` auf ein globales `event` zugreift, was nicht sein sollte. Letzteres ist auch noch fehlerhaft, weil `event` an der Stelle immer den *letzten* Wert aus der Schleife im Hauptprogramm hat, man also gar nicht alle `KEYUP`-Ereignisse erwischt und so ein bisschen Zufall ist, ob man das an der Stelle im Code dann mitbekommt oder nicht. Wobei der Code an der Stelle aber auch sinnlos ist, denn der hat überhaupt keinen Effekt. `self.movement` wird zwar auf 0 gesetzt, aber diese 0 wird nie irgendwo verwendet. Das Attribut `self.movement` wird effektiv nirgends verwendet. Das wird immer nur gesetzt und direkt nach dem setzen einmal verwendet, es macht also keinen Sinn sich das als Zustand zu merken.

Bei dem `screen` in der `__init__()` löst man das einfach dadurch das dieser Code dort sowieso nicht dort hingehört. Der Bildschirmhintergrung gehört nicht zum Spieler.

Kommentare sollen dem Leser einen Mehrwert über den Code geben. Faustregel: Kommentare beschreiben nicht *was* der Code macht, denn das steht da bereits als Code, sondern warum er das macht. Sofern das nicht offensichtlich ist. Offensichtlich ist in aller Regel auch was in der Dokumentation von Python und den verwendeten Bibliotheken steht.

`sys.exit()` verwendet man wenn man mindestens potentiell einen anderen Rückgabecode als 0 an den Aufrufer des Programms übermitteln will. Nicht um sich um einen sauberen Programmablauf zu drücken und überall einen “Notausgang“ zur haben.

Man sollte bei einer natürlichen Sprache bei den Namen bleiben. Bis auf `anziehungskraft` ist alles Englisch benannt. Das müsste also `gravity` heissen. Und dann hat man das Problem, dass es auch eine Methode gibt die so benannt wurde. Schönes Beispiel warum man Funktionen und Methoden nach Tätigkeiten benennt um sie von eher passiven Werten unterscheiden zu können. Wobei für das Datenattribut `anziehungskraft`/`gravity` inhaltlich falsch ist, denn die Anziehungskraft ist eine Konstante (hier konkret 0.8) und kein sich verändernder Wert. (Also selbst wenn man die Anziehungskraft veränderlich machen würde — in einer eigenen Spielwelt kann man sich auch eigene Regeln schaffen — ist das die falsche Berzeichnung für das Attribut.)

Man sollte möglichst keine magischen Zahlen im Programm stehen haben und Werte die sich aus anderen Werten berechnen lassen, nicht von Hand ausrechnen und in den Quelltext schreiben.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
import pygame

SCREEN_SIZE = SCREEN_WIDTH, SCREEN_HEIGHT = 1000, 550
FLOOR_Y = 450
assert FLOOR_Y < SCREEN_HEIGHT

GRAVITY = 0.8
MOVE_SPEED = 4
JUMP_ACCELLERATION = -12


class Player(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)

        self.image = pygame.transform.rotozoom(
            pygame.image.load("gpx/player/player_stand.png").convert_alpha(),
            0,
            4,
        )
        self.rect = self.image.get_rect(midbottom=(80, FLOOR_Y))
        self.y_acceleration = 0

    def move(self):
        keys = pygame.key.get_pressed()

        if keys[pygame.K_a]:
            self.rect.x -= MOVE_SPEED

        if keys[pygame.K_d]:
            self.rect.x += MOVE_SPEED

        if self.rect.bottom == FLOOR_Y and keys[pygame.K_SPACE]:
            self.y_acceleration = JUMP_ACCELLERATION

    def apply_gravity(self):
        self.y_acceleration += GRAVITY
        self.rect.y += self.y_acceleration
        self.rect.bottom = min(self.rect.bottom, FLOOR_Y)

    def update(self):
        self.move()
        self.apply_gravity()


def main():
    pygame.init()
    try:
        screen = pygame.display.set_mode(SCREEN_SIZE)
        pygame.display.set_caption("Name of the Game")
        clock = pygame.time.Clock()

        player = pygame.sprite.GroupSingle()
        player.add(Player())

        background_surface = pygame.transform.rotozoom(
            pygame.image.load("gpx/bg.png").convert_alpha(), 0, 9.3
        )
        background_rect = background_surface.get_rect(
            center=(SCREEN_WIDTH // 2, 300)
        )

        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    return

            player.update()
            
            screen.blit(background_surface, background_rect)
            player.draw(screen)
            pygame.display.update()
            clock.tick(60)
    finally:
        pygame.quit()


if __name__ == "__main__":
    main()
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten