Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/bounce.py
diff options
context:
space:
mode:
authorWalter Bender <walter.bender@gmail.com>2011-10-18 18:32:57 (GMT)
committer Walter Bender <walter.bender@gmail.com>2011-10-18 18:32:57 (GMT)
commitb0aa1047d2fc578bdb555622333dbd977068584b (patch)
treef7505c0453527705022afd61787b581427c72f0b /bounce.py
parent03fc20cc788bc100e5b7aaea8f604a6283f3fd8f (diff)
refactoring to make code easier to read
Diffstat (limited to 'bounce.py')
-rw-r--r--bounce.py402
1 files changed, 85 insertions, 317 deletions
diff --git a/bounce.py b/bounce.py
index 6648821..26f5f23 100644
--- a/bounce.py
+++ b/bounce.py
@@ -16,98 +16,50 @@
# the number of segments in the bar,
# the number of times this challenge has been played]
-EASY = [['1/2', 2, 0], ['1/3', 3, 0], ['1/4', 4, 0],
- ['2/4', 4, 0], ['2/3', 3, 0], ['3/4', 4, 0]]
-MEDIUM = [['1/6', 6, 0], ['2/6', 6, 0], ['3/6', 6, 0],
- ['4/6', 6, 0], ['5/6', 6, 0],
- ['1/8', 8, 0], ['2/8', 8, 0], ['3/8', 8, 0],
- ['4/8', 8, 0], ['5/8', 8, 0], ['6/8', 8, 0],
- ['7/8', 8, 0]]
-HARD = [['1/12', 12, 0], ['2/12', 12, 0], ['3/12', 12, 0],
- ['4/12', 12, 0], ['3/12', 12, 0], ['6/12', 12, 0],
- ['7/12', 12, 0], ['8/12', 12, 0], ['9/12', 12, 0],
- ['10/12', 12, 0], ['11/12', 12, 0],
- ['1/5', 10, 0], ['2/5', 10, 0], ['3/5', 10, 0],
- ['4/5', 10, 0],
- ['1/10', 10, 0], ['2/10', 10, 0], ['3/10', 10, 0],
- ['4/10', 10, 0], ['5/10', 10, 0], ['6/10', 10, 0],
- ['7/10', 10, 0], ['8/10', 10, 0], ['9/10', 10, 0],
- ['1/16', 4, 0], ['2/16', 4, 0], ['3/16', 4, 0],
- ['4/16', 4, 0], ['5/16', 4, 0], ['6/16', 4, 0],
- ['7/16', 4, 0], ['8/16', 4, 0], ['9/16', 4, 0],
- ['10/16', 4, 0], ['11/16', 4, 0], ['12/16', 4, 0],
- ['13/16', 4, 0], ['14/16', 4, 0], ['15/16', 4, 0]]
-EXPERT = 100 # after some number of correct answers, don't segment the bar
-BAR_HEIGHT = 25
+CHALLENGES = [[['1/2', 2, 0], ['1/3', 3, 0], ['1/4', 4, 0],
+ ['2/4', 4, 0], ['2/3', 3, 0], ['3/4', 4, 0]],
+ [['1/8', 8, 0], ['2/8', 8, 0], ['3/8', 8, 0],
+ ['4/8', 8, 0], ['5/8', 8, 0], ['6/8', 8, 0],
+ ['7/8', 8, 0]],
+ [['1/6', 6, 0], ['2/6', 6, 0], ['3/6', 6, 0],
+ ['4/6', 6, 0], ['5/6', 6, 0]],
+ [['1/5', 10, 0], ['2/5', 10, 0], ['3/5', 10, 0],
+ ['4/5', 10, 0]],
+ [['1/10', 10, 0], ['2/10', 10, 0], ['3/10', 10, 0],
+ ['4/10', 10, 0], ['5/10', 10, 0], ['6/10', 10, 0],
+ ['7/10', 10, 0], ['8/10', 10, 0], ['9/10', 10, 0]],
+ [['1/12', 12, 0], ['2/12', 12, 0], ['3/12', 12, 0],
+ ['4/12', 12, 0], ['3/12', 12, 0], ['6/12', 12, 0],
+ ['7/12', 12, 0], ['8/12', 12, 0], ['9/12', 12, 0],
+ ['10/12', 12, 0], ['11/12', 12, 0]],
+ [['1/16', 4, 0], ['2/16', 4, 0], ['3/16', 4, 0],
+ ['4/16', 4, 0], ['5/16', 4, 0], ['6/16', 4, 0],
+ ['7/16', 4, 0], ['8/16', 4, 0], ['9/16', 4, 0],
+ ['10/16', 4, 0], ['11/16', 4, 0], ['12/16', 4, 0],
+ ['13/16', 4, 0], ['14/16', 4, 0], ['15/16', 4, 0]]]
+REWARD_HEIGHT = 25
STEPS = 100. # number of time steps per bounce rise and fall
STEP_PAUSE = 50 # milliseconds between steps
BOUNCE_PAUSE = 3000 # milliseconds between bounces
DX = 10 # starting step size for horizontal movement
DDX = 1.25 # acceleration during keypress
-ANIMATION = {10: (0, 1), 15: (1, 2), 20: (2, 1), 25: (1, 2), 30: (2, 1),
- 35: (1, 2), 40: (2, 3), 45: (3, 4), 50: (4, 3), 55: (3, 4),
- 60: (4, 3), 65: (3, 4), 70: (4, 5), 75: (5, 6), 80: (6, 5),
- 85: (5, 6), 90: (6, 7)}
ACCELEROMETER_DEVICE = '/sys/devices/platform/lis3lv02d/position'
CRASH = 'crash.ogg' # wrong answer sound
LAUGH = 'bottle.ogg' # correct answer sound
BUBBLES = 'bubbles.ogg' # Easter Egg sound
-# Easter Egg animation graphics
-TRANSFORMS = ['<g>',
- '<g transform="matrix(0.83251323,0.17764297,-0.48065174, \
-1.0074555,27.969568,-8.7531294)">',
- '<g transform="matrix(-0.83251323,0.17764297,0.48065174, \
-1.0074555,57.030432,-8.7531294)">',
- '<g transform="matrix(0.57147881,-0.357582,-0.32994345, \
-0.96842187,32.525583,15.686767)">',
- '<g transform="matrix(-0.57147881,-0.357582,0.32994345, \
-0.96842187,52.474417,15.686767)">',
- '<g transform="matrix(0.39557109,-0.57943591,-0.22838308, \
-0.86196565,35.595823,29.733447)">',
- '<g transform="matrix(-0.39557109,-0.57943591,0.22838308, \
-0.86196565,49.404177,29.733447)">',
- '<g transform="matrix(1,0,0,0.08410415,0,73.873449)">']
-PUNCTURE = \
-' <g \
- transform="translate(2.5316175, -8)">\
- <path \
- d="m 33.19688,68.961518 c 3.900378,7.602149 10.970659,7.634416 \
-13.708164,7.432138"\
- style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;\
-stroke-miterlimit:4" />\
- <path \
- d="m 33.031721,77.05429 c 8.199837,0.123635 12.819227,-7.570626 \
-12.882372,-8.423089" \
- style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;\
-stroke-miterlimit:4" />\
- </g>'
-AIR = \
-' <g \
- transform="matrix(0.63786322,0,0,0.64837179,17.379518,68.534252)"> \
- <path \
- d="M 39.054054,1.75 C 37.741313,16.51834 25.926641,23.082047 \
-25.926641,23.082047 l 0,0" \
- style="fill:none;stroke:#0ac9fb;stroke-width:6.0;stroke-linecap:round;\
-stroke-miterlimit:4;" />\
- <path \
- d="m 39.710425,1.75 c 1.312741,14.76834 13.127413,21.332047 \
-13.127413,21.332047 l 0,0" \
- style="fill:none;stroke:#0ac9fb;stroke-width:6.0;stroke-linecap:round;\
-stroke-miterlimit:4" />\
- <path \
- d="m 39.054054,1.75 c 1.969112,3.281854 -0.656371,20.347491 \
--0.656371,20.347491 l 0,0" \
- style="fill:none;stroke:#0ac9fb;stroke-width:6.0;stroke-linecap:round;\
-stroke-miterlimit:4" />\
- </g>'
import gtk
from random import uniform
import os
import gobject
+from svg_utils import svg_header, svg_footer, svg_rect, svg_str_to_pixbuf, \
+ svg_from_file
from play_audio import play_audio_from_file
+from ball import Ball
+from bar import Bar
+
from gettext import gettext as _
import logging
@@ -122,118 +74,6 @@ except ImportError:
from sprites import Sprites, Sprite
-def generate_xo_svg(scale=1.0, colors=["#C0C0C0", "#282828"]):
- ''' Returns an SVG string representing an XO image '''
- return _svg_header(55, 55, scale) + \
- _svg_xo(colors[0], colors[1]) + \
- _svg_footer()
-
-
-def svg_str_to_pixbuf(svg_string):
- ''' Load pixbuf from SVG string '''
- pl = gtk.gdk.PixbufLoader('svg')
- pl.write(svg_string)
- pl.close()
- pixbuf = pl.get_pixbuf()
- return pixbuf
-
-
-def _svg_rect(w, h, rx, ry, x, y, fill, stroke):
- ''' Returns an SVG rectangle '''
- svg_string = ' <rect\n'
- svg_string += ' width="%f"\n' % (w)
- svg_string += ' height="%f"\n' % (h)
- svg_string += ' rx="%f"\n' % (rx)
- svg_string += ' ry="%f"\n' % (ry)
- svg_string += ' x="%f"\n' % (x)
- svg_string += ' y="%f"\n' % (y)
- svg_string += _svg_style('fill:%s;stroke:%s;' % (fill, stroke))
- return svg_string
-
-
-def _svg_xo(fill, stroke, width=3.5):
- ''' Returns XO icon graphic '''
- svg_string = '<path d="M33.233,35.1l10.102,10.1c0.752,\
-0.75,1.217,1.783,1.217,2.932\
- c0,2.287-1.855,4.143-4.146,4.143c-1.145,0-2.178-0.463-2.932-1.211L27.372,\
-40.961l-10.1,10.1c-0.75,0.75-1.787,1.211-2.934,1.211\
- c-2.284,0-4.143-1.854-4.143-4.141c0-1.146,0.465-2.184,\
-1.212-2.934l10.104-10.102L11.409,24.995\
- c-0.747-0.748-1.212-1.785-1.212-2.93c0-2.289,1.854-4.146,4.146-4.146c1.143,\
-0,2.18,0.465,2.93,1.214l10.099,10.102l10.102-10.103\
- c0.754-0.749,1.787-1.214,2.934-1.214c2.289,0,4.146,1.856,4.146,4.145c0,\
-1.146-0.467,2.18-1.217,2.932L33.233,35.1z" '
- svg_string += _svg_style('fill:%s;stroke:%s;stroke_width:%f' % (fill,
- stroke,
- width))
- svg_string += '\n<circle cx="27.371" cy="10.849" r="8.122" '
- svg_string += _svg_style('fill:%s;stroke:%s;stroke_width:%f' % (fill,
- stroke,
- width))
- return svg_string
-
-
-def _svg_header(w, h, scale, hscale=1.0):
- ''' Returns SVG header; some beads are elongated (hscale) '''
- svg_string = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n'
- svg_string += '<!-- Created with Python -->\n'
- svg_string += '<svg\n'
- svg_string += ' xmlns:svg="http://www.w3.org/2000/svg"\n'
- svg_string += ' xmlns="http://www.w3.org/2000/svg"\n'
- svg_string += ' version="1.0"\n'
- svg_string += ' width="%f"\n' % (w * scale)
- svg_string += ' height="%f">\n' % (h * scale * hscale)
- svg_string += '<g\n transform="matrix(%f,0,0,%f,0,0)">\n' % (
- scale, scale)
- return svg_string
-
-
-def _svg_footer():
- ''' Returns SVG footer '''
- svg_string = '</g>\n'
- svg_string += '</svg>\n'
- return svg_string
-
-
-def _svg_style(extras=''):
- ''' Returns SVG style for shape rendering '''
- return 'style="%s"/>\n' % (extras)
-
-
-def svg_from_file(pathname):
- ''' Read SVG string from a file '''
- f = file(pathname, 'r')
- svg = f.read()
- f.close()
- return(svg)
-
-
-def _extract_svg_payload(fd):
- """Returns everything between <svg ...> and </svg>"""
- payload = ''
- looking_for_start_svg_token = True
- looking_for_close_token = True
- looking_for_end_svg_token = True
- for line in fd:
- if looking_for_start_svg_token:
- if line.find('<svg') < 0:
- continue
- looking_for_start_svg_token = False
- line = line.split('<svg', 1)[1]
- if looking_for_close_token:
- if line.find('>') < 0:
- continue
- looking_for_close_token = False
- line = line.split('>', 1)[1]
- if looking_for_end_svg_token:
- if line.find('</svg>') < 0:
- payload += line
- continue
- payload += line.split('</svg>')[0]
- break
- return payload
-
-
class Bounce():
''' The Bounce class is used to define the ball and the user
interaction. '''
@@ -287,8 +127,10 @@ class Bounce():
self._create_sprites(path)
+ self.challenge = 0
+ self.expert = False
self.challenges = []
- for challenge in EASY:
+ for challenge in CHALLENGES[self.challenge]:
self.challenges.append(challenge)
self.fraction = 0.5 # the target of the current challenge
self.label = '1/2' # the label
@@ -316,83 +158,21 @@ class Bounce():
os.path.join(path, 'Easter_egg.svg')))
self.blank_graphic = svg_str_to_pixbuf(
- _svg_header(BAR_HEIGHT, BAR_HEIGHT, 1.0) + \
- _svg_rect(BAR_HEIGHT, BAR_HEIGHT, 5, 5, 0, 0,
- '#C0C0C0', '#282828') + \
- _svg_footer())
-
- self.ball = Sprite(self.sprites, 0, 0, svg_str_to_pixbuf(
- svg_from_file(os.path.join(path, 'basketball.svg'))))
- self.ball.set_layer(1)
- self.ball.set_label_attributes(24)
-
- ball = _extract_svg_payload(
- file(os.path.join(path, 'basketball.svg'), 'r'))
- self.cells = [] # Easter Egg animation
- for i in range(8):
- self.cells.append(Sprite(
- self.sprites, 0, 0, svg_str_to_pixbuf(
- _svg_header(85, 85, 1.0) + TRANSFORMS[i] + \
- ball + PUNCTURE + AIR + '</g>' + _svg_footer())))
-
- for spr in self.cells:
- spr.set_layer(1)
- spr.move((0, self.height)) # move animation cells off screen
- self.frame = 0
-
- mark = _svg_header(self.ball.rect[2] / 2.,
- BAR_HEIGHT * self.scale + 4, 1.0) + \
- _svg_rect(self.ball.rect[2] / 2.,
- BAR_HEIGHT * self.scale + 4, 0, 0, 0, 0,
- '#FF0000', '#FF0000') + \
- _svg_rect(1, BAR_HEIGHT * self.scale + 4, 0, 0,
- self.ball.rect[2] / 4., 0, '#000000', '#000000') + \
- _svg_footer()
- self.mark = Sprite(self.sprites, 0,
- self.height, # hide off bottom of screen
- svg_str_to_pixbuf(mark))
- self.mark.set_layer(2)
-
- self.bars = {}
- self.bars[2] = Sprite(self.sprites, 0, 0,
- svg_str_to_pixbuf(self._gen_bar(2)))
- self.bars[2].move((int(self.ball.rect[2] / 2),
- self.height - int((self.ball.rect[3] + \
- self.bars[2].rect[3]) / 2)))
- self.current_bar = self.bars[2]
-
- num = _svg_header(BAR_HEIGHT * self.scale, BAR_HEIGHT * self.scale,
- 1.0) + \
- _svg_rect(BAR_HEIGHT * self.scale,
- BAR_HEIGHT * self.scale, 0, 0, 0, 0,
- 'none', 'none') + \
- _svg_footer()
- self.left = Sprite(self.sprites, int(self.ball.rect[2] / 4),
- self.bars[2].rect[1], svg_str_to_pixbuf(num))
- self.left.set_label('0')
- self.right = Sprite(self.sprites,
- self.width - int(self.ball.rect[2] / 2),
- self.bars[2].rect[1], svg_str_to_pixbuf(num))
- self.right.set_label('1')
-
- self.ball_y_max = self.bars[2].rect[1] - self.ball.rect[3]
- self.ball.move((int((self.width - self.ball.rect[2]) / 2),
- self.ball_y_max))
+ svg_header(REWARD_HEIGHT, REWARD_HEIGHT, 1.0) + \
+ svg_rect(REWARD_HEIGHT, REWARD_HEIGHT, 5, 5, 0, 0,
+ '#C0C0C0', '#282828') + \
+ svg_footer())
+
+ self.ball = Ball(self.sprites, os.path.join(path, 'basketball.svg'))
+ self.current_frame = 0
- def _gen_bar(self, nsegments):
- ''' Return a bar with n segments '''
- svg = _svg_header(self.width - self.ball.rect[2], BAR_HEIGHT, 1.0)
- dx = (self.width - self.ball.rect[2]) / float(nsegments)
- for i in range(int(nsegments) / 2):
- svg += _svg_rect(dx, BAR_HEIGHT * self.scale, 0, 0,
- i * 2 * dx, 0, '#FFFFFF', '#FFFFFF')
- svg += _svg_rect(dx, BAR_HEIGHT * self.scale, 0, 0,
- (i * 2 + 1) * dx, 0, '#AAAAAA', '#AAAAAA')
- if int(nsegments) % 2 == 1: # odd
- svg += _svg_rect(dx, BAR_HEIGHT * self.scale, 0, 0,
- (i * 2 + 2) * dx, 0, '#FFFFFF', '#FFFFFF')
- svg += _svg_footer()
- return svg
+ self.bar = Bar(self.sprites, self.width, self.height, self.scale,
+ self.ball.width())
+ self.current_bar = self.bar.get_bar(2)
+
+ self.ball_y_max = self.bar.bar_y() - self.ball.height()
+ self.ball.move_ball((int((self.width - self.ball.width()) / 2),
+ self.ball_y_max))
def pause(self):
''' Pause play when visibility changes '''
@@ -458,13 +238,12 @@ class Bounce():
if self.select_a_fraction and self.press == self.current_bar:
# Find the fraction closest to the click
fraction = self._search_challenges(
- (x - self.current_bar.rect[0]) / \
- float(self.current_bar.rect[2]))
+ (x - self.bar.bar_x()) / float(self.bar.width()))
self.select_a_fraction = False
self.activity.send_a_fraction(fraction)
self.play_a_fraction(fraction)
else:
- if self.timeout is None and self.press == self.ball:
+ if self.timeout is None and self.press == self.ball.ball:
self._choose_a_fraction()
self._move_ball()
return True
@@ -484,7 +263,7 @@ class Bounce():
def _move_ball(self):
''' Move the ball and test boundary conditions '''
if self.new_bounce:
- self.mark.move((0, self.height)) # hide the mark
+ self.bar.mark.move((0, self.height)) # hide the mark
if not self.we_are_sharing():
self._choose_a_fraction()
self.new_bounce = False
@@ -497,11 +276,11 @@ class Bounce():
self.dx = float(xyz[0]) / 18.
fh.close()
- if self.ball.get_xy()[0] + self.dx > 0 and \
- self.ball.get_xy()[0] + self.dx < self.width - self.ball.rect[2]:
- self.ball.move_relative((int(self.dx), int(self.dy)))
+ if self.ball.ball_x() + self.dx > 0 and \
+ self.ball.ball_x() + self.dx < self.width - self.ball.width():
+ self.ball.move_ball_relative((int(self.dx), int(self.dy)))
else:
- self.ball.move_relative((0, int(self.dy)))
+ self.ball.move_ball_relative((0, int(self.dy)))
# speed up ball in x while key is pressed
self.dx *= DDX
@@ -509,9 +288,9 @@ class Bounce():
# accelerate in y
self.dy += self.ddy
- if self.ball.get_xy()[1] >= self.ball_y_max:
+ if self.ball.ball_y() >= self.ball_y_max:
# hit the bottom
- self.ball.move((self.ball.get_xy()[0], self.ball_y_max))
+ self.ball.move_ball((self.ball.ball_x(), self.ball_y_max))
self._test()
self.new_bounce = True
@@ -538,10 +317,11 @@ class Bounce():
if self.new_bounce:
self.dy = self.ddy * (1 - STEPS) / 2 # initial step size
self.new_bounce = False
- self.frame = 0
+ self.current_frame = 0
self.frame_counter = 0
- self.cells[self.frame].move(self.ball.get_xy())
- self.ball.move((self.ball.get_xy()[0], self.height))
+ self.ball.move_frame(self.current_frame,
+ (self.ball.ball_x(), self.ball.ball_y()))
+ self.ball.move_ball((self.ball.ball_x(), self.height))
gobject.idle_add(play_audio_from_file, self, self.path_to_bubbles)
if self.accelerometer:
@@ -552,30 +332,23 @@ class Bounce():
fh.close()
else:
self.dx = uniform(-int(DX * self.scale), int(DX * self.scale))
- self.cells[self.frame].move_relative((int(self.dx), int(self.dy)))
+ self.ball.move_frame_relative(self.current_frame, (int(self.dx),
+ int(self.dy)))
self.dy += self.ddy
self.frame_counter += 1
- if self.frame_counter in ANIMATION:
- self._switch_cells(ANIMATION[self.frame_counter])
+ self.current_frame = self.ball.next_frame(self.frame_counter)
- if self.cells[self.frame].get_xy()[1] >= self.ball_y_max:
+ if self.ball.frame_y(self.current_frame) >= self.ball_y_max:
# hit the bottom
- self.ball.move((self.ball.get_xy()[0], self.ball_y_max))
- for spr in self.cells:
- spr.move((0, self.height)) # hide the animation frames
+ self.ball.move_ball((self.ball.ball_x(), self.ball_y_max))
+ self.ball.hide_frames()
self._test(easter_egg=True)
self.new_bounce = True
self.timeout = gobject.timeout_add(BOUNCE_PAUSE, self._move_ball)
else:
gobject.timeout_add(STEP_PAUSE, self._animate)
- def _switch_cells(self, cells):
- ''' Switch between cells in the animation '''
- self.cells[cells[1]].move(self.cells[cells[0]].get_xy())
- self.cells[cells[0]].move((0, self.height))
- self.frame = cells[1]
-
def add_fraction(self, string):
''' Add a new challenge; set bar to 2x demominator '''
numden = string.split('/', 2)
@@ -610,32 +383,26 @@ class Bounce():
else:
self.label = str(int(self.fraction * 100 + 0.5)) + '%'
self.activity.reset_label(self.label)
- self.ball.set_label(self.label)
+ self.ball.ball.set_label(self.label)
- for bar in self.bars:
- self.bars[bar].set_layer(-1)
- if self.correct > EXPERT: # Show two-segment bar in expert mode
- self.bars[2].set_layer(0)
- self.current_bar = self.bars[2]
+ self.bar.hide_bars()
+ if self.expert: # Show two-segment bar in expert mode
+ self.current_bar = self.bar.get_bar(2)
else:
if self.mode == 'fractions':
nseg = self.challenges[self.n][1]
else:
nseg = 10 # percentages
# generate new bar on demand
- if not nseg in self.bars:
- self.bars[nseg] = Sprite(self.sprites, 0, 0,
- svg_str_to_pixbuf(self._gen_bar(nseg)))
- self.bars[nseg].move((self.bars[2].rect[0],
- self.bars[2].rect[1]))
- self.bars[nseg].set_layer(0)
- self.current_bar = self.bars[nseg]
+ self.current_bar = self.bar.get_bar(nseg)
+ self.current_bar.move((self.bar.bar_x(), self.bar.bar_y()))
+ self.current_bar.set_layer(0)
def _easter_egg_test(self):
''' Test to see if we show the Easter Egg '''
- delta = self.ball.rect[2] / 8
- x = self.ball.get_xy()[0] + self.ball.rect[2] / 2
- f = self.bars[2].rect[2] * self.easter_egg / 100.
+ delta = self.ball.width() / 8
+ x = self.ball.ball_x() + self.ball.width() / 2
+ f = self.bar.width() * self.easter_egg / 100.
if x > f - delta and x < f + delta:
return True
else:
@@ -644,11 +411,11 @@ class Bounce():
def _test(self, easter_egg=False):
''' Test to see if we estimated correctly '''
self.timeout = None
- delta = self.ball.rect[2] / 4
- x = self.ball.get_xy()[0] + self.ball.rect[2] / 2
- f = self.ball.rect[2] / 2 + int(self.fraction * self.bars[2].rect[2])
- self.mark.move((int(f - self.mark.rect[2] / 2),
- self.bars[2].rect[1] - 2))
+ delta = self.ball.width() / 4
+ x = self.ball.ball_x() + self.ball.width() / 2
+ f = self.ball.width() / 2 + int(self.fraction * self.bar.width())
+ self.bar.mark.move((int(f - self.bar.mark_width() / 2),
+ self.bar.bar_y() - 2))
if self.challenges[self.n][2] == 0: # label the column
spr = Sprite(self.sprites, 0, 0, self.blank_graphic)
spr.set_label(self.label)
@@ -672,12 +439,13 @@ class Bounce():
spr.set_layer(-1)
# after enough correct answers, up the difficulty
- if self.correct == len(EASY) * 2:
- for challenge in MEDIUM:
- self.challenges.append(challenge)
- elif self.correct == len(EASY) * 4:
- for challenge in HARD:
- self.challenges.append(challenge)
+ if self.correct == len(self.challenges) * 2:
+ self.challenge += 1
+ if self.challenge < len(CHALLENGES):
+ for challenge in CHALLENGES[self.challenge]:
+ self.challenges.append(challenge)
+ else:
+ self.expert = True
self.count += 1
self.dx = 0. # stop horizontal movement between bounces