# L-5 MCS 275 Fri 22 Jan 2010 : similating billiard ball from Tkinter import * import random,math class BilliardBall(): """ GUI to simulate billiard ball movement. """ def __init__(self,wdw,dimension,increment,delay): "determines the layout of the GUI" wdw.title('a pool table') self.dim = dimension # dimension of the canvas self.inc = increment self.dly = IntVar() self.path = IntVar() self.L = Label(wdw,text="delay",justify=LEFT) self.L.grid(row=0,column=0) self.s = Scale(wdw,orient='vertical',\ from_=0,to=200,tickinterval=20,resolution=1,\ length=dimension,variable=self.dly) self.s.grid(row=1,column=0) self.s.set(delay) self.ex = Entry(wdw) # for x value self.ex.grid(row=0,column=1) self.ex.insert(INSERT,"x = ") self.ey = Entry(wdw) # for y value self.ey.grid(row=0,column=2) self.ey.insert(INSERT,"y = ") self.cb = Checkbutton(wdw,text="draw path",\ variable=self.path,onvalue=1,offvalue=0) self.cb.grid(row=0,column=3) self.c = Canvas(wdw,width=self.dim,\ height=self.dim,bg ='green') self.c.grid(row=1,column=1,columnspan=3) self.go = False # state of animation self.b0 = Button(wdw,text='start',\ command = self.start) self.b0.grid(row=2,column=1,sticky=W+E) self.b1 = Button(wdw,text='stop',\ command = self.stop) self.b1.grid(row=2,column=2,sticky=W+E) self.b2 = Button(wdw,text='clear',\ command = self.clear) self.b2.grid(row=2,column=3,sticky=W+E) # initial coordinates of the ball self.x = random.randint(10,self.dim-10) self.y = random.randint(10,self.dim-10) def MapToTable(self,p): "keeps the ball on the pool table" if p < 0: (q,r) = divmod(-p,self.dim) else: (q,r) = divmod(p,self.dim) if q % 2 == 1: r = self.dim - r return r def ShowCoordinates(self,x,y): "show coordinates in entry fields" sx = 'x = %d' % x sy = 'y = %d' % y self.ex.delete(0,END) self.ex.insert(INSERT,sx) self.ey.delete(0,END) self.ey.insert(INSERT,sy) def DrawBall(self): "draws the ball on the pool table" x = self.MapToTable(self.x) y = self.MapToTable(self.y) self.ShowCoordinates(x,y) self.c.delete('dot') self.c.create_oval(x-6,y-6,x+6,y+6,width=1,\ outline='black',fill='red',tags='dot') def DrawPath(self,x0,y0,x1,y1): "draws the line from (x0,y0) to (x1,y1)" px0 = self.MapToTable(x0) py0 = self.MapToTable(y0) px1 = self.MapToTable(x1) py1 = self.MapToTable(y1) self.c.create_line(px0,py0,px1,py1,width=2) def animate(self): "performs the animation" self.DrawBall() angle = random.uniform(0,2*math.pi) vx = math.cos(angle) vy = math.sin(angle) while self.go: x = self.x; y = self.y self.x = x + vx*self.inc self.y = y + vy*self.inc self.c.after(self.dly.get()) self.DrawBall() if self.path.get() == 1: self.DrawPath(x,y,self.x,self.y) self.c.update() def start(self): "starts the animation" self.go = True self.animate() def stop(self): "stops the animation" self.go = False def clear(self): "clears the canvas" self.c.delete(ALL) def main(): top = Tk() dimension = 400 # dimension of pool table increment = 10 # increment for coordinates delay = 50 # how much sleep before update show = BilliardBall(top,dimension,increment,delay) top.mainloop() if __name__ == "__main__": main()