Beispiel #1
0
def get_angle_container(item):
    x, y = item.center
    if item.isParent:
        if len(item.children_refs) > 0:
            x_total = 0
            y_total = 0
            for child in item.children_refs:
                child = child()
                x_total += child.center_x
                y_total += child.center_y

            x_moy = x_total / len(item.children_refs)
            y_moy = y_total / len(item.children_refs)

            v1 = Vector(x - x_moy, y - y_moy)

            angle = v1.angle((-1, 0))
            angle = angle - 90
        else:
            angle = 0
    elif hasattr(item, 'parent_node') and item.parent_node != None:
        x0, y0 = item.parent_node().center
        v1 = Vector(x0 - x, y0 - y)
        angle = v1.angle((-1, 0))
        angle += 90
    return angle
Beispiel #2
0
    def On_Rotate(self, touch) -> None:
        """ handles the rotation event """

        if Globals.oTheScreen.GuiIsBlocked():
            return

        if not self.bInit:
            self.xx = self.x
            self.yy = self.y
            self.bInit = True

        points = [Vector(self._last_touch_pos[t]) for t in self._touches]
        if len(points) == 0:
            # LogError(u'cRotateScatter: On_Rotate shouldnt get called')
            return

        anchor = Vector(self.xx + self.width / 2, self.yy + self.height / 2)
        farthest = max(points, key=anchor.distance)
        if points.index(farthest) != self._touches.index(touch):
            return

        old_line = Vector(*touch.ppos) - anchor
        new_line = Vector(*touch.pos) - anchor

        iRad = radians(new_line.angle(old_line)) * self.do_rotation
        self.SetValueSub(iRad)

        self.dispatch('on_widget_turned')
Beispiel #3
0
    def transform_with_touch(self, touch):
        # just do a simple one finger drag
        changed = False
        if len(self._touches) == self.translation_touches:
            # _last_touch_pos has last pos in correct parent space,
            # just like incoming touch
            dx = (touch.x - self._last_touch_pos[touch][0]) \
                 * self.do_translation_x
            dy = (touch.y - self._last_touch_pos[touch][1]) \
                 * self.do_translation_y
            dx = dx / self.translation_touches
            dy = dy / self.translation_touches
            self.apply_transform(Matrix().translate(dx, dy, 0))
            changed = True

        if len(self._touches) == 1:
            return changed

        # we have more than one touch... list of last known pos
        points = [
            Vector(self._last_touch_pos[t]) for t in self._touches
            if t is not touch
        ]
        # add current touch last
        points.append(Vector(touch.pos))

        # we only want to transform if the touch is part of the two touches
        # farthest apart! So first we find anchor, the point to transform
        # around as another touch farthest away from current touch's pos
        anchor = max(points[:-1], key=lambda p: p.distance(touch.pos))

        # now we find the touch farthest away from anchor, if its not the
        # same as touch. Touch is not one of the two touches used to transform
        farthest = max(points, key=anchor.distance)
        if farthest is not points[-1]:
            return changed

        # ok, so we have touch, and anchor, so we can actually compute the
        # transformation
        old_line = Vector(*touch.ppos) - anchor
        new_line = Vector(*touch.pos) - anchor
        if not old_line.length():  # div by zero
            return changed

        angle = radians(new_line.angle(old_line)) * self.do_rotation
        if angle:
            changed = True
        self.apply_transform(Matrix().rotate(angle, 0, 0, 1), anchor=anchor)

        if self.do_scale:
            scale = new_line.length() / old_line.length()
            new_scale = scale * self.scale
            if new_scale < self.scale_min:
                scale = self.scale_min / self.scale
            elif new_scale > self.scale_max:
                scale = self.scale_max / self.scale
            self.apply_transform(Matrix().scale(scale, scale, scale),
                                 anchor=anchor)
            changed = True
        return changed
Beispiel #4
0
    def update_widget_graphics(self, *l):
        if not self.activated:
            return
        if self.widget is None:
            self.grect.size = 0, 0
            return
        gr = self.grect
        widget = self.widget

        # determine rotation
        a = Vector(1, 0)
        if widget is self.win:
            b = Vector(widget.to_window(0, 0))
            c = Vector(widget.to_window(1, 0))
        else:
            b = Vector(widget.to_window(*widget.to_parent(0, 0)))
            c = Vector(widget.to_window(*widget.to_parent(1, 0))) - b
        angle = -a.angle(c)

        # determine scale
        scale = c.length()

        # apply transform
        gr.size = widget.size
        if widget is self.win:
            self.gtranslate.xy = Vector(widget.to_window(0, 0))
        else:
            self.gtranslate.xy = Vector(widget.to_window(*widget.pos))
        self.grotate.angle = angle
        # fix warning about scale property deprecation
        self.gscale.xyz = (scale, ) * 3
Beispiel #5
0
    def on_touch_move(self, touch):
        if touch.grab_current is not self.transform:
            return
        touch_point_in_parent = self.transform.to_parent(*touch.pos)

        if len(self.touches) == 1 and self.do_translation:
            ptx, pty = self.transform.pos
            px0, py0 = self.transform.to_parent(touch.px, touch.py)
            px1, py1 = touch_point_in_parent
            pdx, pdy = px1 - px0, py1 - py0
            self.transform.pos = ptx + pdx, pty + pdy
        else:
            touch_point = Vector(touch_point_in_parent)
            points = [self.prev_pos[t] for t in self.touches]
            pivot = max(points, key=touch_point.distance)
            farthest = max(points, key=pivot.distance)
            if points.index(farthest) == self.touches.index(touch):
                old_line = Vector(self.transform.to_parent(*touch.ppos)) - pivot
                new_line = Vector(touch_point_in_parent) - pivot

                vx, vy = self.transform.viewport_pos
                local_pivot = self.transform.to_local(*pivot)
                self.transform.viewport_pos = vx-local_pivot[0], vy-local_pivot[1]

                if self.do_rotation:
                    self.transform.do_rotate(radians(new_line.angle(old_line)))
                if self.do_scale:
                    ratio = new_line.length() / old_line.length()
                    self.transform.do_scale(ratio, ratio)
                self.transform.viewport_pos = vx, vy

        self.prev_pos[touch] = Vector(touch_point_in_parent)
Beispiel #6
0
    def update_widget_graphics(self, *l):
        if not self.activated:
            return
        if self.widget is None:
            self.grect.size = 0, 0
            return
        gr = self.grect
        widget = self.widget

        # determine rotation
        a = Vector(1, 0)
        if widget is self.win:
            b = Vector(widget.to_window(0, 0))
            c = Vector(widget.to_window(1, 0))
        else:
            b = Vector(widget.to_window(*widget.to_parent(0, 0)))
            c = Vector(widget.to_window(*widget.to_parent(1, 0))) - b
        angle = -a.angle(c)

        # determine scale
        scale = c.length()

        # apply transform
        gr.size = widget.size
        if widget is self.win:
            self.gtranslate.xy = Vector(widget.to_window(0, 0))
        else:
            self.gtranslate.xy = Vector(widget.to_window(*widget.pos))
        self.grotate.angle = angle
        # fix warning about scale property deprecation
        self.gscale.xyz = (scale,) * 3
