[gcompris] mining: fix wrong usage of instance variables



commit f95663f2df7df2f3de8f98932b730cf49fed5a91
Author: Peter Albrecht <pa-dev gmx de>
Date:   Tue Sep 25 14:14:18 2012 +0200

    mining: fix wrong usage of instance variables
    
    Since this is my first python project and I did not read the whole
    python tutorial (shame on me), I made a mistake with strange
    consequences:
    
     1) start GCompris
     2) start the mining activity
     3) collect one nugget with the tutorial enabled
     4) close the mining activity
     5) start the mining activity again
     6) start the tutorial
     7) go through the tutorial
    
    This resulted in a "zoom in" animation, showing no scroll wheel on the
    mouse.
    
    The reason:
    Coming from the java world, I declared all my member variables in the
    class definition. But in python, this does not create instance
    variables, but class object variables (in java terms: static member
    variables). This means two instances, created from the same class, share
    these variables.
    In my case "TutorialMouse.wheel_imgs" has been created at first activity
    start and the corresponding GooCanvas.Items have been destroyed at
    activity end. At the second activity start, the array
    "TutorialMouse.wheel_imgs" still exists, but pointed to non existing
    GooCanvas.Items.
    
    The solution:
    Create and document all instance variables in the corresponding
    __init__() function. Especially: "self.wheel_imgs = []"

 src/mining-activity/mining.py          |  216 ++++++++++++++++++-------------
 src/mining-activity/mining_tutorial.py |  118 ++++++++++--------
 2 files changed, 189 insertions(+), 145 deletions(-)
---
diff --git a/src/mining-activity/mining.py b/src/mining-activity/mining.py
index f868a35..dc19999 100644
--- a/src/mining-activity/mining.py
+++ b/src/mining-activity/mining.py
@@ -40,43 +40,15 @@ from gcompris import gcompris_gettext as _
 class Gcompris_mining:
   """ GCompis Mining-Activity """
 
-  # the number of nuggets, we need to collect in this level
-  nuggets_to_collect = 0
-
-  # the number of nuggets, we already have collected
-  nugget_count = 0
-
-  # used to trigger the creation of a new nugget at next opportunity (only at max zoomed out)
-  need_new_nugget = False
-
-  # used to start new game, after game was won and bonus is displayed
-  is_game_won = False
-
-  # used to avoid input (like scrolling) during game pause
-  __is_game_paused = False
-
   # The factor to shrink the source image with, in order to make it fit on the screen.
   # This has to be larger than 1 (= source image has higher resolution than screen),
   # so the image looks still nice, if we zoom in a bit.
   source_image_scale = 3.0
 
-  # handle to the tutorial object
-  tutorial = None
-
-  # can the tutorial be started in this level?
-  is_tutorial_startable = False
-
-  # has the tutorial been started for this nugget?
-  is_tutorial_enabled = False
-
   # the distance, the mouse cursor has to approach the nugget, triggering the next tutorial step
   # (in 800x520 coordinate space) (should be in sync with the graphics in tutorial.svgz)
   min_nugget_approach = 50.0
 
-  # the position of the mouse pointer, the last time, we saw it (800x520)
-  last_mouse_pos_x = None
-  last_mouse_pos_y = None
-
 
   def __init__(self, gcomprisBoard):
     """ Constructor """
@@ -91,6 +63,40 @@ class Gcompris_mining:
     gcomprisBoard.disable_im_context = True
 
 
