Seite 1 von 2
Objekt bei jedem Tastendruck fortbewegen in PyGame
Verfasst: Mittwoch 15. Dezember 2021, 16:02
von cypher28
Hallo zusammen,
ich bin gerade dabei ein Spielfeld zu erstellen und ein Objekt einfach zu bewegen i. diesem Spielfeld. Alles soweit gut.
Nur möchte ich daß das Objekt sich nicht durchlaufend bewegt bei gedrückter Taste, sondern erst dann wieder einen bestimmten Schritt nach vorne macht, wen. die Taste nochmals gedrückt wird.
Die Spielfigur soll sich quasi jedesmal um 50 px in eine Richtung bewegen, aber nicht fortlaufend bei gedrückter Taste.
Hier mal der Code:
Code: Alles auswählen
import pygame
import sys
pygame.init()
#hintergrundbild laden
background = pygame.image.load("graphics/background.jpg")
#Grösse des Spielfeldes definieren
screen = pygame.display.set_mode([800,600])
clock = pygame.time.Clock()
#SPielname in der Statusleiste
pygame.display.set_caption("Frogger")
def draw():
screen.blit(background, (0,0))
pygame.draw.rect(screen, (0,0,0), (x,y,bright, wight))
pygame.display.update()
#Objekteigenschaften
x = 300
y = 550
speed = 20
bright = 40
wight = 40
leftWall = pygame.draw.rect(screen, (0,0,0), (0,0, 2, 600), 0)
rightWall = pygame.draw.rect(screen, (0,0,0), (799,0, 2, 600), 0)
go = True
while go:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
playerRect = pygame.Rect(x,y,40,40)
pressed = pygame.key.get_pressed()
if pressed[pygame.K_UP]:
y -= speed
if pressed[pygame.K_RIGHT] and not playerRect.colliderect(rightWall):
x += speed
if pressed[pygame.K_DOWN]:
y += speed
if pressed[pygame.K_LEFT] and not playerRect.colliderect(leftWall):
x -= speed
draw()
clock.tick(60)
In dieser Situation bewegt sich das Objekt, solange die jeweiligen Tasten gedruckt sind.
Ich habe es mit einer bool-Variable versucht, weis aber nicht ob der Ansatz richtig ist.
Code: Alles auswählen
....
wasPressed = True
....
if pressed[pygame.K_UP] and wasPressed:
y -= speed
wasPressed = False
Es klappt dann beim erstenmal, da aber im ersten durchlauf der bool-Wert auf False gesetzt wird klappt es beim zweiten durchlauf nicht. Was ja auch sinn macht.
Wäre super wenn jemand einen Tip hätte.
Vielen dank im voraus.
Re: Objekt bei jedem Tastendruck fortbewegen in PyGame
Verfasst: Mittwoch 15. Dezember 2021, 16:18
von rogerb
@cypher28,
dazu würde ich mir mal die Dokumentation von pygame anschauen. Es gibt über die Funktion "pygame.key.set_repeat()" die Möglichkeit das Verhalten zu bestimmen.
Außerdem gibt "pygame.key.get_pressed()" den Zustand der Taste an und ist damit True solange sie gedrückt ist. Das Verhalten ist also zu erwarten.
Ansonsten sollte der KeyUp Event besser funktionieren. Der wird ausgelöst, wenn eine Taste losgelassen wurde, nicht wenn sie gedrückt wurde.
Mit irgendwelchen boolschen Variablen, wird es nur zu kompliziert. Das braucht man nur wenn man Springen oder ähnliches realisieren will.
sys.exit() würde ich auch nicht verwenden. Dafür hast du doch die Variable "go". Die muss zum Beenden nur auf "False" gesetzt werden.
Re: Objekt bei jedem Tastendruck fortbewegen in PyGame
Verfasst: Mittwoch 15. Dezember 2021, 18:23
von __blackjack__
@cypher28: Weitere Anmerkungen: 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. `draw()` braucht also `screen`, `background`, `x`, `y`, `bright`, und `wight`. Was ganz schön viel ist. Das sollte man überlegen was man davon vielleicht sinnvoll zu Objekten zusammenfassen kann. Die letzten vier beschreiben ja beispielsweise ein Rechteck, da würde sich ein `Rect`-Objekt anbieten.
Was sollen `bright` und `wight` überhaupt bedeuten? Das ist verwirrend. Haben die in irgendeiner (natürlichen) Sprache eine Bedeutung die zu der Bedeutung der Werte im Programm passt?
Es fehlt ein `pygame.quit()` als Gegenstück zum `pygame.init()`.
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.
Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (PascalCase).
Es gibt Zahlen die magisch fest im Code stehen, die von anderen Werten abhängig sind. Das heisst man muss wenn man etwas davon ändert, auch die davon abhängigen Werte im Programm suchen und anpassen, statt das die dort gleich aus dem berechnet werden, von dem sie abhängig sind.
Und die Breite/Höhe von Spieler wird unabhängig an zwei Stellen definiert. Und sogar ein `Rect` erstellt, das man `draw()` übergeben könnte, statt der Einzelwerte.
Zwischenstand (ungetestet):
Code: Alles auswählen
#!/usr/bin/env python3
import pygame
BLACK = (0, 0, 0)
def draw(screen, background, rect):
screen.blit(background, (0, 0))
pygame.draw.rect(screen, BLACK, rect)
pygame.display.update()
def main():
pygame.init()
try:
background = pygame.image.load("graphics/background.jpg")
size = width, height = (800, 600)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Frogger")
player_rect = pygame.Rect(300, 550, 40, 40)
speed = 20
left_wall = pygame.draw.rect(screen, BLACK, (0, 0, 2, height), 0)
right_wall = pygame.draw.rect(screen, BLACK, (width-1, 0, 2, height), 0)
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
pressed = pygame.key.get_pressed()
if pressed[pygame.K_UP]:
player_rect.move_ip(0, -speed)
if pressed[pygame.K_RIGHT] and not player_rect.colliderect(right_wall):
player_rect.move_ip(speed, 0)
if pressed[pygame.K_DOWN]:
player_rect.move_ip(0, speed)
if pressed[pygame.K_LEFT] and not player_rect.colliderect(left_wall):
player_rect.move_ip(-speed, 0)
draw(screen, background, player_rect)
clock.tick(60)
finally:
pygame.quit()
if __name__ == "__main__":
main()
Re: Objekt bei jedem Tastendruck fortbewegen in PyGame
Verfasst: Mittwoch 15. Dezember 2021, 19:22
von cypher28
OK,
vielen dank für die Antworten.
Die Kommentare hatte ich jetzt nur als Orientierung für mich geschrieben .
Werde mich mal da einarbeiten. Ist das erste mal das ich mich an PyGame, geschweige denn an Python versuche.
Re: Objekt bei jedem Tastendruck fortbewegen in PyGame
Verfasst: Donnerstag 16. Dezember 2021, 16:04
von cypher28
Das mir der Fortbewegung klappt soweit.
Kann ich einem rect auch ein image zuweisen? Ich meine wenn ich z.B. kein Rechteck, sondern ein Bild laden möchte als Player?
Ich denke, dann müsste die "draw" Methode angepasst werden. Nur klappt es nicht leider.
Code: Alles auswählen
def draw(screen, background, player):
screen.blit(background, (0, 0))
pygame.draw.rect(screen,BLACK, rect)
pygame.display.update()
Kann ich z.B. anstatt einer Farbe, ein Bild zuweisen? Mir fehlt irgendwie eine Methode Pygame.draw(zeichne Bild xyz)
Re: Objekt bei jedem Tastendruck fortbewegen in PyGame
Verfasst: Donnerstag 16. Dezember 2021, 16:09
von __deets__
Zuweisen kannst du da nichts, du kannst einfach ein Bild malen, das muss dann natuerlich so gross sein wie das rect.
Nachtrag: blit ist doch was du suchst, damit wird ein Bild (Surface) in ein anderes kopiert.
Re: Objekt bei jedem Tastendruck fortbewegen in PyGame
Verfasst: Donnerstag 16. Dezember 2021, 16:31
von cypher28
Also das mit dem Zeichnen habe ich hinbekommen.
Code: Alles auswählen
def draw(screen, background, spieler):
screen.blit(background, (0, 0))
screen.blit(spieler, (x,y))
pygame.display.update()
x = 600
y = 800
Nur kann diese
Code: Alles auswählen
if event.key == pygame.K_UP:
player_image.move_ip(0, -speed)
move_ip Methode glaube ich nur an einem rect Object oder desgleichen angewendet werden.
Wie müsste dann die Bewegung meines Objektes aussehen?
ich hätte gedacht das ich mit:
das Objekt in Richtung x bewegen kann. Nur wird die variable x nicht erkannt, da sie ja ausserhalb der main Methode sich befindet. Es müsste irgendwie ja die Spieler Koordinate in der main Methode vorhanden sein, damit man diese beeinflussen kann.
Re: Objekt bei jedem Tastendruck fortbewegen in PyGame
Verfasst: Donnerstag 16. Dezember 2021, 16:33
von __deets__
Ich kenne deinen gesamten Code nicht, aber angeblich bekommt draw doch player_rect, und das hat doch die Koordinate. Warum haelst du die Daten doppelt?
Re: Objekt bei jedem Tastendruck fortbewegen in PyGame
Verfasst: Donnerstag 16. Dezember 2021, 16:56
von cypher28
Ich glaube ich verstehe das zusammen spiel zwischen dem Konstrukt der Methode "draw()"
Code: Alles auswählen
def draw(screen, background, spieler):
screen.blit(background, (0, 0))
screen.blit(spieler, (x,y))
pygame.display.update()
und dem Aufruf der Methode in der "main()" Methode nicht so ganz.
Hier mal der komplette code.
Code: Alles auswählen
#!/usr/bin/env python3
import pygame
BLACK = (0, 0, 0)
def draw(screen, background, spieler):
screen.blit(background, (0, 0))
screen.blit(spieler, (x,y))
pygame.display.update()
x = 600
y = 800
def main():
pygame.init()
try:
background = pygame.image.load("graphics/background.png")
size = width, height = (1000, 1000)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Game")
player_image = pygame.image.load("graphics/player.png")
speed = 20
left_wall = pygame.draw.rect(screen, BLACK, (0, 0, 2, height), 0)
right_wall = pygame.draw.rect(screen, BLACK, (width-1, 0, 2, height), 0)
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
print("passt")
# player_image += speed
draw(screen, background, player_image)
clock.tick(60)
finally:
pygame.quit()
if __name__ == "__main__":
main()
Mit freundlicher unterstützung von __blackjack__ natürlich.

