Der sprung funktioniert nicht

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
Fly-guy
User
Beiträge: 4
Registriert: Mittwoch 31. Mai 2023, 08:39

Hi leute bin noch einigermassen neu in Python und habe eine frage...
Ich habe einen code programmiert der zwei (einfache) Figuren in die strartpositionen setzt und das dreieck der beiden soll man mit der pfeiltaste "Up" einen einfachen sprung tun lassen.
Nur funktioniert dieser nicht würde mich freuen wenn ihr mir dabei helfen könntert :).....

Das ist der Code:


#spielvorbereitungen
from tkinter import *
from random import *
from time import *
win = Tk()
win.title("Jump'n irgendwas")

c = Canvas(win, width=500, height=350)

player = c.create_oval(190, 90, 210, 110, fill="black")

enemie = c.create_line(200, 150, 200, 130, state=HIDDEN)
# enemie in startposition setzten
for i in range(300):
c.move(enemie, 1,0)
for i in range(175):
c.move(enemie, 0, 1)
# player in startposition setzen
for i in range(240):
c.move(player, 0, 1)

def sprung(event):
key = event.keysym
if key == "Up":
for i in range(55):
c.move(player, 0, -1)
sleep(1)
for i in range(55):
c.move(player, 0, 1)
c.bind_all("<Key>", sprung)
c.pack()
Fly-guy
User
Beiträge: 4
Registriert: Mittwoch 31. Mai 2023, 08:39

sorry ich habe dummerweise vergessen die nach den doppelpunkten folgenden aktionen so zu setzten das es stimmt sorry ich hoffe ihr versteht es trozdem
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Bitte benutze den vollständigen Editor und dort den Button </> und füge deinen Code zwischen die beiden [co.de] <hier dein Code> [/co.de] ein.
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
__deets__
User
Beiträge: 14536
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das uebliche Problem: GUIs duerfen keine lang-laufenden Aktionen durchfuehren. Dazu zaehlt auch sleep.

Muss es tkinter sein? Sowas kann man wesentlich natuerlicher mit pygame programmieren, dessen Hauptschleife sich auch einfacher begreifen laesst, um solche zeitlichen Aktionen zu machen.
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

*-Importe darf man nicht benutzten, weil damit nicht klar ist, woher welcher Name stammt.
Variablennamen sollten sprechend sein, einbuchstabige Namen sind das meist nicht.
Es darf keine globalen Variablen geben, alles was eine Funktion braucht, muß sie über ihre Argumente bekommen.

Bei GUIs darf es keine Langlaufenden Funktionen geben, um eine Animation zu machen, mußt Du jeden Schritt einzeln ausführen und per after-Methode den nächsten Schritt triggern.
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Fly-guy: Es wird alles aus `random` importiert und nichts davon verwendet.

Es fehlt der Aufruf von `mainloop()` vorher läuft die GUI überhaupt gar nicht. Sollte sie das bei Dir tun, dann verwendest Du wahrscheinlich einen Editor oder eine IDE um das Programm auszuführen die da ”Magie” macht, die es ohne diese Umgebung nicht geben würde. Einer der Gründe warum es wichtig ist Programme alleinstehend von einem Terminal aus zu starten wenn man sie testet.

Die ganzen Schleifen sind im Moment unsinnig weil nichts davon für den Benutzer sichtbar ist. Das bewegen der Spieler an ihre Startpositionen passiert vor dem Aufruf der Hauptschleife, der ja am Ende der Initialisierung der GUI stehen muss, denn der Aufruf blockiert bis das Hauptfenster geschlossen ist. Diese Bewegung muss auch schon mit einem `after()`-Aufruf pro Schleifendurchlauf passieren. Beim `enemy` macht das aber auch nicht so wirklich viel Sinn den zu bewegen wenn der `HIDDEN` ist.

`sprung()` ist nicht so gut als Name wenn da erst noch entschieden wird ob den nun gesprungen wird oder nicht. Entweder man nennt das generischer, `on_key()` beispielsweise, oder man bindet nur das Ereignis "<Up>" an diese Funktion.

Ergänzenz zu der Anmerkung das es keine globalen Variablen geben darf, kommt man zwar mit `functools.partial()` ein gewisses Stück weiter, aber jede nicht-triviale GUI braucht objektorientierte Programmierung. Also das man selber Klassen schreibt. Denn das folgende Beispiel hat zwar die Bewegung in mehrere `after()`-Aufrufe und den Zustand in die Argumente gesteckt, aber ausserhalb kommt man da nicht dran, zum Beispiel um zu verhindern das der Benutzer einen weiteren Sprung auslöst während die Spielfigur bereits im Sprung ist. Und so etwas wie Kollisionserkennung und darauf reagieren, zum Beispiel mit Abbruch des Sprungvorgangs, ist so auch nicht möglich, oder wird zumindest sehr, sehr unübersichtlich.