Beispiel #7
0
    def transform_with_touch(self, touch):
        # just do a simple one finger drag
        changed = False
        if len(self._touches) == self.translation_touches:
            # _last_touch_pos has last pos in correct parent space,
            # just like incoming touch
            dx = (touch.x - self._last_touch_pos[touch][0]) \
                * self.do_translation_x
            dy = (touch.y - self._last_touch_pos[touch][1]) \
                * self.do_translation_y
            dx = dx / self.translation_touches
            dy = dy / self.translation_touches
            self.apply_transform(Matrix().translate(dx, dy, 0))
            changed = True

        if len(self._touches) == 1:
            return changed

        # we have more than one touch... list of last known pos
        points = [Vector(self._last_touch_pos[t]) for t in self._touches
                  if t is not touch]
        # add current touch last
        points.append(Vector(touch.pos))

        # we only want to transform if the touch is part of the two touches
        # farthest apart! So first we find anchor, the point to transform
        # around as another touch farthest away from current touch's pos
        anchor = max(points[:-1], key=lambda p: p.distance(touch.pos))

        # now we find the touch farthest away from anchor, if its not the
        # same as touch. Touch is not one of the two touches used to transform
        farthest = max(points, key=anchor.distance)
        if farthest is not points[-1]:
            return changed

        # ok, so we have touch, and anchor, so we can actually compute the
        # transformation
        old_line = Vector(*touch.ppos) - anchor
        new_line = Vector(*touch.pos) - anchor
        if not old_line.length():   # div by zero
            return changed

        angle = radians(new_line.angle(old_line)) * self.do_rotation
        if angle:
            changed = True
        self.apply_transform(Matrix().rotate(angle, 0, 0, 1), anchor=anchor)

        if self.do_scale:
            scale = new_line.length() / old_line.length()
            new_scale = scale * self.scale
            if new_scale < self.scale_min:
                scale = self.scale_min / self.scale
            elif new_scale > self.scale_max:
                scale = self.scale_max / self.scale
            self.apply_transform(Matrix().scale(scale, scale, scale),
                                 anchor=anchor)
            changed = True
        return changed
Beispiel #8
0
    def check_deflector_collision(self, deflector):
        # Here we have a collision Bullet <--> Deflector-bounding-box. But that doesn't mean
        # that there's a collision with the deflector LINE yet. So here's some math stuff
        # for the freaks :) It includes vector calculations, distance problems and trigonometry

        # first thing to do is: we need a vector describing the bullet. Length isn't important.
        bullet_position = Vector(self.center)
        bullet_direction = Vector(1, 0).rotate(self.angle * 360 / (2 * pi))
        deflector_point1 = Vector(
            deflector.to_parent(deflector.point1.center[0],
                                deflector.point1.center[1]))
        deflector_point2 = Vector(
            deflector.to_parent(deflector.point2.center[0],
                                deflector.point2.center[1]))

        # then we need a vector describing the deflector line.
        deflector_vector = Vector(deflector_point2 - deflector_point1)

        # now we do a line intersection with the deflector line:
        intersection = Vector.line_intersection(
            bullet_position, bullet_position + bullet_direction,
            deflector_point1, deflector_point2)

        # now we want to proof if the bullet comes from the 'right' side.
        # Because it's possible that the bullet is colliding with the deflectors bounding box but
        # would miss / has already missed the deflector line.
        # We do that by checking if the expected intersection point is BEHIND the bullet position.
        # ('behind' means the bullets direction vector points AWAY from the vector
        # [bullet -> intersection]. That also means the angle between these two vectors is not 0
        # -> due to some math-engine-internal inaccuracies, i have to check if the angle is greater than one:
        if abs(bullet_direction.angle(intersection - bullet_position)) > 1:
            # if the bullet missed the line already - NO COLLISION
            return False

        # now we finally check if the bullet is close enough to the deflector line:
        distance = abs(
            sin(radians(bullet_direction.angle(deflector_vector)) %
                (pi / 2))) * Vector(intersection - bullet_position).length()
        if distance < (self.width / 2):
            # there is a collision!
            # kill the animation!
            self.animation.unbind(on_complete=self.on_collision_with_edge)
            self.animation.stop(self)
            # call the collision handler
            self.on_collision_with_deflector(deflector, deflector_vector)
Beispiel #9
0
 def check_deflector_collision(self, deflector):
     # Here we have a collision Bullet <--> Deflector-bounding-box. But that doesn't mean
     # that there's a collision with the deflector LINE yet. So here's some math stuff
     # for the freaks :) It includes vector calculations, distance problems and trigonometry
     
     # first thing to do is: we need a vector describing the bullet. Length isn't important.
     bullet_position = Vector(self.center)
     bullet_direction = Vector(1, 0).rotate(self.angle * 360 / (2*pi))
     deflector_point1 = Vector(deflector.to_parent(deflector.point1.center[0], deflector.point1.center[1]))
     deflector_point2 = Vector(deflector.to_parent(deflector.point2.center[0], deflector.point2.center[1]))
     
     # then we need a vector describing the deflector line.
     deflector_vector = Vector(deflector_point2 - deflector_point1)
     
     # now we do a line intersection with the deflector line:
     intersection = Vector.line_intersection(bullet_position, bullet_position + bullet_direction, deflector_point1, deflector_point2)
     
     # now we want to proof if the bullet comes from the 'right' side.
     # Because it's possible that the bullet is colliding with the deflectors bounding box but
     # would miss / has already missed the deflector line.
     # We do that by checking if the expected intersection point is BEHIND the bullet position.
     # ('behind' means the bullets direction vector points AWAY from the vector 
     # [bullet -> intersection]. That also means the angle between these two vectors is not 0
     # -> due to some math-engine-internal inaccuracies, i have to check if the angle is greater than one:
     if abs(bullet_direction.angle(intersection - bullet_position)) > 1:
         # if the bullet missed the line already - NO COLLISION
         return False
     
     # now we finally check if the bullet is close enough to the deflector line:
     distance = abs(sin(radians(bullet_direction.angle(deflector_vector)) % (pi/2))) * Vector(intersection - bullet_position).length()
     if distance < (self.width / 2):
         # there is a collision!
         # kill the animation!
         self.animation.unbind(on_complete=self.on_collision_with_edge)
         self.animation.stop(self)
         # call the collision handler
         self.on_collision_with_deflector(deflector, deflector_vector)
Beispiel #10
0
 def get_rigid_rotation(self, dstpts):
     '''
     Extract the rotation to apply to a group of points to minimize the
     distance to a second group of points. The two groups of points are
     assumed to be centered. This is a simple version that just pick
     an angle based on the first point of the gesture.
     '''
     if len(self.strokes) < 1 or len(self.strokes[0].points) < 1:
         return 0
     if len(dstpts.strokes) < 1 or len(dstpts.strokes[0].points) < 1:
         return 0
     p = dstpts.strokes[0].points[0]
     target = Vector([p.x, p.y])
     source = Vector([p.x, p.y])
     return source.angle(target)
Beispiel #11
0
 def get_rigid_rotation(self, dstpts):
     '''
     Extract the rotation to apply to a group of points to minimize the
     distance to a second group of points. The two groups of points are
     assumed to be centered. This is a simple version that just pick
     an angle based on the first point of the gesture.
     '''
     if len(self.strokes) < 1 or len(self.strokes[0].points) < 1:
         return 0
     if len(dstpts.strokes) < 1 or len(dstpts.strokes[0].points) < 1:
         return 0
     p = dstpts.strokes[0].points[0]
     target = Vector([p.x, p.y])
     source = Vector([p.x, p.y])
     return source.angle(target)
