Hey I'm trying to solve a problem where I got a character moving around on a 2D-plane using the WASD-keys. However when I hold a button the code writes once then makes a delay and then writes nonstop.
How to remove this delay? I've seen some solutions using after() with canvas() but not sure how to apply this to a label() using "text=".
Thanks for any ideas!
from tkinter import *
import tkinter as tk
coordinates = {
"x1y1": "", "x2y1": "", "x3y1": "", "x4y1": "", "x5y1": "", "x6y1": "", "x7y1": "", "x8y1": "", "x9y1": "",
"x1y2": "", "x2y2": "", "x3y2": "", "x4y2": "", "x5y2": "", "x6y2": "", "x7y2": "", "x8y2": "", "x9y2": "",
"x1y3": "", "x2y3": "", "x3y3": "", "x4y3": "", "x5y3": "", "x6y3": "", "x7y3": "", "x8y3": "", "x9y3": "",
"x1y4": "", "x2y4": "", "x3y4": "", "x4y4": "", "x5y4": "", "x6y4": "", "x7y4": "", "x8y4": "", "x9y4": "",
"x1y5": "", "x2y5": "", "x3y5": "", "x4y5": "", "x5y5": "", "x6y5": "", "x7y5": "", "x8y5": "", "x9y5": "",
"x1y6": "", "x2y6": "", "x3y6": "", "x4y6": "", "x5y6": "", "x6y6": "", "x7y6": "", "x8y6": "", "x9y6": "",
"x1y7": "", "x2y7": "", "x3y7": "", "x4y7": "", "x5y7": "", "x6y7": "", "x7y7": "", "x8y7": "", "x9y7": "",
"x1y8": "", "x2y8": "", "x3y8": "", "x4y8": "", "x5y8": "", "x6y8": "", "x7y8": "", "x8y8": "", "x9y8": "",
"x1y9": "", "x2y9": "", "x3y9": "", "x4y9": "", "x5y9": "", "x6y9": "", "x7y9": "", "x8y9": "", "x9y9": "",
}
#Player starting position
player_x = 5
player_y = 5
#Onpress update player X/Y positions and make sure they don't exceed coordinate system
def keypress_w(event):
global player_y
player_y -= 1
if player_y < 1:
player_y = 1
update_world()
def keypress_a(event):
global player_x
player_x -= 1
if player_x < 1:
player_x = 1
update_world()
def keypress_d(event):
global player_x
player_x = 1
if player_x > 9:
player_x -= 1
update_world()
def keypress_s(event):
global player_y
player_y = 1
if player_y > 9:
player_y -= 1
update_world()
def keypress_esc(event):
sys.exit()
def update_world():
#Create string with player coordinates and input into dictionary
player_xy = "x", player_x, "y", player_y
player_coord = ''.join(map(str, player_xy))
#Update previous player tile to map tile
coord_keys = coordinates.keys()
for coords in coord_keys:
if coords == player_coord:
coordinates[player_coord] = '€'
else:
coordinates[coords] = ' '
#Print map
width = 9
coord_values = coordinates.values()
i=0
world=""
for item in coord_values:
world = world item " "
i = 1
if i % width == 0:
world = world[:-1] '\n'
world = world[:-1]
#refresh the label that displays the world
world_label.place(x=220,y=100)
world_label.configure(font=("Courier", 24), text=world, bg="white")
root = Tk() #Create window
world_label = Label() #Create World Label widget
world_label.pack()
update_world() #Function update_world
#Sends pressed key values to functions keypress_"x"
root.bind("<w>", keypress_w)
root.bind("<a>", keypress_a)
root.bind("<s>", keypress_s)
root.bind("<d>", keypress_d)
root.bind("<Escape>", keypress_esc)
root.geometry("800x600") #Size of window
root.title('Game 0.1') #Title of window
root.mainloop() #
CodePudding user response:
You can use timer method root.after(delay, func)
to trigger function to simulate keyboard repeat.
New demo code for you. It work for both key pressed at the same time.
from time import sleep
import tkinter as tk
class Root(tk.Tk):
def __init__(self, title, width, height):
super().__init__()
self.title(title)
self.width = width
self.height = height
self.canvas = tk.Canvas(self, width=width, height=height, bg='green')
self.canvas.pack()
self.geometry(f'{width}x{height}')
self.radius = 20
self.delay = 20
self.step = 5
self.x = width // 2
self.y = height // 2
self.press_left = False
self.press_right = False
self.press_up = False
self.press_down = False
self.ball = None
self.draw_ball()
self.binding()
def draw_ball(self):
if self.ball:
self.canvas.delete(self.ball)
self.ball = self.canvas.create_oval(self.x - self.radius, self.y - self.radius,
self.x self.radius, self.y self.radius, fill='white')
self.canvas.update()
def binding(self):
self.bind("<KeyPress-a>", self.left_down)
self.bind("<KeyPress-d>", self.right_down)
self.bind("<KeyPress-w>", self.up_down)
self.bind("<KeyPress-s>", self.down_down)
self.bind("<KeyRelease-a>", self.left_up)
self.bind("<KeyRelease-d>", self.right_up)
self.bind("<KeyRelease-w>", self.up_up)
self.bind("<KeyRelease-s>", self.down_up)
self.bind("<Escape>", self.escape)
def left_down(self, event):
def left():
if self.press_left:
if self.x >= self.radius self.step:
self.x -= self.step
self.draw_ball()
self.after(self.delay, left)
else:
self.bind("<KeyPress-a>", self.left_down)
self.unbind("<KeyPress-a>")
self.press_left = True
left()
def left_up(self, event):
self.press_left = False
def right_down(self, event):
def right():
if self.press_right:
if self.x <= self.width - self.radius - self.step:
self.x = self.step
self.draw_ball()
self.after(self.delay, right)
else:
self.bind("<KeyPress-d>", self.right_down)
self.unbind("<KeyPress-d>")
self.press_right = True
right()
def right_up(self, event):
self.press_right = False
def up_down(self, event):
def up():
if self.press_up:
if self.y >= self.radius self.step:
self.y -= self.step
self.draw_ball()
self.after(self.delay, up)
else:
self.bind("<KeyPress-w>", self.up_down)
self.unbind("<KeyPress-w>")
self.press_up = True
up()
def up_up(self, event):
self.press_up = False
def down_down(self, event):
def down():
if self.press_down:
if self.y <= self.height - self.radius - self.step:
self.y = self.step
self.draw_ball()
self.after(self.delay, down)
else:
self.bind("<KeyPress-s>", self.down_down)
self.unbind("<KeyPress-s>")
self.press_down = True
down()
def down_up(self, event):
self.press_down = False
def escape(self, event):
root.destroy()
root = Root("Game 0.1", 800, 600)
root.mainloop()