Les mecs. J'essaye de créer ma propre version d'un jeu de cartes. J'ai rencontré le problème suivant en essayant de déplacer mes cartes vers le centre du canevas lors d'un événement de clic. Voici un exemple de mon code

import tkinter as tk

class gui(tk.Frame):

def __init__(self, parent, *args, **kwargs):
    tk.Frame.__init__(self, parent, *args, **kwargs)
    self.canvas =  tk.Canvas(parent, bg="blue", highlightthickness=0)
    self.canvas.pack(fill="both", expand=True)
    self.img = PhotoImage(file="card.gif")
    self.card = self.canvas.create_image(10, 10, image=self.img)
    self.canvas.tag_bind(self.card, '<Button-1>', self.onObjectClick1)

def onObjectClick1(self, event):
    if self.canvas.find_withtag("current"):
        x = 400
        y = 400
        self.canvas.coords("current", x, y)
        self.canvas.tag_raise("current")

if __name__ == "__main__":
root = tk.Tk()
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.geometry("%dx%d+0+0" % (w, h))
gui(root)
root.mainloop()

Ce que je veux, c'est déplacer ma carte, mais pas simplement passer d'une coordonnée à une autre mais lui donner un effet de ralenti.

1
JOrG 21 avril 2017 à 00:32

3 réponses

Meilleure réponse

L'idée de base est d'écrire une fonction qui déplace légèrement un objet, puis se planifie pour être appelée à nouveau après un court délai. Il le fait jusqu'à ce qu'il atteigne sa destination.

Voici un exemple très simple qui déplace quelques éléments indépendamment. Vous pouvez ajuster la vitesse en modifiant le paramètre speed ou en modifiant les valeurs de delta_x et delta_y.

Il s'agit d'un algorithme très simpliste qui augmente simplement les coordonnées x et y d'une quantité fixe. Vous pouvez à la place calculer des points également espacés le long d'une courbe ou d'une ligne droite. Quoi qu'il en soit, la technique d'animation reste la même.

import Tkinter as tk

def move_object(canvas, object_id, destination, speed=50):
    dest_x, dest_y = destination
    coords = canvas.coords(object_id)
    current_x = coords[0]
    current_y = coords[1]

    new_x, new_y = current_x, current_y
    delta_x = delta_y = 0
    if current_x < dest_x:
        delta_x = 1
    elif current_x > dest_x:
        delta_x = -1

    if current_y < dest_y:
        delta_y = 1
    elif current_y > dest_y:
        delta_y = -1

    if (delta_x, delta_y) != (0, 0):
        canvas.move(object_id, delta_x, delta_y)

    if (new_x, new_y) != (dest_x, dest_y):
        canvas.after(speed, move_object, canvas, object_id, destination, speed)

root = tk.Tk()
canvas = tk.Canvas(root, width=400, height=400)
canvas.pack()

item1 = canvas.create_rectangle(10, 10, 30, 30, fill="red")
item2 = canvas.create_rectangle(360, 10, 380, 30, fill="green")

move_object(canvas, item1, (200, 180), 25)
move_object(canvas, item2, (200, 220), 50)

root.mainloop()
1
Bryan Oakley 20 avril 2017 à 22:24

Afin d '«animer» vos cartes en mouvement, un système de décomposition de la distance totale à déplacer, puis de déplacement / mise à jour par des distances plus petites sur une période de temps fonctionnerait.

Par exemple, si vous souhaitez déplacer une carte de 400 unités en x & y, quelque chose comme ceci pourrait fonctionner:

total_time = 500 #Time in milliseconds
period = 8
dx = 400/period
dy = 400/period

for i in range(period):
    self.canvas.move(chosen_card, dx, dy)
    root.after(total_time/period) #Pause for time, creating animation effect
    root.update() #Update position of card on canvas

Cela pourrait être une prémisse de base pour une animation. Bien sûr, vous devrez modifier les variables total_time et period dans mon exemple pour créer ce que vous pensez être juste.

1
SneakyTurtle 20 avril 2017 à 21:43

Ce code ci-dessous (prêt à copier / coller et à exécuter tel quel) donne un joli mouvement fluide sur ma boîte:

import tkinter as tk
import time

class gui(tk.Frame):

    def __init__(self, parent, *args, **kwargs):
        tk.Frame.__init__(self, parent, *args, **kwargs)
        self.canvas =  tk.Canvas(parent, bg="blue", highlightthickness=0)
        self.canvas.pack(fill="both", expand=True)
        self.img = tk.PhotoImage(file="card.gif")
        self.card = self.canvas.create_image(10, 10, image=self.img)
        self.canvas.tag_bind(self.card, '<Button-1>', self.onObjectClick1)

    def onObjectClick1(self, event):
        if self.canvas.find_withtag("current"):
            x = 400
            y = 400
            self.canvas.coords("current", x, y)
            self.canvas.tag_raise("current")
            total_time = 500 #Time in milliseconds
        period = 400
        dx = 400/period
        dy = 400/period
        for i in range(period):
            self.canvas.move(self.card, dx, dy) # chosen_card
            time.sleep(0.01)
            # root.after(total_time/period) #Pause for time, creating animation effect
            root.update() #Update position of card on canvas

if __name__ == "__main__":
    root = tk.Tk()
    w, h = root.winfo_screenwidth(), root.winfo_screenheight()
    root.geometry("%dx%d+0+0" % (w, h))
    gui(root)
    root.mainloop()
0
Claudio 20 avril 2017 à 22:34