[gcompris] Add random stone decorations for each level
- From: Bruno Coudoin <bcoudoin src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gcompris] Add random stone decorations for each level
- Date: Tue, 25 Sep 2012 22:11:39 +0000 (UTC)
commit 436e3e0e4f27d04dcab90a77b96e59ed5d87a141
Author: Peter Albrecht <pa-dev gmx de>
Date: Fri Sep 7 23:36:37 2012 +0200
Add random stone decorations for each level
The Decorations class adds some random stone decorations to the viewport,
while the Placer class prevents objects (stones / goldnugget) from
overlapping with each other, the outer border or the gcompris bar.
src/mining-activity/mining.py | 251 +++++++++++++++++---
src/mining-activity/resources/mining/rockwall.svgz | Bin 10756 -> 13266 bytes
2 files changed, 215 insertions(+), 36 deletions(-)
---
diff --git a/src/mining-activity/mining.py b/src/mining-activity/mining.py
index f91af10..ff7cf47 100644
--- a/src/mining-activity/mining.py
+++ b/src/mining-activity/mining.py
@@ -114,6 +114,11 @@ class Gcompris_mining:
assert(gcompris.BOARD_WIDTH == (rockwall_img.get_bounds().x2 / self.source_image_scale))
assert(gcompris.BOARD_HEIGHT == (rockwall_img.get_bounds().y2 / self.source_image_scale))
+
+ self.placer = Placer(self)
+
+ self.decorations = Decorations(svghandle, self.viewport.get_gc_group(), self.placer)
+
self.nugget = Nugget(svghandle, self.viewport.get_gc_group())
# create sparkling last, so it is on above the nugget
@@ -143,51 +148,23 @@ class Gcompris_mining:
self.need_new_nugget = False
# TODO: set level-function:
- # generate nice level with random stones, bones, ...
- # and place gold nuggest according to no stone/bone bounding boxes
# perhaps different backgrounds?
self.viewport.reset()
- self.place_new_nugget()
-
-
- def do_objects_collide(self, primary_object, *secondary_objects):
- """ Tests whether any object of the tuple secondary_objects collides with the primary_object """
+ self.placer.add_blocker(self.gc_bar_blocker)
+ for blocking_area in self.viewport.get_nugget_blocker():
+ self.placer.add_blocker(blocking_area)
- area_p = Area(primary_object.get_bounds())
-
- for secondary_object in secondary_objects:
- area_s = Area(secondary_object.get_bounds())
-
- # collision on x-axis?
- if math.fabs(area_p.center_x - area_s.center_x) <= (area_s.width + area_p.width) / 2.0:
- # collision on y-axis?
- if math.fabs(area_p.center_y - area_s.center_y) <= (area_s.height + area_p.height) / 2.0:
- # collision!
- return True
+ self.decorations.decorate_viewport(10)
- # no collision
- return False
+ self.place_new_nugget()
def place_new_nugget(self):
""" Place a new nugget to collect on the rockwall """
- nugget_area = Area(self.nugget.get_bounds())
- nugget_width_half = int(nugget_area.width / 2.0)
- nugget_height_half = int(nugget_area.height / 2.0)
-
- while True:
- x = random.randrange(nugget_width_half, gcompris.BOARD_WIDTH - nugget_width_half) * self.source_image_scale
- y = random.randrange(nugget_height_half, gcompris.BOARD_HEIGHT - nugget_height_half) * self.source_image_scale
-
- self.nugget.reset(x, y)
-
- # TODO: check for stones
- if not self.do_objects_collide(self.nugget, self.gc_bar_blocker, *self.viewport.get_nugget_blocker()):
- # we found a valid position without collisions
- break
+ self.placer.place(self.nugget, self.nugget.reset)
(x, y) = self.nugget.get_sparkling_coordinates()
self.sparkling.reset(x, y)
@@ -249,6 +226,7 @@ class Gcompris_mining:
def collect_nugget(self):
""" The nugget was clicked, so collect it """
+ self.placer.remove_blocker(self.nugget)
self.nugget_count += 1
self.sparkling.animation_stop()
self.nugget.hide()
@@ -301,6 +279,8 @@ class Gcompris_mining:
def end_level(self):
""" Terminate the current level """
self.sparkling.end()
+ self.placer.remove_all_blocker()
+ self.decorations.cleanup_viewport()
def end(self):
@@ -333,6 +313,89 @@ class Gcompris_mining:
+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:
+ activity : the main activity class
+ """
+ self.activity = activity
+
+
+ def place(self, item, place_callback):
+ """
+ Place "item" on the screen.
+ item : the item to place (needs to implement "get_bounds()")
+ place_callback : The callback function to actually place the item (and modify, like rotate/scale).
+ Is called with parameters (item, x, y).
+ """
+ area = Area(item.get_bounds())
+ width_half = int(area.width / 2.0)
+ height_half = int(area.height / 2.0)
+
+ while True:
+ # get new random position for the item
+ x = random.randrange(width_half, gcompris.BOARD_WIDTH - width_half) * self.activity.source_image_scale
+ y = random.randrange(height_half, gcompris.BOARD_HEIGHT - height_half) * self.activity.source_image_scale
+
+ # place the item to this position
+ place_callback(item, x, y)
+
+ # check for overlapping objects
+ if not self.__does_object_collide_with_registered_ones(item):
+ # we found a valid position without collisions
+ # lets remember the positioned item...
+ self.add_blocker(item);
+ # ... and end the search for a valid position
+ break
+
+
+ def add_blocker(self, blocking_area):
+ """ Add a new blocking area to the internal list of blocking areas """
+ self.blocking_areas.append(blocking_area)
+
+
+ def remove_blocker(self, blocking_area):
+ """ Removes the given blocking area from the internal list of blocking areas """
+ for i in range(len(self.blocking_areas)):
+ if self.blocking_areas[i] == blocking_area:
+ # this is the blocking_area, we are looking for, so remove it from the list
+ self.blocking_areas.pop(i)
+ return
+
+ print("Warning: blocking-area not in list: " + str(blocking_area))
+
+
+ def remove_all_blocker(self):
+ """ Removes all blocker from the internal list """
+ self.blocking_areas = []
+
+
+ def __does_object_collide_with_registered_ones(self, asked_object):
+ """ Tests whether any registered object collides with the asked_object """
+ area_a = Area(asked_object.get_bounds())
+
+ for blocking_area in self.blocking_areas:
+ area_r = Area(blocking_area.get_bounds())
+
+ # collision on x-axis?
+ if math.fabs(area_a.center_x - area_r.center_x) <= (area_r.width + area_a.width) / 2.0:
+ # collision on y-axis?
+ if math.fabs(area_a.center_y - area_r.center_y) <= (area_r.height + area_a.height) / 2.0:
+ # collision!
+ return True
+
+ # no collision
+ return False
+
+
+
class Viewport:
""" The viewport handles zooming in and out with the appropriate translation """
@@ -518,6 +581,116 @@ class Viewport:
+class Decorations:
+ """
+ This class handles decorations, like stones. They have the meaning of:
+ - make every level look a bit different
+ - help orienting, while scrolling
+ """
+
+ # our decoration types in the svg file
+ decoration_types = (
+ {
+ 'svg_id': '#STONE1',
+ 'svg_x': 500,
+ 'svg_y': 1300
+ },
+ {
+ 'svg_id': '#STONE2',
+ 'svg_x': 1000,
+ 'svg_y': 1300
+ },
+ {
+ 'svg_id': '#STONE3',
+ 'svg_x': 1500,
+ 'svg_y': 1300
+ },
+ {
+ 'svg_id': '#STONE4',
+ 'svg_x': 2000,
+ 'svg_y': 1300
+ },
+ )
+
+ # 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):
+ """
+ Constructor:
+ - svghandle : handle to the svg file, to load the decoration pictures
+ - gc_group : our viewport's gc_group, the decorations are attached to
+ - placer : reference to the Placer object
+ """
+ self.svghandle = svghandle
+ self.viewport_gc_group = gc_group
+ self.placer = placer
+
+
+ def decorate_viewport(self, number_of_decorations):
+ """ Fill the viewport with some decorations """
+
+ assert(self.decoration_group == None)
+ self.decoration_group = goocanvas.Group(parent = self.viewport_gc_group)
+
+ for i in range(number_of_decorations):
+ # select random decoration
+ self.current_decoration_id = random.randrange(4)
+ svg_id = self.decoration_types[self.current_decoration_id]['svg_id']
+
+ # create decoration
+ decoration = goocanvas.Svg(
+ parent = self.decoration_group,
+ svg_handle = self.svghandle,
+ svg_id = svg_id,
+ )
+
+ self.placer.place(decoration, self.__place_decoration)
+
+
+ def __place_decoration(self, decoration, x, y):
+ """ Updates the transformation of the decoration to the new coordinates. Rotation and scale are varied. """
+
+ svg_x = self.decoration_types[self.current_decoration_id]['svg_x']
+ svg_y = self.decoration_types[self.current_decoration_id]['svg_y']
+
+
+ # scale between 0.5 and 2.0
+ scale = math.pow(1.2, random.randrange(-4, +4))
+
+ rot = random.randrange(-20, +20)
+
+
+ # we need those values more than once, so lets remember them
+ a = math.radians(rot)
+ cos_a = math.cos(a)
+ sin_a = math.sin(a)
+
+ # create the transformation matrices
+ m_center_to_origin = cairo.Matrix(1, 0, 0, 1, -svg_x, -svg_y)
+ m_scale = cairo.Matrix(scale, 0, 0, scale, 0, 0)
+ m_rotate = cairo.Matrix(cos_a, sin_a, -sin_a, cos_a, 0, 0)
+ m_to_destination = cairo.Matrix(1, 0, 0, 1, x, y)
+
+ # combine all transformation matrices to one
+ matrix = m_center_to_origin * m_scale * m_rotate * m_to_destination
+
+ decoration.set_transform(matrix)
+
+
+ def cleanup_viewport(self):
+ """ Remove all decorations from the viewport """
+ if self.decoration_group != None:
+ self.decoration_group.remove()
+ self.decoration_group = None
+
+
+
class Nugget:
""" The gold nugget """
@@ -550,8 +723,14 @@ class Nugget:
)
- def reset(self, x, y):
- """ Move nugget to a new position. """
+ def reset(self, nugget, x, y):
+ """
+ Move nugget to a new position.
+ nugget : we don't need it in this case, since there is only one nugget image in this class,
+ but the callback interface defines this parameter
+ x : new x position for the nugget image
+ y : new y position for the nugget image
+ """
self.x = x
self.y = y
self.nugget_img.set_simple_transform(self.x - self.pivot_x, self.y - self.pivot_y, 1.0, 0)
diff --git a/src/mining-activity/resources/mining/rockwall.svgz b/src/mining-activity/resources/mining/rockwall.svgz
index 7ea0bf2..dfd8ef4 100644
Binary files a/src/mining-activity/resources/mining/rockwall.svgz and b/src/mining-activity/resources/mining/rockwall.svgz differ
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]