Beispiel #12
0
    def setup_mode_free(self):
        """Setup the keyboard in free mode.

        Free mode is designed to let the user control the position and
        orientation of the keyboard. The only real usage is for a multiuser
        environment, but you might found other ways to use it.
        If a :data:`target` is set, it will place the vkeyboard under the
        target.

        .. note::
            Don't call this method directly, use :meth:`setup_mode` instead.
        """
        self.do_translation = True
        self.do_rotation = True
        self.do_scale = True
        target = self.target
        if not target:
            return

        # NOTE all math will be done in window point of view
        # determine rotation of the target
        a = Vector(1, 0)
        b = Vector(target.to_window(0, 0))
        c = Vector(target.to_window(1, 0)) - b
        self.rotation = -a.angle(c)

        # determine the position of center/top of the keyboard
        dpos = Vector(self.to_window(self.width / 2.0, self.height))

        # determine the position of center/bottom of the target
        cpos = Vector(target.to_window(target.center_x, target.y))

        # the goal now is to map both point, calculate the diff between them
        diff = dpos - cpos

        # we still have an issue, self.pos represent the bounding box, not the
        # 0,0 coordinate of the scatter. we need to apply also the diff between
        # them (inside and outside coordinate matrix). It's hard to explain, but
        # do a scheme on a paper, wrote all the vector i'm calculating, and
        # you'll understand. :)
        diff2 = Vector(self.x + self.width / 2.0, self.y + self.height) - Vector(
            self.to_parent(self.width / 2.0, self.height)
        )
        diff -= diff2

        # now we have a good "diff", set it as a pos.
        self.pos = -diff
Beispiel #13
0
    def setup_mode_free(self):
        '''Setup the keyboard in free mode.

        Free mode is designed to let the user control the position and
        orientation of the keyboard. The only real usage is for a multiuser
        environment, but you might found other ways to use it.
        If a :attr:`target` is set, it will place the vkeyboard under the
        target.

        .. note::
            Don't call this method directly, use :meth:`setup_mode` instead.
        '''
        self.do_translation = True
        self.do_rotation = True
        self.do_scale = True
        target = self.target
        if not target:
            return

        # NOTE all math will be done in window point of view
        # determine rotation of the target
        a = Vector(1, 0)
        b = Vector(target.to_window(0, 0))
        c = Vector(target.to_window(1, 0)) - b
        self.rotation = -a.angle(c)

        # determine the position of center/top of the keyboard
        dpos = Vector(self.to_window(self.width / 2., self.height))

        # determine the position of center/bottom of the target
        cpos = Vector(target.to_window(target.center_x, target.y))

        # the goal now is to map both point, calculate the diff between them
        diff = dpos - cpos

        # we still have an issue, self.pos represent the bounding box,
        # not the 0,0 coordinate of the scatter. we need to apply also
        # the diff between them (inside and outside coordinate matrix).
        # It's hard to explain, but do a scheme on a paper, write all
        # the vector i'm calculating, and you'll understand. :)
        diff2 = Vector(self.x + self.width / 2., self.y + self.height) - \
            Vector(self.to_parent(self.width / 2., self.height))
        diff -= diff2

        # now we have a good "diff", set it as a pos.
        self.pos = -diff
Beispiel #14
0
    def highlight_at(self, *largs):
        '''A function to highlight the current self.widget'''
        gr = self.grect
        widget = self.widget
        # determine rotation
        a = Vector(1, 0)
        b = Vector(widget.to_window(*widget.to_parent(0, 0)))
        c = Vector(widget.to_window(*widget.to_parent(1, 0))) - b
        angle = -a.angle(c)

        # determine scale
        scale = c.length()

        # apply transform
        gr.size = widget.size
        self.gtranslate.xy = Vector(widget.to_window(*widget.pos))
        self.grotate.angle = angle
        self.gscale.scale = scale
Beispiel #15
0
    def transform_with_touch(self, touch):
        # just do a simple one finger drag
        if len(self._touches) == 1:
            # _last_touch_pos has last pos in correct parent space,
            # just like incoming touch
            dx = (touch.x - self._last_touch_pos[touch][0]) \
                    * self.do_translation_x
            dy = (touch.y - self._last_touch_pos[touch][1]) \
                    * self.do_translation_y
            self.apply_transform(Matrix().translate(dx, dy, 0))
            return

        # we have more than one touch...
        points = [Vector(self._last_touch_pos[t]) for t in self._touches]

        # we only want to transform if the touch is part of the two touches
        # furthest apart! So first we find anchor, the point to transform
        # around as the touch farthest away from touch
        anchor = max(points, key=lambda p: p.distance(touch.pos))

        # now we find the touch farthest away from anchor, if its not the
        # same as touch. Touch is not one of the two touches used to transform
        farthest = max(points, key=anchor.distance)
        if points.index(farthest) != self._touches.index(touch):
            return

        # ok, so we have touch, and anchor, so we can actually compute the
        # transformation
        old_line = Vector(*touch.ppos) - anchor
        new_line = Vector(*touch.pos) - anchor

        angle = radians(new_line.angle(old_line)) * self.do_rotation
        self.apply_transform(Matrix().rotate(angle, 0, 0, 1), anchor=anchor)

        if self.do_scale:
            scale = new_line.length() / old_line.length()
            new_scale = scale * self.scale
            if new_scale < self.scale_min or new_scale > self.scale_max:
                scale = 1.0
            self.apply_transform(Matrix().scale(scale, scale, scale),
                                 anchor=anchor)
Beispiel #16
0
    def transform_with_touch(self, touch):
        # just do a simple one finger drag
        if len(self._touches) == 1:
            # _last_touch_pos has last pos in correct parent space,
            # just like incoming touch
            dx = (touch.x - self._last_touch_pos[touch][0]) \
                    * self.do_translation_x
            dy = (touch.y - self._last_touch_pos[touch][1]) \
                    * self.do_translation_y
            self.apply_transform(Matrix().translate(dx, dy, 0))
            return

        # we have more than one touch...
        points = [Vector(self._last_touch_pos[t]) for t in self._touches]

        # we only want to transform if the touch is part of the two touches
        # furthest apart! So first we find anchor, the point to transform
        # around as the touch farthest away from touch
        anchor = max(points, key=lambda p: p.distance(touch.pos))

        # now we find the touch farthest away from anchor, if its not the
        # same as touch. Touch is not one of the two touches used to transform
        farthest = max(points, key=anchor.distance)
        if points.index(farthest) != self._touches.index(touch):
            return

        # ok, so we have touch, and anchor, so we can actually compute the
        # transformation
        old_line = Vector(*touch.ppos) - anchor
        new_line = Vector(*touch.pos) - anchor

        angle = radians(new_line.angle(old_line)) * self.do_rotation
        self.apply_transform(Matrix().rotate(angle, 0, 0, 1), anchor=anchor)

        if self.do_scale:
            scale = new_line.length() / old_line.length()
            new_scale = scale * self.scale
            if new_scale < self.scale_min or new_scale > self.scale_max:
                scale = 1.0
            self.apply_transform(Matrix().scale(scale, scale, scale),
                                 anchor=anchor)
Beispiel #17
0
 def on_touch_move(self, touch):
     if (self._MarkedMoveDirection == None):
         self._MarkedMoveDirection = Vector(touch.px - touch.x, touch.py - touch.y)
         return
     
     # Whats the current move direction
     currentMoveDir = Vector(touch.px - touch.x, touch.py - touch.y)
     
     # Rotation between this vector and our marked
     angleBetween = currentMoveDir.angle(self._MarkedMoveDirection)
     if (angleBetween >= 90 or angleBetween <= -90):
         # Do things
         self._MarkedMoveDirection = currentMoveDir
         
         self._CatPettingCounter += 1
         
         if (self._CatPettingCounter >= 7):
             # Perform pet
             self._CatPettingCounter = 0
             self.cat_label = "Hapiness+"
             self._LabelPulse = .5
             self.Hapiness += 1
