2
\$\begingroup\$

I am trying to make a scrolling game in Tkinter. However, with all my for loops and functions it is extremely slow.

I am reading the tutorial from Khan Academy's advanced JS. In their JS game everything is fine, so is it just a problem of python is slow or am I doing things inefficiently.

import tkinter as tk
import random
import time
win = tk.Tk()
win.title("Beaver Game")
win.wm_attributes("-topmost", 1)#Makes it stay on top of other windows
canvas = tk.Canvas(win, width=300, height=300, bg='#97FEFF', bd = 0, highlightthickness = 0)   
canvas.pack()
canvas.create_rectangle(0, 270,300, 300, fill = "brown")
win.update()

class Beaver:
    def __init__(self, canvas, color):
        self.canvas = canvas
        self.id = self.canvas.create_rectangle(150,150, 100, 100, fill = color)
        self.y = 0
        self.canvas_height = self.canvas.winfo_height()
        self.canvas_width = self.canvas.winfo_width()
        self.canvas.bind_all('<KeyPress-Up>', self.turn_left)
        self.canvas.bind_all('<KeyPress-Down>', self.turn_right)
        self.sticks = 0
    def draw(self):
        self.canvas.move(self.id, 0, self.y)
        pos = self.canvas.coords(self.id)
        if pos[1] <= 0:
            self.y = 0
        if pos[3] >= self.canvas_height:
            self.y = 0
    def turn_left(self, evt):
        self.y = -3
    def turn_right(self,evt):
        self.y = 3
class Stick:
    def __init__(self, canvas, color, x, y):
        self.canvas = canvas
        self.color = color
        self.x = x
        self.y = y        
    def draw(self):
        canvas.create_rectangle(self.x, self.y, 5, 40, fill = self.color)
beaver = Beaver(canvas, "pink")

grassXs = []
for i in range(25):
     grassXs.append(i * 25)

sticks = []
for i in range(40): 
    sticks.append(Stick(canvas, "black", i * 4 + 100, random.randint(20, 26)))

while 1:
   for i in range(len(grassXs)):
      canvas.create_rectangle(grassXs[i], 250, 270, 270, fill = "green")
      grassXs[i] -= 1
      if (grassXs[i] <= -20):
         grassXs[i] = canvas.winfo_width()
   for i in range(len(sticks)):
       sticks[i].draw()
       sticks[i].x -= 1
   beaver.draw()
   win.update_idletasks()
   win.update()
\$\endgroup\$

migrated from stackoverflow.com Jun 17 '16 at 15:10

This question came from our site for professional and enthusiast programmers.

  • 4
    \$\begingroup\$ Well, Tkinter's purpose is not gaming, it's UI. For gaming, use the pygame module. \$\endgroup\$ – Yotam Salmon Jun 17 '16 at 14:19
  • \$\begingroup\$ Tkinter was not designed / optimized for "update every frame" kind of displays, JavaScript is optimized for that kind of usage. There isn't much you can do to optimize it yourself without reworking a bunch of the tcl backend or just using something that is optimized for this usage like pygame. \$\endgroup\$ – Tadhg McDonald-Jensen Jun 17 '16 at 14:20
1
\$\begingroup\$

You are doing animation wrong. As a rule of thumb you shouldn't have your own infinite loop in a Tkinter program. Tkinter already has an efficient infinite loop — the mainloop function.

Here are a few Stack Overflow questions dealing with Tkinter animation:

I will say that the canvas has performance issues when there are hundreds of thousands of objects on the canvas, and it may start appearing when there are tens of thousands.

In your case, by my estimation you're creating a couple thousand canvas objects per second, and that's just way too many to expect good performance. Considering you're making a side-scroller, you simply don't need to create all those objects every second.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.