Re: Objekt bei jedem Tastendruck fortbewegen in PyGame
Verfasst: Donnerstag 16. Dezember 2021, 16:58
von __deets__
Da ist doch der urspruengliche Code, in dem das player_rect bewegt wurde, weg. Und das wurde doch mal an draw uebergeben. Und enthielt die Koordinate. Warum ist das denn alles verschwunden?
Re: Objekt bei jedem Tastendruck fortbewegen in PyGame
Verfasst: Donnerstag 16. Dezember 2021, 17:22
von cypher28
Ok, dann frage ich mal andersrum.
Wie kann ich denn das Rechteck durch ein eingelesenes Bild ersetzen, so dass ich kein schwarzes Rechteck im Game habe sondern mein eingelesenes Bild?
Das meinte ich mit "Wie kann ich einem Rechteck ein Bild zuweisen".Das einlesen des Bildes kann ich ja wie gewohnt, wie mit "
background" tätigen.
Hier mal der überarbeitete code mit der gewünschten Steuerung:
Code: Alles auswählen
import pygame
BLACK = (0, 0, 0)
def draw(screen, background, rect):
screen.blit(background, (0, 0))
pygame.draw.rect(screen, BLACK, rect)
pygame.display.update()
def main():
pygame.init()
try:
background = pygame.image.load("graphics/background.jpg")
player = pygame.image.load("graphics/player.jpg")
size = width, height = (800, 600)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Frogger")
player_rect = pygame.Rect(300, 550, 40, 40)
speed = 20
left_wall = pygame.draw.rect(screen, BLACK, (0, 0, 2, height), 0)
right_wall = pygame.draw.rect(screen, BLACK, (width-1, 0, 2, height), 0)
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
player_rect.move_ip(0, -speed)
if event.key == pygame.K_DOWN:
player_rect.move_ip(0, speed)
if event.key == pygame.K_LEFT:
player_rect.move_ip(-speed, 0)
if event.key == pygame.K_RIGHT:
player_rect.move_ip(speed, 0)
draw(screen, background, player_rect)
clock.tick(60)
finally:
pygame.quit()
if __name__ == "__main__":
main()
Ich muss doch das Rechteck
irgendwie durch mein eingelesenen "Player" ersetzen, so daß ich den Player sehe und kein Rechteck.
Oder dass Rechteck "durchsichtig" machen, aber irgendwie das Bild anhängen / zuweisen. Damit dann auch Kollisionen erkannt werden können im Spiel!?
Re: Objekt bei jedem Tastendruck fortbewegen in PyGame
Verfasst: Donnerstag 16. Dezember 2021, 17:34
von __deets__
Indem du auch dein bild an draw uebergibst, und das dann da mals, an die Stelle, die das player_rect bezeichnet.
Und wenn das unklar ist, mal das Grundlagentutorial auf python.org durcharbeiten, denn Funktionen und wie man an sie etwas uebergibt muessen sitzen.
Re: Objekt bei jedem Tastendruck fortbewegen in PyGame
Verfasst: Donnerstag 16. Dezember 2021, 17:46
von cypher28
Du meinst:
Code: Alles auswählen
def draw(screen, background, rect, player):
screen.blit(background, (0, 0))
screen.blit(player, (500, 500))
pygame.draw.rect(screen, BLACK, rect)
pygame.display.update()
und in der main Methode mit zeichnen:
Aber, dann funktioniert die Steuerung des players nicht:
Weil anscheinend auf die x Koordinate des Players nicht zugegriffen werden kann, welches ja ausserhalb liegt. Wobei ich mich dann frage wozu ich player_rect dann noch brauche.
Re: Objekt bei jedem Tastendruck fortbewegen in PyGame
Verfasst: Donnerstag 16. Dezember 2021, 17:53
von __deets__
Wieso passt du denn dann die Steuerung an? Warum bleibt das nicht player_rect? player_rect ist doch der Ort, an dem du Position und Ausmass deines Players mitfuehrst, um ihn dann zB kollidieren zu lassen.
Re: Objekt bei jedem Tastendruck fortbewegen in PyGame
Verfasst: Donnerstag 16. Dezember 2021, 18:09
von cypher28
__deets__ hat geschrieben: Donnerstag 16. Dezember 2021, 17:53
Wieso passt du denn dann die Steuerung an?
Die Steuerung musste ich anpassen weil ich wollte, daß das Objekt beim drücken der Taste sich nur einmal bewegt und nicht durchgehend. Was ja auch funktioniert in bezug auf das Rechteck.
__deets__ hat geschrieben: Donnerstag 16. Dezember 2021, 17:53
Warum bleibt das nicht player_rect? player_rect ist doch der Ort, an dem du Position und Ausmass deines Players mitfuehrst, um ihn dann zB kollidieren zu lassen.
Weil player_rect das Rechteck ist und nicht der player.
somit habe ich ja beides auf dem Bildschirm. Mein Rechteck und meinen Player.
Code: Alles auswählen
if event.key == pygame.K_UP:
player_rect.move_ip(0, -speed)
Und damit steuere ich mein Rechteck und nicht meinen Player.
Es sei denn es gibt eine Möglichkeit, meinen "Player" abhängig vom Rechteck zu machen, so daß es sich immer mitbewegt.
Re: Objekt bei jedem Tastendruck fortbewegen in PyGame
Verfasst: Donnerstag 16. Dezember 2021, 18:33
von __deets__
player ist ein Bild. Das hat keine Koordinaten. player_rect sind deine Koordinaten. Du brauchst eben beides. Und wenn du das rect nicht malen willst, mal es nicht. Aber es ist eben immer noch die Koordinate.
Re: Objekt bei jedem Tastendruck fortbewegen in PyGame
Verfasst: Donnerstag 16. Dezember 2021, 18:58
von cypher28
Der player_rect ist doch einfach nur das Rechteck. Das steht doch in keiner Beziehung mit meinem eingelesenen Bild?
Ich kann doch hier dem Rechteck kein Bild zuweisen:
Zumindest gibt es in der Pygame doc kein Modul um dort ein Bild anzuhängen.
https://www.pygame.org/docs/ref/draw.ht ... .draw.rect
Entweder bin ich Blind oder auf dem falschen Pfad.

