Tkinter Animationen

Fragen zu Tkinter.
Antworten
Crafter_07
User
Beiträge: 2
Registriert: Sonntag 27. Mai 2018, 18:22

Hi Leute,
ich bin gerade dabei, ein kleines Spiel mit tkinter zu programmieren.
In dem Spiel soll man quasi eine Kanone sein, und von oben, unten, links und rechts sollen Kanonenkugeln kommen. Wenn man klickt, sollte man schießen(ich habe die feindlichen Kanonenkugel noch nicht programmiert):

Code: Alles auswählen

#Imports
from tkinter import *
from time import *

#window
W_WIDTH = 1600
W_HEIGHT = 900
window = Tk()
window.title("SimpleGame")

#canvas
c = Canvas(window, width=W_WIDTH, height=W_HEIGHT, bg="lightgrey")
c.pack()

#Player

#player1
player1_size = 100
player1_posX = W_WIDTH/2 - player1_size/2
player1_posY = W_HEIGHT/2 - player1_size/2
player_1 = c.create_oval(0, 0, player1_size, player1_size, fill="red")
c.move(player_1, player1_posX, player1_posY)

#player2
player2_sizeX = player1_size*2
player2_sizeY = player1_size/2
player2_posX = player1_posX + player1_size/2
player2_posY = player1_posY + player1_size/4
player_2 = c.create_rectangle(0, 0, player2_sizeX, player2_sizeY, fill="black")
c.move(player_2, player2_posX, player2_posY)


#Schuss

def shoot(event):
    shoot_size = 50
    shoot_posX = player2_posX +  player2_sizeX/2 + shoot_size*2
    shoot_posY = player2_posY
    shoot = c.create_oval(0, 0, shoot_size, shoot_size, fill="black")
    c.move(shoot, shoot_posX, shoot_posY)
    for i in range(80):
        shoot_posX += 10
        shoot_posY += 10
        c.move(shoot, shoot_posX, shoot_posY)
        window.update()
        sleep(0.5)
c.bind_all("<Button-1>", shoot)
Aber immer wenn ich klicke, stürzt das Programm ab. Kann mir da jemand helfen?
LG,
Crafter_07
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

Das Programm macht gar nichts, weil `mainloop` fehlt. Was ist denn die Fehlermeldung, die Du bekommst? Schleifen und sleep dürfen in GUIs nicht vorkommen, weil sie die Abarbeitung von Events stoppt. Für "Animationen" gibt es ›after‹. `move` beweget Objekte relativ zu ihrer aktuellen Position. Sternchenimporte vermeiden, weil man nicht kontrollieren kann, was da alles in den eigenen Namensraum geladen wird.
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

du definierst eine Funktion shoot mit Parameter event, wo wird die aufgerufen?
in dieser Funktion erzeugst du eine Variable shoot = c.create..... die Namensgebung solltest du überdenken, dass sind zuviele shoots :lol:
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
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

Die Funktion `shoot` wird an das Button-Event gebunden. Die muß man also nicht direkt aufrufen. Und solange man sich nicht selbst aufrufen will, ist es egal, ob eine lokale Variable auch `shoot` heißt.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi Crafter_07

Hier meine primitiver Lösungsansatz:

Code: Alles auswählen

#Imports
from tkinter import *
from time import *

#window
W_WIDTH = 1600
W_HEIGHT = 900
window = Tk()
window.title("SimpleGame")

#canvas
c = Canvas(window, width=W_WIDTH, height=W_HEIGHT, bg="lightgrey")
c.pack()

#Player

#player1
player1_size = 100
player1_posX = W_WIDTH/2 - player1_size/2
player1_posY = W_HEIGHT/2 - player1_size/2

player_1 = c.create_oval(0, 0, player1_size, player1_size, fill="red")
c.move(player_1, player1_posX, player1_posY)

#player2
player2_sizeX = player1_size*2
player2_sizeY = player1_size/2
player2_posX = player1_posX + player1_size/2
player2_posY = player1_posY + player1_size/4

player_2 = c.create_rectangle(0, 0, player2_sizeX, player2_sizeY, fill="black")
c.move(player_2, player2_posX, player2_posY)


#Schuss

def shoot(event):
    shoot_size = 50
    shoot_posX = player2_posX +  player2_sizeX/2 + shoot_size*2
    shoot_posY = player2_posY
    c.create_oval(0, 0, shoot_size, shoot_size, fill="black", tags="bullet")
    c.move(shoot, shoot_posX, shoot_posY)
    move_bullet()
    
def move_bullet(cycle=0):
    x0, y0, x1, y1 = c.coords("bullet")
    x0 += 10
    y0 += 10
    x1 += 10
    y1 += 10
    print(x0, y0)
    c.coords("bullet", x0, y0, x1, y1)
    cycle -= 1
    if cycle == 0:return
    window.after(100, move_bullet, cycle)
            
c.bind_all("<Button-1>", shoot)

window.mainloop()
Gruss wuf ;-)
Take it easy Mates!
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

@wuf: Sternchenimporte vermeiden, da man nicht kontrollieren kann, was da in den eigenen Namensraum geladen wird. Aus dem Modul `time` wird nichts verwendet, also kann der Import weg. In `shoot` ist das erste Argument von `move` falsch. `move_bullet` wird genau einmal durchlaufen, weil das `cycle`-Argument null ist. `shoot` und `move_bullet` könnten besser so aussehen:

Code: Alles auswählen

def shoot(event):
    shoot_size = 50
    shoot_posX = player2_posX +  player2_sizeX/2 + shoot_size*2
    shoot_posY = player2_posY
    shoot_id = c.create_oval(0, 0, shoot_size, shoot_size, fill="black")
    c.move(shoot_id, shoot_posX, shoot_posY)
    move_bullet(shoot_id, 100)

def move_bullet(shoot_id, turn):
    c.move(shoot_id, 10, 10)
    if turn > 0:
        window.after(100, move_bullet, shoot_id, turn - 1)
Antworten