2018年6月9日 星期六
Kivy PongGame adaption
markdown
Lately I try to do some side projects and I found an app might be great. So I start to look for some Python libraries as a GUI solution. I compared Tkinter, PyQt, WxPython, Kivy. I want it free, modern, and have good API reference. Tkinter looks old, PyQt is not free and API of PySide is somewhat difficult for me to read. WxPython is good, but I like the UI of Kivy more.
Therefore I have gone through the tutorials and Development guide, and also the PongGame one. Following the steps is really easy and it did not take much time to complete. As the author said, the app was the bare minimum to understand the application development in Kivy, so I made some improvements, mostly to make it more naturally, and I think share it would be interesting.
Here are the improvements I did:
1. Instead of Touch event( hard to play by PC users), I try to read the API and use Window.KeyBoard class.
2. Moving the paddle was not smooth and it can stuck when you change direction promptly.
Here it is:
#pong.kv
```
#:kivy 1.0.9
#step2
:
size_x:self.size_x
size_y:self.size_y
size: self.size_x, self.size_y
canvas:
Ellipse:
pos: self.pos
size: self.size
:
size: 25, 200
canvas:
Rectangle:
pos:self.pos
size:self.size
:
#ball id here
ball: pong_ball
p1: player_left
p2: player_right
canvas:
Rectangle:
pos: self.center_x - 5, 0
size: 5, self.height
Label:
font_size: 70
center_x: root.width / 4
top: root.top - 5
text: str(root.p1.score)
Label:
font_size: 70
center_x: root.width * 3 / 4
top: root.top - 5
text: str(root.p2.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
```
#PongGame.py
```
#Original by the author of Kivy- inclement, Adapted by iamlockon on 2018-06-09
#More PongGame information from the author:
#https://kivy.org/docs/tutorials/pong.html
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
from kivy.core.window import Window
class PongPaddle(Widget):
score = NumericProperty(0)
#setting paddle speed
vel_paddle_y = NumericProperty(0)
#track the key states with mask
key_mask = 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
def move(self):
#12,3: both pressed ; 0: both unpressed --> stop
if self.key_mask in (12, 3, 0):
self.vel_paddle_y = 0
#8,2: pressing up
if self.key_mask in (8, 2):
self.vel_paddle_y = 8
#4,1: pressing down
if self.key_mask in (4, 1):
self.vel_paddle_y = -8
self.center_y = self.vel_paddle_y + self.center_y
#step2
class PongBall(Widget):
size_x = NumericProperty(50)
size_y = NumericProperty(50)
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)
p1 = ObjectProperty(None)
p2 = ObjectProperty(None)
def __init__(self, **kwargs):
super(PongGame, self).__init__(**kwargs)
#Get a keyboard instance
self._keyboard = Window.request_keyboard(
self._keyboard_closed, self, 'text')
if self._keyboard.widget:
pass
#Binding key events to keyboard
self._keyboard.bind(on_key_down=self._on_keyboard_down)
self._keyboard.bind(on_key_up=self._on_keyboard_up)
def _keyboard_closed(self):
print('My kb has been closed!')
def _on_keyboard_down(self, keyboard, keycode, *args):
'''
Setting the key_mask of paddles(players) respectively.
You might need some bitwise operation knowledge to understand this.
'c' for player 1 up, 'v' for player 1 down.
'n' for player 2 up, 'm' for player 2 down.
bit: 4 3 2 1
key: c v n m
ex: 0 1 0 0 -> 4, player 1 goes down
ex: 1 1 0 1 -> 13, player 1 stops, player 2 moves down
'''
if keycode[1] == 'c':
self.p1.key_mask = self.p1.key_mask | 8
return True
if keycode[1] == 'v':
self.p1.key_mask = self.p1.key_mask | 4
return True
if keycode[1] == 'n':
self.p2.key_mask = self.p2.key_mask | 2
return True
if keycode[1] == 'm':
self.p2.key_mask = self.p2.key_mask | 1
return True
def _on_keyboard_up(self, keyboard, keycode):
if keycode[1] == 'c':
self.p1.key_mask = self.p1.key_mask & 7
return True
if keycode[1] == 'v':
self.p1.key_mask = self.p1.key_mask & 11
return True
if keycode[1] == 'n':
self.p2.key_mask = self.p2.key_mask & 13
return True
if keycode[1] == 'm':
self.p2.key_mask = self.p2.key_mask & 14
return True
def serve_ball(self, vel=(4, 0)):
self.ball.center = self.center
self.ball.velocity = vel
def update(self, dt):
self.ball.move()
#go outside the fringes, pull it back 2 pixels to make sure it can still move.
if self.p1.top > self.top:
self.p1.top = self.top-2
if self.p1.pos[1] < self.x:
self.p1.pos[1] = self.x+2
self.p1.move()
if self.p2.top > self.top:
self.p2.top = self.top-2
if self.p2.pos[1] < self.x:
self.p2.pos[1] = self.x+2
self.p2.move()
self.p1.bounce_ball(self.ball)
self.p2.bounce_ball(self.ball)
if (self.ball.y < self.y) or (self.ball.top > self.top):
self.ball.velocity_y *= -1
if self.ball.x < self.x:
self.p2.score += 1
self.serve_ball(vel=(4,0))
if self.ball.x > self.width:
self.p1.score += 1
self.serve_ball(vel=(-4,0))
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()
```
訂閱:
文章 (Atom)