Mad Wombat
Mad Wombat

Reputation: 15135

Kivy widgets behaving erratically

I have been playing around with the Kivy Pong tutorial, getting up to speed with the framework, seeing if I could implement a few ideas. I have removed most of the Pong functionality, so I could have only bouncing ball on the screen and added some code to generate multiple bouncing balls on the screen, generated on touch. That worked fine. I then added some extra canvas instructions, so I would have a line drawn indicating the direction the ball is moving. This is where things got weird. The first ball acts just as it should, bouncing around the screen. But any following clicks generate balls that go off screen, randomly change direction and speed and in general behave chaotically. I have been looking at my code and I cannot seem to find any indication of what might be going wrong. I keep all the references to the widgets, I add them to the root widget, I don't seem to be sharing any information between them... Anyway, here is the code, maybe someone can enlighten me. Using latest kivy and python 3.6.

from random import randint

from kivy.app import App

from kivy.clock import Clock
from kivy.config import Config
from kivy.vector import Vector
from kivy.uix.widget import Widget
from kivy.properties import AliasProperty, ListProperty, NumericProperty, ReferenceListProperty


class Playground(Widget):
    critters = ListProperty([])

    def update(self, dt):
        for critter in self.critters:
            critter.move()
            if (critter.y  self.height):
                critter.v_y *= -1
            if (critter.x  self.width):
                critter.v_x *= -1
        self.score.text = "{}".format(len(self.critters))

    def on_touch_down(self, touch):
        critter = Critter()
        critter.pos = touch.x, touch.y
        self.critters.append(critter)
        self.add_widget(critter)


class Critter(Widget):
    angle = NumericProperty(0)
    v_x = NumericProperty(0)
    v_y = NumericProperty(0)
    velocity = ReferenceListProperty(v_x, v_y)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.velocity = Vector(5, 0).rotate(randint(0, 360))
        self.angle = Vector(*self.velocity).angle(Vector(1, 0))

    def move(self):
        self.pos = Vector(*self.velocity) + self.pos
        self.angle = Vector(*self.velocity).angle(Vector(1, 0))


class WorldApp(App):
    def build(self):
        game = Playground()
        Clock.schedule_interval(game.update, 1.0/60.0)
        return game

if __name__ == '__main__':
    Config.set('kivy', 'desktop', 1)
    Config.set('kivy', 'exit_on_escape', 1)
    Config.set('graphics', 'resizable', 0)
    WorldApp().run()

and the KV file

<Playground>
    score: score

    canvas:
        Color:
            rgb: 0.0, 0.1, 0.0
        Rectangle
            pos: self.pos
            size: self.size

    Label:
        id: score
        pos: self.parent.width - self.size[0], self.parent.height - self.size[1]
        font_size: 16
        size: self.texture_size


<Critter>
    size: 30, 30
    canvas:
        Rotate:
            angle: self.angle
            origin: self.center
            axis: 0, 0, 1
        Color:
            rgb: 0.5, 0.0, 0.0
        Ellipse:
            pos: self.pos
            size: self.size
        Color:
            rgb: 1, 1, 0.0
        Line:
            width: 2
            points: self.center[0], self.center[1], self.center[0] + self.size[0] / 2, self.center[1]

Upvotes: 3

Views: 908

Answers (1)

inclement
inclement

Reputation: 29488

I'm not sure if it's causing your problem, but your Rotate instructions aren't bounded by the widget rule and will affect any later widgets - so the Rotate of each Critter is applied to every later one.

To avoid this, add PushMatrix: at the top of the canvas rule and PopMatrix: at the bottom. These instructions effectively save and later revert to the initial rotation state before your change.

Upvotes: 3

Related Questions