2
# A matplotlib based game of Pong illustrating one way to write interactive
3
# animation which are easily ported to multiply backends
4
# pipong.py was written by Paul Ivanov <http://pirsquared.org>
7
import matplotlib.pyplot as plt
8
from numpy.random import randn, randint
15
press 't' -- close these instructions
16
(animation will be much faster)
17
press 'a' -- add a puck
18
press 'A' -- remove a puck
19
press '1' -- slow down all pucks
20
press '2' -- speed up all pucks
21
press '3' -- slow down distractors
22
press '4' -- speed up distractors
23
press ' ' -- reset the first puck
24
press 'n' -- toggle distractors on/off
25
press 'g' -- toggle the game on/off
30
def __init__(self, disp,x,y,type='l'):
41
if type=='l' or type=='r':
47
def contains(self, loc):
48
return self.disp.get_bbox().contains(loc.x,loc.y)
51
def __init__(self, disp, pad, field):
57
self.x = pad.x + pad.xoffset
59
self.y = pad.y + pad.yoffset
61
self.y = pad.y - pad.yoffset
62
self.vx = pad.x - self.x
63
self.vy = pad.y + pad.w/2 - self.y
67
def update(self,pads):
71
if pad.contains(self):
72
self.vx *= 1.2 *pad.signx
73
self.vy *= 1.2 *pad.signy
75
#probably cleaner with something like...if not self.field.contains(self.x, self.y):
77
#print "player A loses"
82
#print "player B loses"
86
if self.y < -1+fudge or self.y > 1-fudge:
88
# add some randomness, just to make it interesting
89
self.vy -= (randn()/300.0 + 1/300.0) * np.sign(self.vy)
98
def _speedlimit(self):
99
if self.vx > self.vmax:
101
if self.vx < -self.vmax:
104
if self.vy > self.vmax:
106
if self.vy < -self.vmax:
111
def __init__(self, ax):
112
# create the initial line
117
pA, = self.ax.barh(padAy,.2, height=.3,color='k', alpha=.5, edgecolor='b',lw=2,label="Player B", animated=True)
118
pB, = self.ax.barh(padBy,.2, height=.3, left=padBx, color='k',alpha=.5, edgecolor='r',lw=2,label="Player A",animated=True)
121
self.x = np.arange(0,2.22*np.pi,0.01)
122
self.line, = self.ax.plot(self.x, np.sin(self.x),"r", animated=True, lw=4)
123
self.line2, = self.ax.plot(self.x, np.cos(self.x),"g", animated=True, lw=4)
124
self.line3, = self.ax.plot(self.x, np.cos(self.x),"g", animated=True, lw=4)
125
self.line4, = self.ax.plot(self.x, np.cos(self.x),"r", animated=True, lw=4)
126
self.centerline,= self.ax.plot([3.5,3.5], [1,-1],'k',alpha=.5, animated=True, lw=8)
127
self.puckdisp = self.ax.scatter([1],[1],label='_nolegend_', s=200,c='g',alpha=.9,animated=True)
129
self.canvas = self.ax.figure.canvas
130
self.background = None
135
self.inst = True # show instructions from the beginning
136
self.background = None
138
self.pads.append( Pad(pA,0,padAy))
139
self.pads.append( Pad(pB,padBx,padBy,'r'))
141
self.i = self.ax.annotate(instructions,(.5,0.5),
143
verticalalignment='center',
144
horizontalalignment='center',
145
multialignment='left',
146
textcoords='axes fraction',animated=True )
147
self.canvas.mpl_connect('key_press_event', self.key_press)
150
draw_artist = self.ax.draw_artist
151
if self.background is None:
152
self.background = self.canvas.copy_from_bbox(self.ax.bbox)
154
# restore the clean slate background
155
self.canvas.restore_region(self.background)
157
# show the distractors
159
self.line.set_ydata(np.sin(self.x+self.cnt/self.res))
160
self.line2.set_ydata(np.cos(self.x-self.cnt/self.res))
161
self.line3.set_ydata(np.tan(self.x+self.cnt/self.res))
162
self.line4.set_ydata(np.tan(self.x-self.cnt/self.res))
163
draw_artist(self.line)
164
draw_artist(self.line2)
165
draw_artist(self.line3)
166
draw_artist(self.line4)
168
# show the instructions - this is very slow
170
self.ax.draw_artist(self.i)
174
self.ax.draw_artist(self.centerline)
175
for pad in self.pads:
176
pad.disp.set_y(pad.y)
177
pad.disp.set_x(pad.x)
178
self.ax.draw_artist(pad.disp)
180
for puck in self.pucks:
181
if puck.update(self.pads):
182
# we only get here if someone scored
183
self.pads[0].disp.set_label(" "+ str(self.pads[0].score))
184
self.pads[1].disp.set_label(" "+ str(self.pads[1].score))
185
self.ax.legend(loc='center')
186
self.leg = self.ax.get_legend()
187
#self.leg.draw_frame(False) #don't draw the legend border
188
self.leg.get_frame().set_alpha(.2)
189
plt.setp(self.leg.get_texts(),fontweight='bold',fontsize='xx-large')
190
self.leg.get_frame().set_facecolor('0.2')
191
self.background = None
192
self.ax.figure.canvas.draw()
194
puck.disp.set_offsets([puck.x,puck.y])
195
self.ax.draw_artist(puck.disp)
198
# just redraw the axes rectangle
199
self.canvas.blit(self.ax.bbox)
202
# just so we don't get carried away
203
print "...and you've been playing for too long!!!"
209
def key_press(self,event):
217
if self.pads[0].y > 1 - .3:
218
self.pads[0].y = 1-.3
221
if self.pads[0].y < -1:
226
if self.pads[1].y > 1 - .3:
227
self.pads[1].y = 1-.3
230
if self.pads[1].y < -1:
234
self.pucks.append(Puck(self.puckdisp,self.pads[randint(2)],self.ax.bbox))
235
if event.key == 'A' and len(self.pucks):
237
if event.key == ' ' and len(self.pucks):
238
self.pucks[0]._reset(self.pads[randint(2)])
247
self.distract = not self.distract
251
#self.ax.grid() # seems to be necessary for qt backend
252
self.on = not self.on
254
self.inst = not self.inst
255
self.i.set_visible(self.i.get_visible())