Beispiel #18
0
    def update_widget_graphics(self, *l):
        if not self.activated:
            return
        if self.widget is None:
            self.grect.size = 0, 0
            return
        gr = self.grect
        widget = self.widget

        # determine rotation
        a = Vector(1, 0)
        b = Vector(widget.to_window(*widget.to_parent(0, 0)))
        c = Vector(widget.to_window(*widget.to_parent(1, 0))) - b
        angle = -a.angle(c)

        # determine scale
        scale = c.length()

        # apply transform
        gr.size = widget.size
        self.gtranslate.xy = Vector(widget.to_window(*widget.pos))
        self.grotate.angle = angle
        self.gscale.scale = scale
Beispiel #19
0
    def On_Rotate(self, touch):
        ''' handles the rotation event '''
        if not self.bInit:
            self.xx=self.x
            self.yy=self.y
            self.bInit=True

        points = [Vector(self._last_touch_pos[t]) for t in self._touches]
        if len(points)==0:
            # LogError(u'cRotateScatter: On_Rotate shouldnt get called')
            return

        anchor= Vector(self.xx+self.width/2,self.yy+self.height/2)
        farthest = max(points, key=anchor.distance)
        if points.index(farthest) != self._touches.index(touch):
            return

        old_line = Vector(*touch.ppos) - anchor
        new_line = Vector(*touch.pos) - anchor

        iRad = radians(new_line.angle(old_line)) * self.do_rotation
        self.SetValueSub(iRad)

        self.dispatch('on_widget_turned')
class Eyes(Scatter):
    active = BooleanProperty(False)
    alive = BooleanProperty(True)
    navigating = BooleanProperty(False)

    # Max level 8
    obese_lvl = BoundedNumericProperty(1, min=0, max=8)

    def __init__(self,
                 image="images/eyes_normal.png",
                 box=[0, 0, 100, 100],
                 **kwargs):
        self.direction = Vector(-1, 0)
        self.angle = 5

        self.size = (700, 700)
        self.box = box
        self.center = (Window.width / 2, Window.height)
        self.image = Image(source=image, allow_stretch=True, size=self.size)

        self.image.texture = self.image.texture.get_region(0, 0, 316, 168)

        self.target_pos = self.center

        super(Eyes, self).__init__(**kwargs)
        self.add_widget(self.image)

        self.register_event_type('on_death')

        # Every living creature consumes own self
        #        self.bind(active=lambda instance, value: Clock.schedule_interval(instance.consume_calories, 0.5) if value else Clock.unschedule(instance.consume_calories))
        # Dynamic entry
        self.bind(active=lambda instance, value: Animation(
            y=Window.height - 520, t="out_back", d=1.2).start(instance)
                  if value else True)
        # Too many calories make you obese
#        self.bind(total_calories=self.lvlup)

    def swim(self, dt):
        anim = Animation(center=self.target_pos, d=0.1)
        anim.start(self)

    def on_death(self):
        self.alive = False
        self.active = False

    def on_touch_down(self, touch):
        if not self.collide_point(touch.x, touch.y):
            return False
        if self.active and self.alive:
            Clock.schedule_interval(self.swim, 0.1)
            self.navigating = True

    def on_touch_move(self, touch):
        if not self.alive:
            return False

        # Bounding box
        x = touch.x
        if touch.x >= self.box[2]:
            x = self.box[2]
        elif touch.x <= self.box[0]:
            x = self.box[0]

        y = touch.y
        if touch.y >= self.box[3]:
            y = self.box[3]
        elif touch.y <= self.box[1]:
            y = self.box[1]

        self.target_pos = (x, y)

    def on_touch_up(self, touch):
        if not self.navigating:
            return False

        self.navigating = False

        Clock.unschedule(self.swim)

        speed = Vector((0, 0)).distance((touch.dsx, touch.dsy)) * 5000

        angle = self.direction.angle((touch.dsx, touch.dsy))
        if angle < 0:
            angle = 360 + angle
        angle = 270 - angle

        anim = Animation(
            center=(self.target_pos[0] + sin(radians(angle)) * speed,
                    self.target_pos[1] - cos(radians(angle)) * speed),
            t="out_cubic",
            d=0.6)
        anim.start(self)
Beispiel #21
0
    def transform_with_touch(self, touch):
        init_pos = self.center
        init_scale = self.scale
        init_touch_len = len(self._touches)
        #super(ZIScatter, self).transform__with__touch(touch)

        # just do a simple one finger drag
        if len(self._touches
               ) == 1 and self.scale > 1.05:  #THIS IS NOT IN ORIGINAL SCATTER:
            # _last_touch_pos has last pos in correct parent space,
            # just like incoming touch
            dx = (touch.x - self._last_touch_pos[touch][0]) \
                    * self.do_translation_x
            dy = (touch.y - self._last_touch_pos[touch][1]) \
                    * self.do_translation_y
            self.apply_transform(Matrix().translate(dx, dy, 0))
            #return

        elif len(
                self._touches
        ) == 1 and self.scale < 1.05:  #THIS IS NOT IN ORIGINAL SCATTER:
            return

        else:  #TO AVOID RETURN IN ORIGINAL SCATTER
            # we have more than one touch...
            points = [Vector(self._last_touch_pos[t]) for t in self._touches]

            # we only want to transform if the touch is part of the two touches
            # furthest apart! So first we find anchor, the point to transform
            # around as the touch farthest away from touch
            anchor = max(points, key=lambda p: p.distance(touch.pos))

            # now we find the touch farthest away from anchor, if its not the
            # same as touch. Touch is not one of the two touches used to transform
            farthest = max(points, key=anchor.distance)
            if points.index(farthest) != self._touches.index(touch):
                return

            # ok, so we have touch, and anchor, so we can actually compute the
            # transformation
            old_line = Vector(*touch.ppos) - anchor
            new_line = Vector(*touch.pos) - anchor

            angle = radians(new_line.angle(old_line)) * self.do_rotation
            self.apply_transform(Matrix().rotate(angle, 0, 0, 1),
                                 anchor=anchor)

            if self.do_scale:
                scale = new_line.length() / old_line.length()
                new_scale = scale * self.scale
                if new_scale < self.scale_min or new_scale > self.scale_max:
                    scale = 1.0
                self.apply_transform(Matrix().scale(scale, scale, scale),
                                     anchor=anchor)

        #avoid scatter leaving its box
        limitx, limity = self.is_leaving_its_box()
        if limitx or limity:
            #cancel previous apply_transform
            if init_touch_len == 1:
                ddx = ddy = 0
                if limitx: ddx = -dx
                if limity: ddy = -dy
                self.apply_transform(Matrix().translate(ddx, ddy, 0))
            else:
                if self.do_scale:
                    #self.apply_transform(Matrix().scale(scale/init_scale, scale/init_scale, scale/init_scale),
                    #             anchor=anchor)
                    # control
                    #limitx, limity = self.is_leaving_its_box()
                    #if limitx or limity:
                    self.fix_after_leaving_its_box()
Beispiel #22
0
 def _get_rotation(self):
     v1 = Vector(0, 10)
     tp = self.to_parent
     v2 = Vector(*tp(*self.pos)) - tp(self.x, self.y + 10)
     return -1.0 * (v1.angle(v2) + 180) % 360