+    ##
+    # initialize and document instance variables
+
+    self.nuggets_to_collect = 0
+    """ the number of nuggets, we need to collect in this level """
+
+    self.nugget_count = 0
+    """ the number of nuggets, we already have collected """
+
+    self.need_new_nugget = False
+    """ used to trigger the creation of a new nugget at next opportunity (only at max zoomed out) """
+
+    self.is_game_won = False
+    """ used to start new game, after game was won and bonus is displayed """
+
+    self.__is_game_paused = False
+    """ used to avoid input (like scrolling) during game pause """
+
+    self.tutorial = None
+    """ handle to the tutorial object """
+
+    self.is_tutorial_startable = False
+    """ can the tutorial be started in this level? """
+
+    self.is_tutorial_enabled = False
+    """ has the tutorial been started for this nugget? """
+
+    self.last_mouse_pos_x = None
+    """ the x position of the mouse pointer, the last time, we saw it (800x520) """
+
+    self.last_mouse_pos_y = None
+    """ the y position of the mouse pointer, the last time, we saw it (800x520) """
+
+
   def start(self):
     """ Load data and start the activity """
 
@@ -613,10 +619,6 @@ class Lorry:
 class Placer:
   """ This class randomly places items on the screen and assures, that they do not overlap """
 
-  # the internal list of blocking areas
-  blocking_areas = []
-
-
   def __init__(self, activity):
     """
     Constructor:
@@ -625,6 +627,12 @@ class Placer:
     self.activity = activity
 
 
+    # initialize and document instance variables
+
+    self.blocking_areas = []
+    """ the internal list of blocking areas """
+
+
   def place(self, item, place_callback):
     """
     Place "item" on the screen.
@@ -711,48 +719,49 @@ class Placer:
 class Viewport:
   """ The viewport handles zooming in and out with the appropriate translation """
 
-  # viewport transformation
-  x = 0
-  y = 0
-  scale = 1.0
+  def __init__(self, activity, parent):
+    """
+    Constructor:
+      activity           : the main activity object
+      parent             : the parent GooCanvas item to add our gc_group
+    """
+    # initialize and document instance variables
+
+    self.source_image_scale = activity.source_image_scale
+    """ see documentation in Gcompris_mining """
 
+    self.x = 0
+    """ viewport x translation """
 
-  # zooming
+    self.y = 0
+    """ viewport y translation """
 
-  # The limit to max zoom out, while still filling all the screen with the rockwall.
-  # This value is set up in the constructor.
-  scale_min = None
+    self.scale = 1.0
+    """ current viewport scale / zoom """
 
-  # The limit to max zoom in.
-  # Try to keep scale_max reachable by  scale_min * zoom_factor ^ n  (with n in [1, 2, 3, 4, ...[)
-  # This value is set up in reset()
-  scale_max = None
+    self.scale_min = 1.0 / self.source_image_scale
+    """ The limit to max zoom out, while still filling all the screen with the rockwall. """
 
-  # the factor to zoom on each zoom event
-  # This value is set up in reset()
-  zoom_factor = None
+    self.scale_max = None
+    """
+    The limit to max zoom in.
+    Try to keep scale_max reachable by  scale_min * zoom_factor ^ n  (with n in [1, 2, 3, 4, ...[)
+    This value is set up in reset()
+    """
 
+    self.zoom_factor = None
+    """ The factor to zoom on each zoom event. This value is set up in reset() """
 
-  # The GooCanvas group, which holds everything that is affected by zooming
-  gc_group = None
 
-  # see documentation in Gcompris_mining
-  source_image_scale = None
+    self.gc_group = goocanvas.Group(parent = parent)
+    """ The GooCanvas group, which holds everything that is affected by zooming """
 
 
-  def __init__(self, activity, parent):
-    """
-    Constructor:
-      activity           : the main activity object
-      parent             : the parent GooCanvas item to add our gc_group
-    """
     self.gcomprisBoard = activity.gcomprisBoard
-    self.gc_group = goocanvas.Group(parent = parent)
-    self.gc_group.connect("scroll_event", self.__on_scroll)
     self.cb_zoom_change = activity.on_zoom_change
-    self.source_image_scale = activity.source_image_scale
     self.is_game_paused = activity.is_game_paused
-    self.scale_min = 1.0 / self.source_image_scale
+
+    self.gc_group.connect("scroll_event", self.__on_scroll)
 
     self.nugget_blocker = (
       BlockingArea(0, 0, 800, 42), # top
@@ -946,13 +955,6 @@ class Decorations:
     },
   )
 