Code: Alles auswählen

#!/usr/bin/env python3
import tkinter as tk
from functools import partial


def do_jump(canvas, player, height, steps=None, is_up=True):
    if steps is None:
        steps = height

    if steps:
        canvas.move(player, 0, -1 if is_up else 1)
        canvas.after(10, do_jump, canvas, player, height, steps - 1, is_up)
    elif is_up:
        canvas.after(1000, do_jump, canvas, player, height, height, False)


def start_jump(canvas, player, _event=None):
    do_jump(canvas, player, 55)


def main():
    window = tk.Tk()
    window.title("Jump'n irgendwas")

    canvas = tk.Canvas(window, width=500, height=350)
    canvas.pack()
    player = canvas.create_oval(190, 90, 210, 110, fill="black")
    enemy = canvas.create_line(200, 150, 200, 130, state=tk.HIDDEN)

    # enemy in startposition setzten
    for _ in range(300):
        canvas.move(enemy, 1, 0)
    for _ in range(175):
        canvas.move(enemy, 0, 1)

    # player in startposition setzen
    for _ in range(240):
        canvas.move(player, 0, 1)
    canvas.bind_all("<Up>", partial(start_jump, canvas, player))
    window.mainloop()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Fly-guy
User
Beiträge: 4
Registriert: Mittwoch 31. Mai 2023, 08:39

__blackjack__ hat geschrieben: Mittwoch 31. Mai 2023, 12:08 @Fly-guy: Es wird alles aus `random` importiert und nichts davon verwendet.

Es fehlt der Aufruf von `mainloop()` vorher läuft die GUI überhaupt gar nicht. Sollte sie das bei Dir tun, dann verwendest Du wahrscheinlich einen Editor oder eine IDE um das Programm auszuführen die da ”Magie” macht, die es ohne diese Umgebung nicht geben würde. Einer der Gründe warum es wichtig ist Programme alleinstehend von einem Terminal aus zu starten wenn man sie testet.

Die ganzen Schleifen sind im Moment unsinnig weil nichts davon für den Benutzer sichtbar ist. Das bewegen der Spieler an ihre Startpositionen passiert vor dem Aufruf der Hauptschleife, der ja am Ende der Initialisierung der GUI stehen muss, denn der Aufruf blockiert bis das Hauptfenster geschlossen ist. Diese Bewegung muss auch schon mit einem `after()`-Aufruf pro Schleifendurchlauf passieren. Beim `enemy` macht das aber auch nicht so wirklich viel Sinn den zu bewegen wenn der `HIDDEN` ist.

`sprung()` ist nicht so gut als Name wenn da erst noch entschieden wird ob den nun gesprungen wird oder nicht. Entweder man nennt das generischer, `on_key()` beispielsweise, oder man bindet nur das Ereignis "<Up>" an diese Funktion.

Ergänzenz zu der Anmerkung das es keine globalen Variablen geben darf, kommt man zwar mit `functools.partial()` ein gewisses Stück weiter, aber jede nicht-triviale GUI braucht objektorientierte Programmierung. Also das man selber Klassen schreibt. Denn das folgende Beispiel hat zwar die Bewegung in mehrere `after()`-Aufrufe und den Zustand in die Argumente gesteckt, aber ausserhalb kommt man da nicht dran, zum Beispiel um zu verhindern das der Benutzer einen weiteren Sprung auslöst während die Spielfigur bereits im Sprung ist. Und so etwas wie Kollisionserkennung und darauf reagieren, zum Beispiel mit Abbruch des Sprungvorgangs, ist so auch nicht möglich, oder wird zumindest sehr, sehr unübersichtlich.

Code: Alles auswählen

#!/usr/bin/env python3
import tkinter as tk
from functools import partial


def do_jump(canvas, player, height, steps=None, is_up=True):
    if steps is None:
        steps = height

    if steps:
        canvas.move(player, 0, -1 if is_up else 1)
        canvas.after(10, do_jump, canvas, player, height, steps - 1, is_up)
    elif is_up:
        canvas.after(1000, do_jump, canvas, player, height, height, False)


def start_jump(canvas, player, _event=None):
    do_jump(canvas, player, 55)