Beispiel #23
0
class Car(RelativeLayout):
    _ROTATIONS = (0, 20, -20)

    def __init__(self, car_idx, initial_destination, args):
        self.pos = (100, 100)

        self._idx = car_idx
        self._sand_speed = _PADDING / 5.0
        self._full_speed = _PADDING / 4.0
        self._velocity = self._full_speed
        self._last_action = 0  # index of _ROTATIONS
        self._direction = Vector(-1, 0)
        self._scores = []
        self._orientation = 0.0
        self._distance = 0.0
        self._current_destination = initial_destination
        self._write_status_file = args.write_status_file

        if self._write_status_file:
            self._status_file = open("car{}_status".format(car_idx), "w")

        RelativeLayout.__init__(self)

        with self.canvas.before:
            PushMatrix()
            self._rotation = Rotate()

        with self.canvas.after:
            PopMatrix()

        self._center = Center()
        self._body = Body(Vector(-5, -5), _IDX_TO_COLOR[self._idx][0])
        self._mid_sensor = Sensor(Vector(-30, -5), RGBAColor.RED,
                                  self._rotation)
        self._right_sensor = Sensor(Vector(-20, 10), RGBAColor.GREEN,
                                    self._rotation)
        self._left_sensor = Sensor(Vector(-20, -20), RGBAColor.BLUE,
                                   self._rotation)

        if args.use_pytorch:
            from torch_ai import Brain
        else:
            from simple_ai import Brain

        self._brain = Brain(len(self._state), len(self._ROTATIONS), args)

    def build(self):
        self.add_widget(self._body)
        self.add_widget(self._mid_sensor)
        self.add_widget(self._right_sensor)
        self.add_widget(self._left_sensor)
        self.add_widget(self._center)

    @property
    def _state(self):
        return (
            self._left_sensor.signal,
            self._mid_sensor.signal,
            self._right_sensor.signal,
            self._orientation,
            -self._orientation,
        )

    @property
    def position(self):
        return Vector(*self.pos) + self._center.position

    def _rotate(self, angle_of_rotation):
        self._rotation.angle += angle_of_rotation

        self._direction = self._direction.rotate(angle_of_rotation)

    def _write_status(self, reward):
        self._status_file.seek(0)
        self._status_file.write("Car color    : {}\n".format(
            _IDX_TO_COLOR[self._idx][1]))
        self._status_file.write("Destination  : {}, ({:>4d}, {:>4d})\n".format(
            self._current_destination,
            self._current_destination.position.x,
            self._current_destination.position.y,
        ))
        self._status_file.write("Distance     : {:>9.4f}\n".format(
            self._distance))
        self._status_file.write("Orientation  : {:>9.4f}\n".format(
            self._orientation))
        self._status_file.write("Reward       : {: >9.4f}\n".format(reward))
        self._status_file.write(
            "Middle sensor: {: 2.4f}, ({:>9.4f}, {:>9.4f})\n".format(
                self._mid_sensor.signal,
                self._mid_sensor.abs_pos.x,
                self._mid_sensor.abs_pos.y,
            ))
        self._status_file.write(
            "Right sensor : {: 2.4f}, ({:>9.4f}, {:>9.4f})\n".format(
                self._right_sensor.signal,
                self._right_sensor.abs_pos.x,
                self._right_sensor.abs_pos.y,
            ))
        self._status_file.write(
            "Left sensor  : {: 2.4f}, ({:>9.4f}, {:>9.4f})\n".format(
                self._left_sensor.signal,
                self._left_sensor.abs_pos.x,
                self._left_sensor.abs_pos.y,
            ))

    def _set_collision_signal_value(self, sensor):
        if (sensor.abs_pos.x >= self.parent.width - _PADDING
                or sensor.abs_pos.x <= _PADDING
                or sensor.abs_pos.y >= self.parent.height - _PADDING
                or sensor.abs_pos.y <= _PADDING):
            sensor.signal = 1.

    def _get_reward(self, approached_destination):
        reward = 0.0

        if self.position.x < _PADDING:
            self.pos = (_PADDING, self.pos[1])
            reward = -1.0

        if self.position.x > self.parent.width - _PADDING:
            self.pos = (self.parent.width - _PADDING, self.pos[1])
            reward = -1.0

        if self.position.y < _PADDING:
            self.pos = (self.pos[0], _PADDING)
            reward = -1.0

        if self.position.y > self.parent.height - _PADDING:
            self.pos = (self.pos[0], self.parent.height - _PADDING)
            reward = -1.0

        if reward < 0.0:
            if approached_destination:
                if self.parent.sand[int(self.position.x),
                                    int(self.position.y)] > 0:
                    self._velocity = self._sand_speed
                    reward += 0.1
                else:
                    self._velocity = self._full_speed
                    reward += 0.3
        else:
            if approached_destination:
                if self.parent.sand[int(self.position.x),
                                    int(self.position.y)] > 0:
                    self._velocity = self._sand_speed
                    reward -= 0.2
                else:
                    self._velocity = self._full_speed
                    reward += 0.6

        return reward

    def move(self):
        self._rotate(self._ROTATIONS[self._last_action])

        self.pos = self._direction * self._velocity + self.pos

        new_distance = self.position.distance(
            self._current_destination.position)

        self._orientation = self._direction.angle(
            self._current_destination.position - self.position) / 180.
        self._left_sensor.signal = numpy.sum(
            self.parent.sand[int(self._left_sensor.abs_pos.x) -
                             _SIGNAL_RADIUS:int(self._left_sensor.abs_pos.x) +
                             _SIGNAL_RADIUS,
                             int(self._left_sensor.abs_pos.y) -
                             _SIGNAL_RADIUS:int(self._left_sensor.abs_pos.y) +
                             _SIGNAL_RADIUS, ]) / 400.
        self._mid_sensor.signal = numpy.sum(
            self.parent.sand[int(self._mid_sensor.abs_pos.x) -
                             _SIGNAL_RADIUS:int(self._mid_sensor.abs_pos.x) +
                             _SIGNAL_RADIUS,
                             int(self._mid_sensor.abs_pos.y) -
                             _SIGNAL_RADIUS:int(self._mid_sensor.abs_pos.y) +
                             _SIGNAL_RADIUS, ]) / 400.
        self._right_sensor.signal = numpy.sum(
            self.parent.sand[int(self._right_sensor.abs_pos.x) -
                             _SIGNAL_RADIUS:int(self._right_sensor.abs_pos.x) +
                             _SIGNAL_RADIUS,
                             int(self._right_sensor.abs_pos.y) -
                             _SIGNAL_RADIUS:int(self._right_sensor.abs_pos.y) +
                             _SIGNAL_RADIUS, ]) / 400.

        self._set_collision_signal_value(self._left_sensor)
        self._set_collision_signal_value(self._right_sensor)
        self._set_collision_signal_value(self._mid_sensor)

        reward = self._get_reward(new_distance < self._distance)

        self._last_action = self._brain.update(
            reward,
            self._state,
        )

        self._distance = new_distance

        if self._distance < _PADDING * 2:
            if isinstance(self._current_destination, Airport):
                self._current_destination = self.parent.downtown
            else:
                self._current_destination = self.parent.airport

        self._scores.append(self._brain.score)

        if len(self._scores) > 1000:
            del self._scores[0]

        if self._write_status_file:
            self._write_status(reward)

    def save_brain(self):
        self._brain.save("car{}_brain".format(self._idx))

    def load_brain(self):
        self._brain.load("car{}_brain".format(self._idx))

    @property
    def scores(self):
        return self._scores

    @property
    def body_color(self):
        return self._body.color