-  # A goocanvas group, that holds all our decoration, so we can easily
-  # remove them, by removing only this group.
-  decoration_group = None
-
-  # ID of the decoration type, currently being placed. (Used to overcome callback bounderies)
-  current_decoration_id = None
-
 
   def __init__(self, svghandle, gc_group, placer):
     """
@@ -962,10 +964,22 @@ class Decorations:
       - placer    : reference to the Placer object
     """
     self.svghandle = svghandle
-    self.viewport_gc_group = gc_group
     self.placer = placer
 
 
+    ##
+    # initialize and document instance variables
+
+    self.viewport_gc_group = gc_group
+    """ The viewport's GooCanvas Group to add our decoration_group to """
+
+    self.decoration_group = None
+    """ A goocanvas group, that holds all our decoration, so we can easily remove them, by removing only this group. """
+
+    self.current_decoration_id = None
+    """ ID of the decoration type, currently being placed. (Used to overcome callback bounderies) """
+
+
   def decorate_viewport(self, number_of_decorations):
     """ Fill the viewport with some decorations """
 
@@ -1028,17 +1042,10 @@ class Decorations:
 class Nugget:
   """ The gold nugget """
 
-  # position of the nugget (in the rockwall/gc_group)
-  x = 0.0
-  y = 0.0
-
   # center of the spark in the svg file (used for rotation and positioning)
   pivot_x = 1000
   pivot_y = 800
 
-  # picture of the nugget
-  nugget_img = None
-
 
   def __init__(self, svghandle, parent):
     """
@@ -1047,6 +1054,14 @@ class Nugget:
       parent         : GooCanvas parent item of the gold nugget
     """
 
+    # initialize and document instance variables
+
+    self.x = 0.0
+    """ x position of the nugget (in the rockwall/gc_group) """
+
+    self.y = 0.0
+    """ y position of the nugget (in the rockwall/gc_group) """
+
     self.nugget_img = goocanvas.Svg(
       parent = parent,
       svg_handle = svghandle,
@@ -1055,6 +1070,7 @@ class Nugget:
       # start invisible, since x/y are not set properly yet
       visibility = goocanvas.ITEM_INVISIBLE
       )
+    """ picture of the nugget """
 
 
   def reset(self, nugget, x, y):
@@ -1118,32 +1134,26 @@ class Sparkling:
   and pauses, the time when the spark is hidden.
   """
 
-  # position of the spark (in the rockwall/gc_group)
-  x = 0.0
-  y = 0.0
-
-  # rotation (in degrees)
-  angle = 0
-  rot_delta = 0
+  # value to initialize the rotation delta with
   rot_delta_init = 6
 
-  # size
-  scale = 0
+  # the factor, the spark shrinks every animation step
   scale_factor = 0.90
+
+  # minimum scale factor; if reached, the current spark-phase ends
   scale_min = 0.4
+
+  # the scale factor to start a spark-phase with
   scale_max = 1.0
 
-  # animation
-  timer = None
+  # the time (in milliseconds) between two sparkling animation steps
   timer_milliseconds = 30
 
   # the number of timer-events, a pause lasts
   pause_ticks_total = 25
-  pause_ticks_current = 0
-  pause_tick_variation = 10
 
-  # spark image
-  spark = None
+  # add some randomness to pause_ticks_total
+  pause_tick_variation = 10
 
   # center of the spark in the svg file (used for rotation and positioning)
   pivot_x = 600
@@ -1157,6 +1167,8 @@ class Sparkling:
       parent    : GooCanvas parent item of this spark
     """
 
+    # initialize and document instance variables
+
     self.spark = goocanvas.Svg(
       parent = parent,
       svg_handle = svghandle,
@@ -1165,6 +1177,28 @@ class Sparkling:
       # start invisible, since x/y are not set properly yet
       visibility = goocanvas.ITEM_INVISIBLE
       )
