我是Kivy的新手,我正在做pong教程,一切都很顺利,我把它改编成4个玩家,每个球拍都有自己的颜色,如果球击中桨,它会得到它的颜色,这样如果球离开屏幕,那么最后一名击球手就会得分。
我在Ubuntu 14,04中使用virtualenv。
为了便于下载和检查,可以在此处找到所有代码:Pong_kivy
有什么问题?
比赛结束后,重新启动球似乎每次都在增加速度,直到它崩溃,这不是由速度矢量引起的,我检查过它,因此我认为我处理错误的Clock.Schedule功能。我似乎无法找到什么错误,所以任何帮助都表示赞赏。
pong.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
from kivy.graphics import *
from kivy.uix.button import Button, Label
from random import randint
class PongPaddle(Widget):
score = NumericProperty(0)
orientation = ObjectProperty([0, 0])
color = ObjectProperty([0,0,0,1])
def bounce_ball(self, ball):
if self.collide_widget(ball):
vx, vy = ball.velocity
ball.color = self.color
ball.last_hit = int(self.custom_id)
if self.orientation[0] == 25:
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
else:
offset = (ball.center_x - self.center_x) / (self.width / 2)
bounced = Vector(vx, -1 * vy)
vel = bounced * 1.1
ball.velocity = vel.x + offset, vel.y
class PongBall(Widget):
velocity_x = NumericProperty(0)
velocity_y = NumericProperty(0)
last_hit = 0
color = ObjectProperty([0,0,0,1])
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)
player3 = ObjectProperty(None)
player4 = ObjectProperty(None)
l = Label()
btn1 = Button(text='Restart')
win_game = 1
def start(self):
Clock.schedule_interval(self.update, 1.0 / 60.0)
def stop(self):
# Stop updating
Clock.unschedule(self.update)
def init(self):
## Setup players
self.player1.orientation = [25, 200]
self.player1.color = [1,0,0,1]
self.player1.score = 0
# Player 2
self.player2.orientation = [25, 200]
self.player2.color = [0,1,0,1]
self.player2.score = 0
# Player 3
self.player3.orientation = [200, 25]
self.player3.color = [0,0,1,1]
self.player3.score = 0
# Player 4
self.player4.orientation = [200, 25]
self.player4.color = [1,1,0,1]
self.player4.score = 0
def serve_ball(self):
# Ball velocity - Add 2 to avoid 0
vel = (randint(-8,6)+2, randint(-8,6)+2)
# Setup ball
self.ball.center = self.center
self.ball.velocity = vel
self.ball.last_hit = 0
self.ball.color = [1,1,1,1]
def update(self, dt):
self.ball.move()
#Bounce out the of paddles - Why do all check? Only can bounce on one any given time
self.player1.bounce_ball(self.ball)
self.player2.bounce_ball(self.ball)
self.player3.bounce_ball(self.ball)
self.player4.bounce_ball(self.ball)
#bounce ball off bottom or top - This is for 2 players game
# if (self.ball.y < self.y) or (self.ball.top > self.top):
# self.ball.velocity_y *= -1
# Went of any side? - Last hitter gets a goal
if self.ball.x < self.x or self.ball.x > self.width or self.ball.y < self.y or self.ball.y > self.height:
if self.ball.last_hit == 1:
self.player1.score += 1
elif self.ball.last_hit == 2:
self.player2.score += 1
elif self.ball.last_hit == 3:
self.player3.score += 1
elif self.ball.last_hit == 4:
self.player4.score += 1
self.serve_ball()
if self.player1.score >= self.win_game:
self.player_win(1)
elif self.player2.score >= self.win_game:
self.player_win(2)
elif self.player3.score >= self.win_game:
self.player_win(3)
elif self.player4.score >= self.win_game:
self.player_win(4)
def player_win(self, player_int):
# Remove Ball and players
self.clear_widgets()
# Configure Label and Btn
self.l.text ='Player ' + str(player_int) + ' Wins!!'
self.l.top = self.top-50
self.l.font_size = 50
self.l.center_x = self.width/2
self.btn1.bind(on_press=self.restart)
self.btn1.center_x = self.width/2
self.btn1.top = self.top/2
self.add_widget(self.l)
self.add_widget(self.btn1)
self.stop()
def on_touch_move(self, touch):
if touch.x < self.width / 3 and touch.y > self.height / 6 \
and touch.y < 5 * self.height/6:
self.player1.center_y = touch.y
if touch.x > self.width - self.width / 3 and touch.y > self.height / 6 \
and touch.y < 5 * self.height / 6:
self.player2.center_y = touch.y
if touch.y < self.height / 3 and touch.x > self.width / 6 \
and touch.x < 5 * self.width / 6:
self.player4.center_x = touch.x
if touch.y > 2* self.height / 3 and touch.x > self.width / 6 \
and touch.x < 5 * self.width / 6:
self.player3.center_x = touch.x
# Method update layout
def update_rect(instance, value):
instance.rect.pos = instance.pos
instance.rect.size = instance.size
def restart(self, instance):
# Remove btn and labels
self.clear_widgets()
# Add what I want
self.add_widget(self.ball)
self.add_widget(self.player1)
self.add_widget(self.player2)
self.add_widget(self.player3)
self.add_widget(self.player4)
self.init()
self.serve_ball()
self.start()
class PongApp(App):
def build(self):
game = PongGame()
game.init()
game.serve_ball()
game.start()
return game
if __name__ == '__main__':
PongApp().run()
pong.kv文件
#:kivy 1.0.9
<PongBall>:
size: 50, 50
canvas:
Color:
rgba: self.color[0], self.color[1], self.color[2], self.color[3]
Ellipse:
pos: self.pos
size: self.size
<PongPaddle>:
size: root.orientation[0], root.orientation[1]
canvas:
Color:
rgba: self.color[0], self.color[1], self.color[2], self.color[3]
Rectangle:
pos:self.pos
size:self.size
<PongGame>:
ball: pong_ball
player1: player_left
player2: player_right
player3: player_top
player4: player_bottom
canvas.before:
Rectangle:
pos: self.pos
size: self.size
source: 'black.jpg'
Label:
font_size: 15
center_x: root.width / 8
top: self.height*0.95
text: "P1: " + str(root.player1.score)
Label:
font_size: 15
center_x: root.width / 8
top: self.height*0.80
text: "P2: " + str(root.player2.score)
Label:
font_size: 15
center_x: root.width / 5
top: self.height*0.95
text: "P3: " + str(root.player3.score)
Label:
font_size: 15
center_x: root.width / 5
top: self.height*0.80
text: "P4: " + str(root.player4.score)
PongBall:
id: pong_ball
center: self.parent.center
PongPaddle:
id: player_left
custom_id: "1"
x: root.x
center_y: root.center_y
PongPaddle:
id: player_right
custom_id: "2"
x: root.width-self.width
center_y: root.center_y
PongPaddle:
id: player_top
custom_id: "3"
y: root.height - self.height
center_x: root.center_x
PongPaddle:
id: player_bottom
custom_id: "4"
y: root.y
center_x: root.center_x
答案 0 :(得分:1)
问题似乎不是时钟。 restart
方法被多次调用,似乎是因为每次调用on_press
时都会绑定init()
来电
如果将该行移动到__init__
函数,则只调用一次绑定,按钮仅在每次按下时调用一次重启,并且不会发生错误:
def __init__(self, **kwargs):
super(PongGame, self).__init__(**kwargs)
self.btn1.bind(on_press=self.restart)
答案 1 :(得分:0)
通过更改:
我发现了什么问题 def start(self):
Clock.schedule_interval(self.update, 1.0 / 60.0)
要:
def start(self):
Clock.unschedule(self.update)
Clock.schedule_interval(self.update, 1.0 / 60.0)
我不明白为什么需要这种改变,但似乎我在不同的线程中创建事件,也许有人可以更好地解释它。
答案 2 :(得分:0)
请参阅Kivy文档中的9.2.3触发器事件
有时您可能希望将某个函数安排为下一帧仅被调用一次,从而防止 重复通话。您可能会很想这样实现:
示例代码:
2.27
这种对触发器进行编程的方法非常昂贵,因为即使事件已经完成,您也总是会调用未安排的时间。此外,每次都会创建一个新事件。改用触发器:
provider "aws" {
version = "2.27.0"
}
每次调用trigger()时,都会安排一次回调调用。如果已经安排了,则不会重新安排。