Beispiel #24
0
 def process(self, touches, strokes):
     uid = touches[0].uid
     v = Vector(touches[0].x, touches[0].y) - self.initial_touches[uid]
     a = v.angle((1, 0))
     self.get_app().fire_event("on_gesture_swipe", v,
                               self.initial_touches[uid])
Beispiel #25
0
    def collide_wall(self, wall):
        # don't collide with this wall if we just did so; this
        # eliminates a huge class of weird behaviors
        if self.last_bounced_wall == wall and self.last_bounced_ticks < 5:
            return

        deflect_edge = None
        velocity_v = Vector(self.velocity)
        pos_v = Vector(self.pos)

        edge_points = zip(wall.quad_points[0::2], wall.quad_points[1::2])
        edges = [
            (edge_points[0], edge_points[1]),
            (edge_points[1], edge_points[2]),
            (edge_points[2], edge_points[3]),
            (edge_points[3], edge_points[0]),
        ]

        closest_point = None

        for point in edge_points:
            if (pos_v - Vector(point)).length() < self.r:
                if (
                    not closest_point
                    or (pos_v - Vector(point)).length() < (Vector(closest_point) - Vector(point)).length()
                ):
                    closest_point = point

        if closest_point:
            # take the deflection edge to be the normal of here to the corner
            deflect_edge = (pos_v - Vector(point)).rotate(90)

        else:
            for edge in edges:
                e0 = Vector(edge[0])
                e1 = Vector(edge[1])

                ortho_v = (e0 - e1).rotate(90).normalize()
                dist_v = Vector.line_intersection(self.pos, pos_v + ortho_v, edge[0], edge[1])

                # dist_v will be None if we happen to be parallel
                if not dist_v:
                    continue

                dist_from_edge = (pos_v - dist_v).length()

                # if the shot touches the wall here
                if (
                    min(e0[0], e1[0]) <= dist_v[0] <= max(e0[0], e1[0])
                    and min(e0[1], e1[1]) <= dist_v[1] <= max(e0[1], e1[1])
                    and dist_from_edge < self.r + (wall.thickness / 2.0)
                ):
                    if not deflect_edge:
                        deflect_edge = e0 - e1
                        dist_from_deflect_edge = dist_from_edge

                    elif dist_from_edge < dist_from_deflect_edge:
                        deflect_edge = e0 - e1
                        dist_from_deflect_edge = dist_from_edge

        if deflect_edge:
            self.velocity = velocity_v.rotate(-2 * velocity_v.angle(deflect_edge))
            self.last_bounced_wall = wall
            self.last_bounced_ticks = 0
Beispiel #26
0
class Fish(Scatter):
    active = BooleanProperty(False)
    alive = BooleanProperty(True)
    navigating = BooleanProperty(False)
    box = ListProperty([])

    calories = BoundedNumericProperty(1000, min=0, max=1000)
    total_calories = NumericProperty(0)
    junk_swallowed = NumericProperty(0)

    # Max level 8
    obese_lvl = BoundedNumericProperty(1, min=0, max=8)

    # Immutable properties
    #
    # How many calories will be consumed per second each level
    calories_consumption = [7, 16, 20, 29, 32, 35, 42, 50]
    # Eat that much calories (in total) and you level up!
    lvlup_on_calories = [150, 350, 550, 900, 1400, 2100, 3000, 4100]
    # Relative size increase upon each lvlup
    size_increment = [1, 1.2, 1.2, 1.2, 1.4, 1.1, 1.1, 1.1]
    # Every level has a rank!
    rank = [
        "a fry", "a cat", "a car", "a whale", "a candy store", "an oil tanker",
        "the Iceland", "the Indian Ocean itself!", 'the "MAFIAA"'
    ]

    def __init__(self,
                 image="images/fish.png",
                 box=[0, 0, 100, 100],
                 **kwargs):
        self.direction = Vector(-1, 0)
        self.angle = 1

        self.size = (48, 48)
        self.box = box
        self.center = (Window.width / 2, Window.height)
        self.image = Image(source=image, allow_stretch=True, size=self.size)

        # Can't be arsed to 'rotate' texture 'properly', this is so frikin more simple
        self.texture_left = self.image.texture.get_region(0, 0, 194, 192)
        self.texture_right = self.image.texture.get_region(205, 0, 194, 192)
        self.image.texture = self.texture_left

        self.target_pos = self.center

        super(Fish, self).__init__(**kwargs)
        self.add_widget(self.image)

        self.register_event_type('on_death')

        # Every living creature consumes own self
        self.bind(active=lambda instance, value: Clock.schedule_interval(
            instance.consume_calories, 0.5)
                  if value else Clock.unschedule(instance.consume_calories))
        # Dynamic entry
        self.bind(active=lambda instance, value: Animation(
            y=Window.height - 400, t="out_back", d=1.2).start(instance)
                  if value else True)
        # Too many calories make you obese
        self.bind(total_calories=self.lvlup)

    def eat(self, stuff):
        self.calories = self.calories + stuff.calories if self.calories + stuff.calories <= 1000 else 1000

        # Scrap food does not count into total calories
        if stuff.calories > 0:
            self.total_calories += stuff.calories

        if isinstance(stuff, Junk):
            self.junk_swallowed += 1

    def consume_calories(self, *args):
        self.calories -= self.calories_consumption[self.obese_lvl - 1]

    def lvlup(self, instance, value):
        if self.total_calories >= self.lvlup_on_calories[self.obese_lvl]:
            self.obese_lvl += 1
            print(self.obese_lvl)
            self.image.size = (self.image.width *
                               self.size_increment[self.obese_lvl - 1],
                               self.image.height *
                               self.size_increment[self.obese_lvl - 1])
            self.size = self.image.size

    def swim(self, dt):
        if self.angle > 0:
            self.image.texture = self.texture_left
        else:
            self.image.texture = self.texture_right

        anim = Animation(center=self.target_pos, d=0.1)
        anim.start(self)

    def on_death(self):
        self.alive = False
        self.active = False

    def on_touch_down(self, touch):
        if not self.collide_point(touch.x, touch.y):
            return False

        if self.active and self.alive:
            Clock.schedule_interval(self.swim, 0.1)
            self.navigating = True

    def on_touch_move(self, touch):
        if not self.alive:
            return False

        # Facing to the left will be positive, to right - negative deg values
        angle = self.direction.angle((touch.dsx, touch.dsy))
        self.angle = cos(radians(angle)) * 180

        # TODO: solve facing glitch problem with Clock, which sets facing_change cooldown timer for half a sec

        # Bounding box
        x = touch.x
        if touch.x >= self.box[2]:
            x = self.box[2]
        elif touch.x <= self.box[0]:
            x = self.box[0]

        y = touch.y
        if touch.y >= self.box[3]:
            y = self.box[3]
        elif touch.y <= self.box[1]:
            y = self.box[1]

        self.target_pos = (x, y)

    def on_touch_up(self, touch):
        if not self.navigating:
            return False

        self.navigating = False

        Clock.unschedule(self.swim)

        speed = Vector((0, 0)).distance((touch.dsx, touch.dsy)) * 5000

        angle = self.direction.angle((touch.dsx, touch.dsy))
        if angle < 0:
            angle = 360 + angle
        angle = 270 - angle

        anim = Animation(
            center=(self.target_pos[0] + sin(radians(angle)) * speed,
                    self.target_pos[1] - cos(radians(angle)) * speed),
            t="out_cubic",
            d=0.6)
        anim.start(self)
    def calc_mesh_vertices(self, step = None, update_mesh=True, preserve_uv=True):
        """Calculate Mesh.vertices and indices from the ControlPoints
        If step omitted, uses ControlPoints at current position, otherwise
        vertices at that animation step (ControlPoint.positions[step]).
        Central vertice at center is added as first item in list if mesh_mode=='triangle_fan'
        preserve_uv: Do not overwrite the uv coordinates in the current Mesh.vertices
        (only has an effect if update_mesh==True and vertices are already set)

        returns vertices, indices
        """
        if step is not None and not isinstance(step, basestring):
            raise ValueError('step must be a string')

        num = len(self.control_points)
        if num == 0:
            Logger.warning("AnimationConstructor: Called calc_mesh_vertices without any control_points")
            return [], []


        triangle_fan_mode = self.mesh_mode == 'triangle_fan'

        verts = []
        cent_x, cent_y, cent_u, cent_v = 0.0, 0.0, 0.0, 0.0

        # Need to calculate Centroid first, then do pass through to calculate vertices
        for cp in self.control_points:
            tx, ty = cp.get_tex_coords(step)
            cent_x += tx
            cent_y += ty

        cent_x /= num
        cent_y /= num

        # step may be None if moving points
        if triangle_fan_mode and self.animation_step==setup_step:
            # Sort by angle from centroid in case user didn't place around perimeter in order

            cent_vec = Vector(cent_x, cent_y)
            ref = Vector(1, 0) # Reference vector to measure angle from
            for cp in self.control_points:
                cp.centroid_angle = ref.angle(Vector(cp.get_tex_coords(step)) - cent_vec)

            # ListProperty.sort does not exist
            #self.control_points.sort(key = lambda cp: cp.centroid_angle)
            self.control_points = sorted(self.control_points, key = lambda cp: cp.centroid_angle)

        # TODO Need to figure out similar solution if using triangle_strip

        # Create vertices list
        # centroid added as first vertex in triangle-fan mode
        start = 1 if triangle_fan_mode else 0
        # enumerate always goes through all items, start is just where the count starts
        for index, cp in enumerate(self.control_points, start=start):
            coords = cp.calc_vertex_coords(pos_index=step)
            # Need to calculate u, v centroid still
            cent_u += coords[2]
            cent_v += coords[3]

            cp.vertex_index = index
            verts.extend(coords)

        cent_u /= num
        cent_v /= num

        if triangle_fan_mode:
            # Calculate mean centroid and add to beginning of vertices
            verts.insert(0, cent_v)
            verts.insert(0, cent_u)
            verts.insert(0, cent_y)
            verts.insert(0, cent_x)

            # PERF: Technically don't need to recalculate indices except step 0, but not bothering with optimization now
            indices = range(1, num + 1)
            indices.insert(0, 0)
            indices.append(1)

        else:
            indices = range(num)

        if update_mesh:
            mesh_verts = self.mesh.vertices
            num_mesh_verts = len(mesh_verts)

            # preserve_uv: Do not overwrite the uv coordinates in the current Mesh.vertices
            # None: False if self.animation_step == setup_step
            # specified: False if step == setup_step
            # Refactored this way earlier, but went back because Animation uses None and when animating
            # back to setup_step we want preserve_uv false
            # preserve_uv = True
            # if step is None and self.animation_step == setup_step:
            #     preserve_uv = False
            # elif step == setup_step:
            #     preserve_uv = False

            if preserve_uv and num_mesh_verts > 0:
                if num_mesh_verts != len(verts):
                    raise AssertionError('Number of calculated vertices (%d) != number Mesh.vertices (%d) step=%s'
                                         %(len(verts), num_mesh_verts, step))

                # Only overwrite x, y mesh coords
                for x in range(0, num_mesh_verts, 4):
                    mesh_verts[x] = verts[x]
                    mesh_verts[x+1] = verts[x+1]

                self.mesh.vertices = mesh_verts

            else:
                self.mesh.vertices = verts

            self.mesh.indices = indices

        return verts, indices