+    """ the spark image in the GooCanvas """
+
+    self.x = 0.0
+    """ x position of the spark (in the rockwall/gc_group) """
+
+    self.y = 0.0
+    """ y position of the spark (in the rockwall/gc_group) """
+
+    self.angle = 0
+    """ rotation (in degrees) """
+
+    self.rot_delta = 0
+    """ the amount to rotate at every animation step """
+
+    self.scale = 0
+    """ the sparks current scale factor """
+
+    self.timer = None
+    """ the timer object, firing timeout-events for our animation """
+
+    self.pause_ticks_current = 0
+    """ counts the number of elapsed pause ticks between two spark-phases """
 
 
   def end(self):
diff --git a/src/mining-activity/mining_tutorial.py b/src/mining-activity/mining_tutorial.py
index dd1c851..f35e95e 100644
--- a/src/mining-activity/mining_tutorial.py
+++ b/src/mining-activity/mining_tutorial.py
@@ -28,10 +28,6 @@ from mining_tools import BlockingArea
 class MiningTutorial:
   """ This class provides tutorial information to the user """
 
-  # the current tutorial state
-  current_state = None
-
-
   def __init__(self, rootitem):
     """
     Constructor
@@ -49,6 +45,9 @@ class MiningTutorial:
     self.cursor = TutorialCursor(self.tutorial_rootitem, svghandle)
     self.touchpad = TutorialTouchpad(self.tutorial_rootitem, svghandle, 500, 440)
 
+    self.current_state = None
+    """ the current tutorial state """
+
 
   def get_blocking_area(self):
     """
@@ -160,14 +159,6 @@ class MiningTutorial:
 class TutorialCursor:
   """ This class demonstrates to move the cursor to a specific position """
 
-  # position of the center of the cursor target in screen coordinates (800 x 520)
-  circle_x = 0.0
-  circle_y = 0.0
-
-  # position of the center of the ghost mouse cursor in screen coordinates (800 x 520)
-  cursor_x = 0.0
-  cursor_y = 0.0
-
   # center of the cursor target in the svg file
   pivot_circle_x = 400.0
   pivot_circle_y = 370.0
@@ -206,6 +197,20 @@ class TutorialCursor:
       pointer_events = goocanvas.EVENTS_NONE
       )
 
+    # initialize and document instance variables
+
+    self.circle_x = 0.0
+    """ x position of the center of the cursor target in screen coordinates (800 x 520) """
+
+    self.circle_y = 0.0
+    """ y position of the center of the cursor target in screen coordinates (800 x 520) """
+
+    self.cursor_x = 0.0
+    """ x position of the center of the ghost mouse cursor in screen coordinates (800 x 520) """
+
+    self.cursor_y = 0.0
+    """ y position of the center of the ghost mouse cursor in screen coordinates (800 x 520) """
+
 
   def start(self, cx, cy, tx, ty):
     """
@@ -278,14 +283,6 @@ class TutorialMouse:
   timer_scroll_milliseconds = 300
   timer_click_milliseconds = 800
 
-  # timer
-  timer_scroll = None
-  timer_click = None
-
-  # position of the center of the mouse in screen coordinates (800 x 520)
-  x = 0.0
-  y = 0.0
-
   # center of the mouse in the svg file
   pivot_mouse_x = 200
   pivot_mouse_y = 220
@@ -318,20 +315,9 @@ class TutorialMouse:
   center_mouse_to_center_button_x = -16
   center_mouse_to_center_button_y = -12
 
-  # the current wheel displayed
-  current_wheel = None
-
-  # define the scroll direction:
-  #   +1: zoom in
-  #   -1: zoom out
-  scroll_direction = None
-
   # the number of different wheels
   number_of_wheels = 3
 
-  # list of mouse wheel images
-  wheel_imgs = []
-
 
   def __init__(self, rootitem, svghandle, x, y):
     """
