Reputation: 49
guys. I am trying to create my own version of a card game. I got the following problem trying to move my cards to the center of the canvas on click event. Here is an example of my 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()
What I want is to move my card but not just move from one coordinate to another but giving it in slow motion effect.
Upvotes: 1
Views: 1852
Reputation:
This code below (ready for copy/paste and run as it is) gives a nice smooth motion on my box:
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()
Upvotes: 0
Reputation: 386210
The basic idea is to write a function that moves an object a small amount, and then schedules itself to be called again after a short delay. It does this until it reaches its destination.
Here is a very simple example that moves a couple items independently. You can adjust the speed by changing the speed
parameter, or by changing the values of delta_x
and delta_y
.
This is a very simplistic algorithm that just increases the x and y coordinates by a fixed amount. You could instead calculate equally spaced points along a curve or straight line. Regardless, the animation technique remains the same.
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()
Upvotes: 1
Reputation: 1857
In order to 'animate' your cards moving, a system of breaking down the total distance to be moved, and then moving/updating by smaller distances over a time-period would work.
For example, if you wish to move a card 400 units in x & y, something like this could work:
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
This could be a basic premise for an animation. Of course you would need to edit the total_time
and period
variables in my example to create what you feel is right.
Upvotes: 1