Relation

Connecting Input Events

At this point in our app, we need to add moveable player racquets and touch input. In Kivy, a widget can react to input by implementing the on_touch_down, the on_touch_move, and the on_touch_up methods. By default, the Widget class implements these methods by just calling the corresponding method on all its child widgets to pass on the event until one of the children returns True.

For the racquets, we essentially just need them to move up and down, and we don't need them to have the player widgets handle the events themselves. So, all we need to do is to implement the on_touch_move function for the PongGame class and have it set the position of left or right based on whether the touch occurs on the left or right side of the screen.

This is the on_touch_move handler:

def on_touch_move(self, touch): if touch.x < self.width/3: self.player1.center_y = touch.y if touch.x > self.width - self.width/3: self.player2.center_y = touch.y

Next, we can keep the score for each player in a NumericProperty. The score labels of the PongGame are kept updated by changing the NumericProperty score. The PongPaddle class also implements a bounce_ball method, so that the ball bounces differently based on where it hits the racket.

class PongPaddle(Widget): score = NumericProperty(0) def bounce_ball(self, ball): if self.collide_widget(ball): speedup = 1.1 offset = 0.02 * Vector(0, ball.center_y-self.center_y) ball.velocity = speedup * (offset - ball.velocity)

And the game is pretty much done! Here is our final code.

main.py:

from kivy.app import App from kivy.uix.widget import Widget from kivy.properties import ( NumericProperty, ReferenceListProperty, ObjectProperty ) from kivy.vector import Vector from kivy.clock import Clock class PongPaddle(Widget): score = NumericProperty(0) def bounce_ball(self, ball): if self.collide_widget(ball): vx, vy = ball.velocity offset = (ball.center_y - self.center_y) / (self.height / 2) bounced = Vector(-1 * vx, vy) vel = bounced * 1.1 ball.velocity = vel.x, vel.y + offset class PongBall(Widget): velocity_x = NumericProperty(0) velocity_y = NumericProperty(0) velocity = ReferenceListProperty(velocity_x, velocity_y) def move(self): self.pos = Vector(*self.velocity) + self.pos class PongGame(Widget): ball = ObjectProperty(None) player1 = ObjectProperty(None) player2 = ObjectProperty(None) def serve_ball(self, vel=(4, 0)): self.ball.center = self.center self.ball.velocity = vel def update(self, dt): self.ball.move() # bounce of paddles self.player1.bounce_ball(self.ball) self.player2.bounce_ball(self.ball) # bounce ball off bottom or top if (self.ball.y < self.y) or (self.ball.top > self.top): self.ball.velocity_y *= -1 # went of to a side to score point? if self.ball.x < self.x: self.player2.score += 1 self.serve_ball(vel=(4, 0)) if self.ball.x > self.width: self.player1.score += 1 self.serve_ball(vel=(-4, 0)) def on_touch_move(self, touch): if touch.x < self.width / 3: self.player1.center_y = touch.y if touch.x > self.width - self.width / 3: self.player2.center_y = touch.y class PongApp(App): def build(self): game = PongGame() game.serve_ball() Clock.schedule_interval(game.update, 1.0 / 60.0) return game if __name__ == '__main__': PongApp().run()

pong.kv:

#:kivy 1.0.9 <PongBall>: size: 50, 50 canvas: Ellipse: pos: self.pos size: self.size <PongPaddle>: size: 25, 200 canvas: Rectangle: pos: self.pos size: self.size <PongGame>: ball: pong_ball player1: player_left player2: player_right canvas: Rectangle: pos: self.center_x - 5, 0 size: 10, self.height Label: font_size: 70 center_x: root.width / 4 top: root.top - 50 text: str(root.player1.score) Label: font_size: 70 center_x: root.width * 3 / 4 top: root.top - 50 text: str(root.player2.score) PongBall: id: pong_ball center: self.parent.center PongPaddle: id: player_left x: root.x center_y: root.center_y PongPaddle: id: player_right x: root.width - self.width center_y: root.center_y

0

1

Updated 2021-09-03

Tags

Python Programming Language

Data Science