@@ -341,8 +327,27 @@ class TutorialMouse:
         x, y        : Position of the center of the mouse in screen coordinates (800 x 520)
     """
 
+    self.timer_scroll = None
+    """ timer for scroll animation """
+
+    self.timer_click = None
+    """ timer for click animation """
+
+    self.scroll_direction = None
+    """
+    defines the scroll direction:
+       +1: zoom in
+       -1: zoom out
+    """
+
+    self.wheel_imgs = []
+    """ list of mouse wheel images """
+
     self.x = x
+    """ x position of the center of the mouse in screen coordinates (800 x 520) """
+
     self.y = y
+    """ y position of the center of the mouse in screen coordinates (800 x 520) """
 
     self.mouse_img = goocanvas.Svg(
       parent = rootitem,
@@ -360,6 +365,7 @@ class TutorialMouse:
       pointer_events = goocanvas.EVENTS_NONE
       )
 
+
     # GooCanvas does not support to add SVG-items to other SVG-items, so we have to add
     # the wheels to the rootitem.
 
@@ -388,6 +394,8 @@ class TutorialMouse:
       ))
 
     self.current_wheel = 0
+    """ the current wheel displayed """
+
     self.__update_transformation()
 
 
@@ -568,10 +576,6 @@ class TutorialMouse:
 class TutorialTouchpad:
   """ Displays a touchpad showing the zoom animation """
 
-  # position of the center of the touchpad in screen coordinates (800 x 520)
-  touchpad_x = 0.0
-  touchpad_y = 0.0
-
   # center of the touchpad in the svg file
   pivot_touchpad_x = 400
   pivot_touchpad_y = 220
@@ -594,22 +598,9 @@ class TutorialTouchpad:
   # the time between each zoom animation step, in milliseconds
   zoom_animation_time_step = 100
 
-  # 1: show "1"-finger animation
-  # 2: show "2"-finger animation
-  zoom_number_of_fingers = None
-
-  # zoom "in" or "out"
-  zoom_direction = None
-
   # the finger's movement on the y-axis during one finger animation
   zoom_finger_movement_y = 40
 
-  # one time timer to start the zoom animation again
-  zoom_animation_start_timer = None
-
-  # we remember the handler id to be able to disconnect it again
-  zoom_animation_finished_handler_id = None
-
   # the number of milliseconds one finger click animation lasts (only the lowering part)
   click_animation_time_total = 1000
 
@@ -622,12 +613,6 @@ class TutorialTouchpad:
   # the number of milliseconds, the touch-effect is shown during a click animation
   click_show_effect_milliseconds = 750
 
-  # one time timer to restart the click animation, after showing the touch effect
-  click_animation_show_effect_timer = None
-
-  # we remember the handler id to be able to disconnect it again
-  click_animation_finished_handler_id = None
-
 
   def __init__(self, rootitem, svghandle, x, y):
     """
@@ -638,7 +623,32 @@ class TutorialTouchpad:
     """
 
     self.touchpad_x = x
+    """ x position of the center of the touchpad in screen coordinates (800 x 520) """
+
     self.touchpad_y = y
+    """ y position of the center of the touchpad in screen coordinates (800 x 520) """
+
+    self.zoom_number_of_fingers = None
+    """
+    1: show "1"-finger animation
+    2: show "2"-finger animation
+    """
+
+    self.zoom_direction = None
+    """ zoom "in" or "out" """
+
+    self.zoom_animation_start_timer = None
+    """ one time timer to start the zoom animation again """
+
+    self.zoom_animation_finished_handler_id = None
+    """ we remember the handler id to be able to disconnect it again """
+
+    self.click_animation_show_effect_timer = None
+    """ one time timer to restart the click animation, after showing the touch effect """
+
+    self.click_animation_finished_handler_id = None
+    """ we remember the handler id to be able to disconnect it again """
+
 
     self.touchpad_img = goocanvas.Svg(
       parent = rootitem,



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]