Re: Objekt bei jedem Tastendruck fortbewegen in PyGame
Verfasst: Donnerstag 16. Dezember 2021, 19:13
von __blackjack__
@cypher28: `blit()` braucht das Bild und die Koordinaten. Du übergibst `draw()` das Bild und die Koordinaten und rufst `blit()` dann mit beidem auf. Das zweite Argument dort muss kein Tupel sein, das kann auch ein `Rect`-Objekt sein. Und Du hast da ja ein passendes für.
`pygame.draw.rect()` ist falsch, denn Du willst ja gar kein Rechteck mehr malen sondern das Bild blitten.
Re: Objekt bei jedem Tastendruck fortbewegen in PyGame
Verfasst: Donnerstag 16. Dezember 2021, 19:57
von cypher28
Du meinst die draw() methode folgt:
Code: Alles auswählen
def draw(screen, background, player, position):
screen.blit(background, (0, 0))
screen.blit(player, position)
pygame.display.update()
Soweit so gut. Objekt wird an der gewünschten Position gezeichnet. Nur wie kann ich das Objekt bewegen.
Hier mal der aktuelle code:
Code: Alles auswählen
import pygame
BLACK = (0, 0, 0)
def draw(screen, background, player, position):
screen.blit(background, (0, 0))
screen.blit(player, position)
pygame.display.update()
def main():
pygame.init()
try:
background = pygame.image.load("graphics/background.jpg")
player = pygame.image.load("graphics/player.png")
position_player = (400,500)
size = width, height = (800, 600)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Frogger")
player_rect = pygame.Rect(300, 550, 40, 40)
speed = 20
left_wall = pygame.draw.rect(screen, BLACK, (0, 0, 2, height), 0)
right_wall = pygame.draw.rect(screen, BLACK, (width-1, 0, 2, height), 0)
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
#player.move_ip(0, -speed)
position_player = speed
draw(screen, background, player, position = position_player)
clock.tick(60)
finally:
pygame.quit()
if __name__ == "__main__":
main()
Nur wie kann ich die x oder die y Koordinate meines Objekts beeinflussen um mein Objekt zu bewegen?
Die methode "move_ip()" ist nicht anwendbar.
Auch folgendes führt zu einem Fehler auf der Konsole:
Code: Alles auswählen
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
#player.move_ip(0, -speed)
position_player -= speed
Wobei ich hier ja den ganzen Tutel anspreche und nicht gezielt x oder y.
Fehler:
Code: Alles auswählen
TypeError: unsupported operand type(s) for -=: 'tuple' and 'int'
Es sei denn, meine draw() methode ist komplett falsch.
Re: Objekt bei jedem Tastendruck fortbewegen in PyGame
Verfasst: Donnerstag 16. Dezember 2021, 20:21
von __deets__
Ich geb auf. Wir reden offensichtlich komplett aneinander vorbei. Ich kann nur zum x-ten mal sagen, dass du nichts an der positions-Berechnung verändern musst, aber es greift offensichtlich nicht. Vielleicht hat wer anders eine Idee.