Beispiel #28
0
 def _get_rotation(self):
     v1 = Vector(0, 10)
     tp = self.to_parent
     v2 = Vector(*tp(*self.pos)) - tp(self.x, self.y + 10)
     return -1.0 * (v1.angle(v2) + 180) % 360
Beispiel #29
0
    def update(self, dt):
        # collisions:
        # stick collide with the balls:
        if self.stick.collide_widget(
                self.white_ball) and self.shoot_power != 0:
            print("collide with white ball")
            dx = cos(self.stick.angle * pi / 180 + pi / 2) * self.shoot_power
            dy = sin(self.stick.angle * pi / 180 + pi / 2) * self.shoot_power
            self.white_ball.dx = dx
            self.white_ball.dy = dy
            try:
                self.anim.cancel(self.stick)
            except:
                pass
        # collisions with borders:
        for ball in self.balls:
            if ball.top > self.table.top:
                ball.top = self.table.top
                ball.dy *= -1
            if ball.y < self.table.y:
                ball.y = self.table.y
                ball.dy *= -1
            if ball.right > self.table.right:
                ball.right = self.table.right
                ball.dx *= -1
            if ball.x < self.table.x:
                ball.x = self.table.x
                ball.dx *= -1
        # collision ball1-ball2:
        for ball1, ball2 in [(self.balls[0], self.balls[1]),
                             (self.balls[0], self.balls[2]),
                             (self.balls[1], self.balls[2])]:
            if ball1.collide_widget(ball2):
                ball1_pos = Vector(*ball1.pos)
                print(ball2)
                ball2_pos = Vector(*ball2.pos)
                dist_ball1_ball2 = ball1_pos.distance(ball2_pos)
                offset = max(ball1.width - dist_ball1_ball2, 0)

                ball1_vel = Vector(ball1.dx, ball1.dy)
                half_speed = ball1_vel.length() / 2
                angle_vel = ball1_vel.angle(Vector(1, 0))
                angle_ball1_ball2 = Vector(ball2.x - ball1.x,
                                           ball2.y - ball1.y).angle(
                                               Vector(1, 0))
                angle_desv_perp_collision = angle_ball1_ball2 + (90 -
                                                                 angle_vel)
                angle_ball1 = angle_desv_perp_collision + angle_ball1_ball2 + 90
                ball1_vel = Vector(half_speed, 0).rotate(angle_ball1)
                ball1.dx = ball1_vel.x
                ball1.dy = ball1_vel.y
                angle_ball2 = angle_ball1_ball2 + 90 - angle_desv_perp_collision
                ball_1 = Vector(half_speed, 0).rotate(angle_ball2)
                ball2.dx = ball_1.x
                ball2.dy = ball_1.y
                vector_offset = Vector(offset, 0).rotate(angle_ball1)
                ball1.x += vector_offset.x
                ball1.y += vector_offset.y

        for ball in self.balls:
            print("ball", ball, ball.x, ball.y, ball.dx, ball.dy)
            # Collide with holes:
            for hole in self.holes:
                if hole.collide_point(*ball.center):
                    self.remove_widget(ball)
            # Friction:
            ball.frictionx = ball.dx * BALL_FRICTION * dt
            ball.frictiony = ball.dy * BALL_FRICTION * dt
            # kinematic equations:
            ball.x += ball.dx * dt
            ball.y += ball.dy * dt
            ball.dx -= ball.frictionx
            ball.dy -= ball.frictiony
            if abs(ball.dx) < 0.01:
                ball.dx = 0
            if abs(ball.dy) < 0.01:
                ball.dy = 0
