~ubuntu-branches/ubuntu/trusty/matplotlib/trusty-proposed

« back to all changes in this revision

Viewing changes to lib/mpl_examples/event_handling/pipong.py

  • Committer: Package Import Robot
  • Author(s): Sandro Tosi
  • Date: 2011-01-25 18:17:56 UTC
  • mfrom: (0.1.1) (1.2.4) (9.1.7 sid)
  • Revision ID: package-import@ubuntu.com-20110125181756-r2ckh9qfadms2k3x
Tags: 1.0.1-1
* New upstream release; Closes: #606116
* debian/patches/{10_build_fix.patch, 20_matplotlibrc_path_search_fix.patch}
  - updated to new upstream code
* debian/patches/30_doc_pass_dpi.patch
  - removed, merged upstream
* debian/rules
  - don't compress objects.inv; thanks to Michael Fladischer for the report;
    Closes: #608760
* debian/rules, debian/patches/30_disable_sample_downloads.patch
  - bypass examples data download from internet, but use local copy instead
* debian/python-matplotlib-data.install
  - install examples sample data
* debian/control
  - bump Standards-Version: to 3.9.1 (no changes needed)
  - removed DM-U-A flag, no more needed
  - added python-xlwt to b-d, needed to build doc examples
  - Benjamin Drung removed himself from the Uploaders list
* debian/copyright
  - updated debian packaging copyright
* debian/patches/40_bts608939_draw_markers_description.patch
  - fix a glitch (missing reference to documentation page) in draw_markers()
    description; thanks to Jakub Wilk for report and patch; Closes: #608939
* debian/patches/50_bts608942_spaces_in_param_args.patch
  - don't separate param and its argument with a space, new sphinx consider
    the first argument as the type; thanks to Jakub Wilk for the report;
    Closes: #608942
* debian/patches/60_doc_output_format.patch
  - obtain the documentation output format even if the value is a unicode (as
    returned by recent sphinx); thanks to Jakub Wilk for the tip on IRC

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
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>
 
5
 
 
6
import numpy as np
 
7
import matplotlib.pyplot as plt
 
8
from numpy.random import randn, randint
 
9
 
 
10
instructions = """
 
11
Player A:       Player B:
 
12
  'e'      up     'i'
 
13
  'd'     down    'k'
 
14
 
 
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
 
26
 
 
27
  """
 
28
 
 
29
class Pad(object):
 
30
    def __init__(self, disp,x,y,type='l'):
 
31
        self.disp = disp
 
32
        self.x = x
 
33
        self.y = y
 
34
        self.w = .3
 
35
        self.score = 0
 
36
        self.xoffset = 0.3
 
37
        self.yoffset = 0.1
 
38
        if type=='r':
 
39
            self.xoffset *= -1.0
 
40
 
 
41
        if type=='l' or type=='r':
 
42
            self.signx = -1.0
 
43
            self.signy = 1.0
 
44
        else:
 
45
            self.signx = 1.0
 
46
            self.signy = -1.0
 
47
    def contains(self, loc):
 
48
        return self.disp.get_bbox().contains(loc.x,loc.y)
 
49
 
 
50
class Puck(object):
 
51
    def __init__(self, disp, pad, field):
 
52
        self.vmax= .2
 
53
        self.disp = disp
 
54
        self.field = field
 
55
        self._reset(pad)
 
56
    def _reset(self,pad):
 
57
        self.x = pad.x + pad.xoffset
 
58
        if pad.y < 0:
 
59
            self.y = pad.y +  pad.yoffset
 
60
        else:
 
61
            self.y = pad.y - pad.yoffset
 
62
        self.vx = pad.x - self.x
 
63
        self.vy = pad.y + pad.w/2 - self.y
 
64
        self._speedlimit()
 
65
        self._slower()
 
66
        self._slower()
 
67
    def update(self,pads):
 
68
        self.x += self.vx
 
69
        self.y += self.vy
 
70
        for pad in pads:
 
71
            if pad.contains(self):
 
72
                self.vx *= 1.2 *pad.signx
 
73
                self.vy *= 1.2 *pad.signy
 
74
        fudge = .001
 
75
        #probably cleaner with something like...if not self.field.contains(self.x, self.y):
 
76
        if self.x < 0+fudge:
 
77
            #print "player A loses"
 
78
            pads[1].score += 1;
 
79
            self._reset(pads[0])
 
80
            return True
 
81
        if self.x > 7-fudge:
 
82
            #print "player B loses"
 
83
            pads[0].score += 1;
 
84
            self._reset(pads[1])
 
85
            return True
 
86
        if self.y < -1+fudge or self.y > 1-fudge:
 
87
            self.vy *= -1.0
 
88
            # add some randomness, just to make it interesting
 
89
            self.vy -= (randn()/300.0 + 1/300.0) * np.sign(self.vy)
 
90
        self._speedlimit()
 
