44import operator
55import time
66import math
7+ import random
78from typing import NamedTuple , Callable , TypeVar , Generator
89from enum import Enum
9- from dataclasses import dataclass
1010from functools import partialmethod
1111
1212
@@ -36,8 +36,11 @@ def run(self):
3636 try :
3737 move = next (motion )
3838 move ()
39+ self .canvas .update ()
3940 except StopIteration :
4041 self ._motions .remove (motion )
42+ self .canvas .update ()
43+ # self.canvas.after(10, self.run)
4144
4245 def add (self , motion : Motion ):
4346 self ._motions .add (motion .start ())
@@ -54,16 +57,12 @@ def running(self):
5457 return bool (self ._motions )
5558
5659
57- @dataclass
5860class Motion :
59- """
60-
61- """
62- canvas : tk .Canvas
63- id : int
64- end : Coord
65-
66- speed : int = 1
61+ def __init__ (self , canvas : tk .Canvas , id : str , end : Coord , speed : float = 1 ):
62+ self .canvas = canvas
63+ self .id = id
64+ self .end = end
65+ self .speed = speed ** 3
6766
6867 def __iter__ (self ):
6968 return self .start ()
@@ -81,13 +80,16 @@ def start(self) -> Generator[Callable]:
8180 """
8281 The entry point for generating move commands.
8382 """
84- self .time = time .time ()
85- self .start = self .current
86- self .distance = self .start .distance (self .end )
87- self .speed = self .speed ** 3
83+ self .reset ()
8884 while self .current != self .end :
85+ print (self .current , self .end )
8986 yield self .move
9087
88+ def reset (self ):
89+ self .time = time .time ()
90+ self .beg = self .current
91+ self .distance = self .beg .distance (self .end )
92+
9193 def move (self ):
9294 self .canvas .move (self .id , * self .increment )
9395 self .canvas .update_idletasks ()
@@ -102,13 +104,16 @@ def time(self, val):
102104
103105 @property
104106 def increment (self ):
105- mult = (self .time * self .speed ) / self .distance
106- point = (self .end - self .start ) * mult + self .start
107-
108- if point .distance (self .end ) > self .journey :
107+ future = self .future
108+ if future .distance (self .end ) > self .journey :
109109 return self .end - self .current
110110 else :
111- return point - self .current
111+ return future - self .current
112+
113+ @property
114+ def future (self ):
115+ mult = (self .time * self .speed ) / self .distance
116+ return (self .end - self .beg ) * mult + self .beg
112117
113118 @property
114119 def current (self ):
@@ -119,6 +124,60 @@ def journey(self):
119124 return self .current .distance (self .end )
120125
121126
127+ class BounceBall (Motion ):
128+
129+ chaos = 3
130+
131+ def kick (self , direction : Point ):
132+ self .canvas .update ()
133+
134+ c1 , c2 = - self .chaos , self .chaos
135+ chaoticx , chaoticy = random .randint (c1 , c2 ), random .randint (c1 , c2 )
136+ self .direction = direction + Coord (chaoticx , chaoticy )
137+ self .end = self .direction * self .canvas .winfo_height ()
138+ self .reset ()
139+
140+ @property
141+ def increment (self ):
142+ bounce = self .get_bounce ()
143+ if bounce != Coord (0 , 0 ):
144+ self .kick (bounce )
145+ return self .future - self .current
146+
147+ def get_bounce (self ):
148+ x1 , y1 , x2 , y2 = self .canvas .bbox (self .id )
149+ bounce = Coord (0 , 0 )
150+ if x1 <= self .bound_x1 :
151+ # print('x1', x1, self.bound_x1)
152+ bounce += Direction .RIGHT
153+ if y1 <= self .bound_y1 :
154+ # print('y1', y1, self.bound_y1)
155+ bounce += Direction .DOWN
156+ if x2 >= self .bound_x2 :
157+ # print('x2', x2, self.bound_x2)
158+ bounce += Direction .LEFT
159+ if y2 >= self .bound_y2 :
160+ # print('y2', y2, self.bound_y2)
161+ bounce += Direction .UP
162+ return bounce
163+
164+ @property
165+ def bound_x1 (self ):
166+ return self .canvas .winfo_x ()
167+
168+ @property
169+ def bound_y1 (self ):
170+ return self .canvas .winfo_y ()
171+
172+ @property
173+ def bound_x2 (self ):
174+ return self .bound_x1 + self .canvas .winfo_width ()
175+
176+ @property
177+ def bound_y2 (self ):
178+ return self .bound_y1 + self .canvas .winfo_height ()
179+
180+
122181class Coord (NamedTuple ):
123182 """
124183 Helper class for managing coordinate values.
@@ -149,10 +208,10 @@ class Coord(NamedTuple):
149208 Operand = TypeVar ('Operand' , 'Coord' , float )
150209
151210 def __apply (self , op : Callable , other : Coord .Operand ) -> Coord :
152- if not isinstance (other , self .__class__ ):
153- other = self .__class__ (other , other )
154211 if isinstance (other , Direction ):
155212 other = other .value
213+ elif not isinstance (other , self .__class__ ):
214+ other = self .__class__ (other , other )
156215
157216 x = op (self .x , other .x )
158217 y = op (self .y , other .y )
@@ -183,6 +242,9 @@ def distance(self, other: Coord) -> float:
183242 diff = other - self
184243 return math .hypot (* diff )
185244
245+ def flip (self ):
246+ return Coord (0 , 0 ) - self
247+
186248 __add__ = partialmethod (__apply , operator .add )
187249 __sub__ = partialmethod (__apply , operator .sub )
188250 __mul__ = partialmethod (__apply , operator .mul )
0 commit comments