Beispiel #30
0
    def collide_wall(self, wall):
        # don't collide with this wall if we just did so; this
        # eliminates a huge class of weird behaviors
        if self.last_bounced_wall == wall and self.last_bounced_ticks < 5:
            return

        deflect_edge = None
        velocity_v = Vector(self.velocity)
        pos_v = Vector(self.pos)

        edge_points = zip(wall.quad_points[0::2], wall.quad_points[1::2])
        edges = [
            (edge_points[0], edge_points[1]),
            (edge_points[1], edge_points[2]),
            (edge_points[2], edge_points[3]),
            (edge_points[3], edge_points[0]),
        ]

        closest_point = None

        for point in edge_points:
            if (pos_v - Vector(point)).length() < self.r:
                if not closest_point or \
                   (pos_v - Vector(point)).length() < (Vector(closest_point) - Vector(point)).length():
                    closest_point = point

        if closest_point:
            # take the deflection edge to be the normal of here to the corner
            deflect_edge = (pos_v - Vector(point)).rotate(90)

        else:
            for edge in edges:
                e0 = Vector(edge[0])
                e1 = Vector(edge[1])

                ortho_v = (e0 - e1).rotate(90).normalize()
                dist_v = Vector.line_intersection(self.pos, pos_v + ortho_v,
                                                  edge[0], edge[1])

                # dist_v will be None if we happen to be parallel
                if not dist_v:
                    continue

                dist_from_edge = (pos_v - dist_v).length()

                # if the shot touches the wall here
                if min(e0[0], e1[0]) <= dist_v[0] <= max(e0[0], e1[0]) and \
                   min(e0[1], e1[1]) <= dist_v[1] <= max(e0[1], e1[1]) and \
                   dist_from_edge < self.r + (wall.thickness / 2.):
                    if not deflect_edge:
                        deflect_edge = e0 - e1
                        dist_from_deflect_edge = dist_from_edge

                    elif dist_from_edge < dist_from_deflect_edge:
                        deflect_edge = e0 - e1
                        dist_from_deflect_edge = dist_from_edge

        if deflect_edge:
            self.velocity = velocity_v.rotate(-2 *
                                              velocity_v.angle(deflect_edge))
            self.last_bounced_wall = wall
            self.last_bounced_ticks = 0
Beispiel #31
0
class Fish(Scatter):
    active = BooleanProperty(False)
    alive = BooleanProperty(True)
    navigating = BooleanProperty(False)
    box = ListProperty([])
    
    calories = BoundedNumericProperty(1000, min=0, max=1000)
    total_calories = NumericProperty(0)
    junk_swallowed = NumericProperty(0)
    
    # Max level 8
    obese_lvl = BoundedNumericProperty(1, min=0, max=8)
    
    # Immutable properties
    #
    # How many calories will be consumed per second each level
    calories_consumption = [7, 16, 20, 29, 32, 35, 42, 50]
    # Eat that much calories (in total) and you level up!
    lvlup_on_calories = [150, 350, 550, 900, 1400, 2100, 3000, 4100]
    # Relative size increase upon each lvlup
    size_increment = [1, 1.2, 1.2, 1.2, 1.4, 1.1, 1.1, 1.1]
    # Every level has a rank!
    rank = ["a fry", "a cat", "a car", "a whale", "a candy store", "an oil tanker", "the Iceland", "the Pacific Ocean itself!", 'the "MAFIAA"']

    def __init__(self, image = "images/fish.png", box = [0, 0, 100, 100], **kwargs):
        self.direction = Vector(-1, 0)
        self.angle = 1
        
        self.size = (48,48)
        self.box = box
        self.center = (Window.width / 2, Window.height)
        self.image = Image(source=image, allow_stretch=True, size=self.size)
        
        # Can't be arsed to 'rotate' texture 'properly', this is so frikin more simple
        self.texture_left = self.image.texture.get_region(0, 0, 194, 192)
        self.texture_right = self.image.texture.get_region(205, 0, 194, 192)
        self.image.texture = self.texture_left
        
        self.target_pos = self.center
        
        super(Fish, self).__init__(**kwargs)
        self.add_widget(self.image)
        
        self.register_event_type('on_death')
        
        # Every living creature consumes own self
        self.bind(active=lambda instance, value: Clock.schedule_interval(instance.consume_calories, 0.5) if value else Clock.unschedule(instance.consume_calories))
        # Dynamic entry
        self.bind(active=lambda instance, value: Animation(y=Window.height - 400, t="out_back", d=1.2).start(instance) if value else True)
        # Too many calories make you obese
        self.bind(total_calories=self.lvlup)
    
    def eat(self, stuff):
        try:
            self.calories = self.calories + stuff.calories if self.calories + stuff.calories <= 1000 else 1000
        except:
            self.calories = 0
            self.dispatch("on_death")
            
        # Scrap food does not count into total calories
        if stuff.calories > 0:
            self.total_calories += stuff.calories
        
        if isinstance(stuff, Junk):
            self.junk_swallowed += 1
                
    def consume_calories(self, *args):
        try:
            self.calories -= self.calories_consumption[self.obese_lvl-1]
        except:
            self.calories = 0
            self.dispatch("on_death")
    
    def lvlup(self, instance, value):
        try:
            #TODO: will there be lvl limit?
            if self.total_calories >= self.lvlup_on_calories[self.obese_lvl]:
                self.obese_lvl += 1
                print self.obese_lvl
                self.image.size = (self.image.width * self.size_increment[self.obese_lvl-1], self.image.height * self.size_increment[self.obese_lvl-1])
                self.size = self.image.size
        except:
            pass
            
    def swim(self, dt):
        if self.angle > 0:
            self.image.texture = self.texture_left
        else:
            self.image.texture = self.texture_right
  
        anim = Animation(center=self.target_pos, d=0.1)
        anim.start(self)
        
    def on_death(self):
        self.alive = False
        self.active = False
            
    def on_touch_down(self, touch):
        if not self.collide_point(touch.x, touch.y):
            return False
            
        if self.active and self.alive:
            Clock.schedule_interval(self.swim, 0.1)  
            self.navigating = True      
        
    def on_touch_move(self, touch):
        if not self.alive:
            return False
            
        # Facing to the left will be positive, to right - negative deg values
        angle = self.direction.angle((touch.dsx, touch.dsy))
        self.angle = cos(radians(angle)) * 180
        
        # TODO: solve facing glitch problem with Clock, which sets facing_change cooldown timer for half a sec
        
        # Bounding box
        x = touch.x
        if touch.x >= self.box[2]:
            x = self.box[2]
        elif touch.x <= self.box[0]:
            x = self.box[0]
            
        y = touch.y
        if touch.y >= self.box[3]:
            y = self.box[3]
        elif touch.y <= self.box[1]:
            y = self.box[1]
            
        self.target_pos = (x, y)
        
    def on_touch_up(self, touch):
        if not self.navigating:
            return False
        
        self.navigating = False
        
        Clock.unschedule(self.swim)
        
        speed = Vector((0,0)).distance((touch.dsx, touch.dsy)) * 5000
        
        angle = self.direction.angle((touch.dsx, touch.dsy))
        if angle < 0:
            angle = 360 + angle
        angle = 270 - angle

        anim = Animation(center=(self.target_pos[0] + sin(radians(angle)) * speed,self.target_pos[1] - cos(radians(angle)) * speed), t="out_cubic", d=0.6)
        anim.start(self)