91
        return False
 
92
    def _slower(self):
 
93
        self.vx /= 5.0
 
94
        self.vy /= 5.0
 
95
    def _faster(self):
 
96
        self.vx *= 5.0
 
97
        self.vy *= 5.0
 
98
    def _speedlimit(self):
 
99
        if self.vx > self.vmax:
 
100
            self.vx = self.vmax
 
101
        if self.vx < -self.vmax:
 
102
            self.vx = -self.vmax
 
103
 
 
104
        if self.vy > self.vmax:
 
105
            self.vy = self.vmax
 
106
        if self.vy < -self.vmax:
 
107
            self.vy = -self.vmax
 
108
 
 
109
class Game(object):
 
110
 
 
111
    def __init__(self, ax):
 
112
        # create the initial line
 
113
        self.ax = ax
 
114
        padAx = padBx= .50
 
115
        padAy = padBy= .30
 
116
        padBx+=6.3
 
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)
 
119
 
 
120
        # distractors
 
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)
 
128
 
 
129
        self.canvas = self.ax.figure.canvas
 
130
        self.background = None
 
131
        self.cnt = 0
 
132
        self.distract = True
 
133
        self.res = 100.0
 
134
        self.on = False
 
135
        self.inst = True    # show instructions from the beginning
 
136
        self.background = None
 
137
        self.pads = []
 
138
        self.pads.append( Pad(pA,0,padAy))
 
139
        self.pads.append( Pad(pB,padBx,padBy,'r'))
 
140
        self.pucks =[]
 
141
        self.i = self.ax.annotate(instructions,(.5,0.5),
 
142
                     name='monospace',
 
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)
 
148
 
 
149
    def draw(self, evt):
 
150
        draw_artist = self.ax.draw_artist
 
151
        if self.background is None:
 
152
            self.background = self.canvas.copy_from_bbox(self.ax.bbox)
 
153
 
 
154
        # restore the clean slate background
 
155
        self.canvas.restore_region(self.background)
 
156
 
 
157
        # show the distractors
 
158
        if self.distract:
 
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)
 
167
 
 
168
        # show the instructions - this is very slow
 
169
        if self.inst:
 
170
            self.ax.draw_artist(self.i)
 
171
 
 
172
        # pucks and pads
 
173
        if self.on:
 
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)
 
179
 
 
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()
 
193
                    return True
 
194
                puck.disp.set_offsets([puck.x,puck.y])
 
195
                self.ax.draw_artist(puck.disp)
 
196
 
 
197
 
 
198
        # just redraw the axes rectangle
 
199
        self.canvas.blit(self.ax.bbox)
 
200
 
 
201
        if self.cnt==50000:
 
202
            # just so we don't get carried away
 
203
            print "...and you've been playing for too long!!!"
 
204
            plt.close()
 
205
 
 
206
        self.cnt += 1
 
207
        return True
 
208
 
 
209
    def key_press(self,event):
 
210
        if event.key == '3':
 
211
            self.res *= 5.0
 
212
        if event.key == '4':
 
213
            self.res /= 5.0
 
214
 
 
215
        if event.key == 'e':
 
216
            self.pads[0].y += .1
 
217
            if self.pads[0].y > 1 - .3:
 
218
                self.pads[0].y = 1-.3
 
219
        if event.key == 'd':
 
220
            self.pads[0].y -= .1
 
221
            if self.pads[0].y < -1:
 
222
                self.pads[0].y = -1
 
223
 
 
224
        if event.key == 'i':
 
225
            self.pads[1].y += .1
 
226
            if self.pads[1].y > 1 - .3:
 
227
                self.pads[1].y = 1-.3
 
228
        if event.key == 'k':
 
229
            self.pads[1].y -= .1
 
230
            if self.pads[1].y < -1:
 
231
                self.pads[1].y = -1
 
232
 
 
233
        if event.key == 'a':
 
234
            self.pucks.append(Puck(self.puckdisp,self.pads[randint(2)],self.ax.bbox))
 
235
        if event.key == 'A' and len(self.pucks):
 
236
            self.pucks.pop()
 
237
        if event.key == ' ' and len(self.pucks):
 
238
            self.pucks[0]._reset(self.pads[randint(2)])
 
239
        if event.key == '1':
 
240
            for p in self.pucks:
 
241
                p._slower()
 
242
        if event.key == '2':
 
243
            for p in self.pucks:
 
244
                p._faster()
 
245
 
 
246
        if event.key == 'n':
 
247
            self.distract = not self.distract
 
248
 
 
249
        if event.key == 'g':
 
250
            #self.ax.clear()
 
251
            #self.ax.grid() # seems to be necessary for qt backend
 
252
            self.on = not self.on
 
253
        if event.key == 't':
 
254
            self.inst = not self.inst
 
255
            self.i.set_visible(self.i.get_visible())
 
256
        if event.key == 'q':
 
257
            plt.close()