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]
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With