def main():
    window = tk.Tk()
    window.title("Jump'n irgendwas")

    canvas = tk.Canvas(window, width=500, height=350)
    canvas.pack()
    player = canvas.create_oval(190, 90, 210, 110, fill="black")
    enemy = canvas.create_line(200, 150, 200, 130, state=tk.HIDDEN)

    # enemy in startposition setzten
    for _ in range(300):
        canvas.move(enemy, 1, 0)
    for _ in range(175):
        canvas.move(enemy, 0, 1)

    # player in startposition setzen
    for _ in range(240):
        canvas.move(player, 0, 1)
    canvas.bind_all("<Up>", partial(start_jump, canvas, player))
    window.mainloop()

Danke danke für diese infos nur bei diesem Code hat sich bei mir kein fenster geöfnet aber trozdem danke ich versuche es weiter
Fly-guy
User
Beiträge: 4
Registriert: Mittwoch 31. Mai 2023, 08:39

__blackjack__ hat geschrieben: Mittwoch 31. Mai 2023, 12:08 @Fly-guy: Es wird alles aus `random` importiert und nichts davon verwendet.

Es fehlt der Aufruf von `mainloop()` vorher läuft die GUI überhaupt gar nicht. Sollte sie das bei Dir tun, dann verwendest Du wahrscheinlich einen Editor oder eine IDE um das Programm auszuführen die da ”Magie” macht, die es ohne diese Umgebung nicht geben würde. Einer der Gründe warum es wichtig ist Programme alleinstehend von einem Terminal aus zu starten wenn man sie testet.

Die ganzen Schleifen sind im Moment unsinnig weil nichts davon für den Benutzer sichtbar ist. Das bewegen der Spieler an ihre Startpositionen passiert vor dem Aufruf der Hauptschleife, der ja am Ende der Initialisierung der GUI stehen muss, denn der Aufruf blockiert bis das Hauptfenster geschlossen ist. Diese Bewegung muss auch schon mit einem `after()`-Aufruf pro Schleifendurchlauf passieren. Beim `enemy` macht das aber auch nicht so wirklich viel Sinn den zu bewegen wenn der `HIDDEN` ist.

`sprung()` ist nicht so gut als Name wenn da erst noch entschieden wird ob den nun gesprungen wird oder nicht. Entweder man nennt das generischer, `on_key()` beispielsweise, oder man bindet nur das Ereignis "<Up>" an diese Funktion.

Ergänzenz zu der Anmerkung das es keine globalen Variablen geben darf, kommt man zwar mit `functools.partial()` ein gewisses Stück weiter, aber jede nicht-triviale GUI braucht objektorientierte Programmierung. Also das man selber Klassen schreibt. Denn das folgende Beispiel hat zwar die Bewegung in mehrere `after()`-Aufrufe und den Zustand in die Argumente gesteckt, aber ausserhalb kommt man da nicht dran, zum Beispiel um zu verhindern das der Benutzer einen weiteren Sprung auslöst während die Spielfigur bereits im Sprung ist. Und so etwas wie Kollisionserkennung und darauf reagieren, zum Beispiel mit Abbruch des Sprungvorgangs, ist so auch nicht möglich, oder wird zumindest sehr, sehr unübersichtlich.

Code: Alles auswählen

#!/usr/bin/env python3
import tkinter as tk
from functools import partial


def do_jump(canvas, player, height, steps=None, is_up=True):
    if steps is None:
        steps = height

    if steps:
        canvas.move(player, 0, -1 if is_up else 1)
        canvas.after(10, do_jump, canvas, player, height, steps - 1, is_up)
    elif is_up:
        canvas.after(1000, do_jump, canvas, player, height, height, False)


def start_jump(canvas, player, _event=None):
    do_jump(canvas, player, 55)


def main():
    window = tk.Tk()
    window.title("Jump'n irgendwas")

    canvas = tk.Canvas(window, width=500, height=350)
    canvas.pack()
    player = canvas.create_oval(190, 90, 210, 110, fill="black")
    enemy = canvas.create_line(200, 150, 200, 130, state=tk.HIDDEN)

    # enemy in startposition setzten
    for _ in range(300):
        canvas.move(enemy, 1, 0)
    for _ in range(175):
        canvas.move(enemy, 0, 1)

    # player in startposition setzen
    for _ in range(240):
        canvas.move(player, 0, 1)
    canvas.bind_all("<Up>", partial(start_jump, canvas, player))
    window.mainloop()

Danke danke für diese infos nur bei diesem Code hat sich bei mir kein fenster geöfnet aber trozdem danke ich versuche es weiter
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Fly-guy hat geschrieben: Montag 5. Juni 2023, 09:36 Danke danke für diese infos nur bei diesem Code hat sich bei mir kein fenster geöfnet aber trozdem danke ich versuche es weiter
Da fehlt noch am Ende der Aufruf von `main`.

Code: Alles auswählen

if __name__ ==  '__main__':
    main()
Antworten