mirror of
https://github.com/Estom/notes.git
synced 2026-04-24 10:34:11 +08:00
matplotlib & pandas
This commit is contained in:
291
Python/matplotlab/gallery/event_handling/pipong.md
Normal file
291
Python/matplotlab/gallery/event_handling/pipong.md
Normal file
@@ -0,0 +1,291 @@
|
||||
# Pipong
|
||||
|
||||
一个基于Matplotlib的Pong游戏,说明了一种编写交互动画的方法,它很容易移植到多个后端pipong.py由Paul Ivanov撰写<http://pirsquared.org>
|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
from numpy.random import randn, randint
|
||||
from matplotlib.font_manager import FontProperties
|
||||
|
||||
instructions = """
|
||||
Player A: Player B:
|
||||
'e' up 'i'
|
||||
'd' down 'k'
|
||||
|
||||
press 't' -- close these instructions
|
||||
(animation will be much faster)
|
||||
press 'a' -- add a puck
|
||||
press 'A' -- remove a puck
|
||||
press '1' -- slow down all pucks
|
||||
press '2' -- speed up all pucks
|
||||
press '3' -- slow down distractors
|
||||
press '4' -- speed up distractors
|
||||
press ' ' -- reset the first puck
|
||||
press 'n' -- toggle distractors on/off
|
||||
press 'g' -- toggle the game on/off
|
||||
|
||||
"""
|
||||
|
||||
|
||||
class Pad(object):
|
||||
def __init__(self, disp, x, y, type='l'):
|
||||
self.disp = disp
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.w = .3
|
||||
self.score = 0
|
||||
self.xoffset = 0.3
|
||||
self.yoffset = 0.1
|
||||
if type == 'r':
|
||||
self.xoffset *= -1.0
|
||||
|
||||
if type == 'l' or type == 'r':
|
||||
self.signx = -1.0
|
||||
self.signy = 1.0
|
||||
else:
|
||||
self.signx = 1.0
|
||||
self.signy = -1.0
|
||||
|
||||
def contains(self, loc):
|
||||
return self.disp.get_bbox().contains(loc.x, loc.y)
|
||||
|
||||
|
||||
class Puck(object):
|
||||
def __init__(self, disp, pad, field):
|
||||
self.vmax = .2
|
||||
self.disp = disp
|
||||
self.field = field
|
||||
self._reset(pad)
|
||||
|
||||
def _reset(self, pad):
|
||||
self.x = pad.x + pad.xoffset
|
||||
if pad.y < 0:
|
||||
self.y = pad.y + pad.yoffset
|
||||
else:
|
||||
self.y = pad.y - pad.yoffset
|
||||
self.vx = pad.x - self.x
|
||||
self.vy = pad.y + pad.w/2 - self.y
|
||||
self._speedlimit()
|
||||
self._slower()
|
||||
self._slower()
|
||||
|
||||
def update(self, pads):
|
||||
self.x += self.vx
|
||||
self.y += self.vy
|
||||
for pad in pads:
|
||||
if pad.contains(self):
|
||||
self.vx *= 1.2 * pad.signx
|
||||
self.vy *= 1.2 * pad.signy
|
||||
fudge = .001
|
||||
# probably cleaner with something like...
|
||||
if self.x < fudge:
|
||||
pads[1].score += 1
|
||||
self._reset(pads[0])
|
||||
return True
|
||||
if self.x > 7 - fudge:
|
||||
pads[0].score += 1
|
||||
self._reset(pads[1])
|
||||
return True
|
||||
if self.y < -1 + fudge or self.y > 1 - fudge:
|
||||
self.vy *= -1.0
|
||||
# add some randomness, just to make it interesting
|
||||
self.vy -= (randn()/300.0 + 1/300.0) * np.sign(self.vy)
|
||||
self._speedlimit()
|
||||
return False
|
||||
|
||||
def _slower(self):
|
||||
self.vx /= 5.0
|
||||
self.vy /= 5.0
|
||||
|
||||
def _faster(self):
|
||||
self.vx *= 5.0
|
||||
self.vy *= 5.0
|
||||
|
||||
def _speedlimit(self):
|
||||
if self.vx > self.vmax:
|
||||
self.vx = self.vmax
|
||||
if self.vx < -self.vmax:
|
||||
self.vx = -self.vmax
|
||||
|
||||
if self.vy > self.vmax:
|
||||
self.vy = self.vmax
|
||||
if self.vy < -self.vmax:
|
||||
self.vy = -self.vmax
|
||||
|
||||
|
||||
class Game(object):
|
||||
def __init__(self, ax):
|
||||
# create the initial line
|
||||
self.ax = ax
|
||||
ax.set_ylim([-1, 1])
|
||||
ax.set_xlim([0, 7])
|
||||
padAx = 0
|
||||
padBx = .50
|
||||
padAy = padBy = .30
|
||||
padBx += 6.3
|
||||
|
||||
# pads
|
||||
pA, = self.ax.barh(padAy, .2,
|
||||
height=.3, color='k', alpha=.5, edgecolor='b',
|
||||
lw=2, label="Player B",
|
||||
animated=True)
|
||||
pB, = self.ax.barh(padBy, .2,
|
||||
height=.3, left=padBx, color='k', alpha=.5,
|
||||
edgecolor='r', lw=2, label="Player A",
|
||||
animated=True)
|
||||
|
||||
# distractors
|
||||
self.x = np.arange(0, 2.22*np.pi, 0.01)
|
||||
self.line, = self.ax.plot(self.x, np.sin(self.x), "r",
|
||||
animated=True, lw=4)
|
||||
self.line2, = self.ax.plot(self.x, np.cos(self.x), "g",
|
||||
animated=True, lw=4)
|
||||
self.line3, = self.ax.plot(self.x, np.cos(self.x), "g",
|
||||
animated=True, lw=4)
|
||||
self.line4, = self.ax.plot(self.x, np.cos(self.x), "r",
|
||||
animated=True, lw=4)
|
||||
|
||||
# center line
|
||||
self.centerline, = self.ax.plot([3.5, 3.5], [1, -1], 'k',
|
||||
alpha=.5, animated=True, lw=8)
|
||||
|
||||
# puck (s)
|
||||
self.puckdisp = self.ax.scatter([1], [1], label='_nolegend_',
|
||||
s=200, c='g',
|
||||
alpha=.9, animated=True)
|
||||
|
||||
self.canvas = self.ax.figure.canvas
|
||||
self.background = None
|
||||
self.cnt = 0
|
||||
self.distract = True
|
||||
self.res = 100.0
|
||||
self.on = False
|
||||
self.inst = True # show instructions from the beginning
|
||||
self.background = None
|
||||
self.pads = []
|
||||
self.pads.append(Pad(pA, padAx, padAy))
|
||||
self.pads.append(Pad(pB, padBx, padBy, 'r'))
|
||||
self.pucks = []
|
||||
self.i = self.ax.annotate(instructions, (.5, 0.5),
|
||||
name='monospace',
|
||||
verticalalignment='center',
|
||||
horizontalalignment='center',
|
||||
multialignment='left',
|
||||
textcoords='axes fraction',
|
||||
animated=False)
|
||||
self.canvas.mpl_connect('key_press_event', self.key_press)
|
||||
|
||||
def draw(self, evt):
|
||||
draw_artist = self.ax.draw_artist
|
||||
if self.background is None:
|
||||
self.background = self.canvas.copy_from_bbox(self.ax.bbox)
|
||||
|
||||
# restore the clean slate background
|
||||
self.canvas.restore_region(self.background)
|
||||
|
||||
# show the distractors
|
||||
if self.distract:
|
||||
self.line.set_ydata(np.sin(self.x + self.cnt/self.res))
|
||||
self.line2.set_ydata(np.cos(self.x - self.cnt/self.res))
|
||||
self.line3.set_ydata(np.tan(self.x + self.cnt/self.res))
|
||||
self.line4.set_ydata(np.tan(self.x - self.cnt/self.res))
|
||||
draw_artist(self.line)
|
||||
draw_artist(self.line2)
|
||||
draw_artist(self.line3)
|
||||
draw_artist(self.line4)
|
||||
|
||||
# pucks and pads
|
||||
if self.on:
|
||||
self.ax.draw_artist(self.centerline)
|
||||
for pad in self.pads:
|
||||
pad.disp.set_y(pad.y)
|
||||
pad.disp.set_x(pad.x)
|
||||
self.ax.draw_artist(pad.disp)
|
||||
|
||||
for puck in self.pucks:
|
||||
if puck.update(self.pads):
|
||||
# we only get here if someone scored
|
||||
self.pads[0].disp.set_label(
|
||||
" " + str(self.pads[0].score))
|
||||
self.pads[1].disp.set_label(
|
||||
" " + str(self.pads[1].score))
|
||||
self.ax.legend(loc='center', framealpha=.2,
|
||||
facecolor='0.5',
|
||||
prop=FontProperties(size='xx-large',
|
||||
weight='bold'))
|
||||
|
||||
self.background = None
|
||||
self.ax.figure.canvas.draw_idle()
|
||||
return True
|
||||
puck.disp.set_offsets([[puck.x, puck.y]])
|
||||
self.ax.draw_artist(puck.disp)
|
||||
|
||||
# just redraw the axes rectangle
|
||||
self.canvas.blit(self.ax.bbox)
|
||||
self.canvas.flush_events()
|
||||
if self.cnt == 50000:
|
||||
# just so we don't get carried away
|
||||
print("...and you've been playing for too long!!!")
|
||||
plt.close()
|
||||
|
||||
self.cnt += 1
|
||||
return True
|
||||
|
||||
def key_press(self, event):
|
||||
if event.key == '3':
|
||||
self.res *= 5.0
|
||||
if event.key == '4':
|
||||
self.res /= 5.0
|
||||
|
||||
if event.key == 'e':
|
||||
self.pads[0].y += .1
|
||||
if self.pads[0].y > 1 - .3:
|
||||
self.pads[0].y = 1 - .3
|
||||
if event.key == 'd':
|
||||
self.pads[0].y -= .1
|
||||
if self.pads[0].y < -1:
|
||||
self.pads[0].y = -1
|
||||
|
||||
if event.key == 'i':
|
||||
self.pads[1].y += .1
|
||||
if self.pads[1].y > 1 - .3:
|
||||
self.pads[1].y = 1 - .3
|
||||
if event.key == 'k':
|
||||
self.pads[1].y -= .1
|
||||
if self.pads[1].y < -1:
|
||||
self.pads[1].y = -1
|
||||
|
||||
if event.key == 'a':
|
||||
self.pucks.append(Puck(self.puckdisp,
|
||||
self.pads[randint(2)],
|
||||
self.ax.bbox))
|
||||
if event.key == 'A' and len(self.pucks):
|
||||
self.pucks.pop()
|
||||
if event.key == ' ' and len(self.pucks):
|
||||
self.pucks[0]._reset(self.pads[randint(2)])
|
||||
if event.key == '1':
|
||||
for p in self.pucks:
|
||||
p._slower()
|
||||
if event.key == '2':
|
||||
for p in self.pucks:
|
||||
p._faster()
|
||||
|
||||
if event.key == 'n':
|
||||
self.distract = not self.distract
|
||||
|
||||
if event.key == 'g':
|
||||
self.on = not self.on
|
||||
if event.key == 't':
|
||||
self.inst = not self.inst
|
||||
self.i.set_visible(not self.i.get_visible())
|
||||
self.background = None
|
||||
self.canvas.draw_idle()
|
||||
if event.key == 'q':
|
||||
plt.close()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: pipong.py](https://matplotlib.org/_downloads/pipong.py)
|
||||
- [下载Jupyter notebook: pipong.ipynb](https://matplotlib.org/_downloads/pipong.ipynb)
|
||||
Reference in New Issue
Block a user