Kivy - 添加和删除标签
Posted
技术标签:
【中文标题】Kivy - 添加和删除标签【英文标题】:Kivy - adding and removing labels 【发布时间】:2013-08-01 19:59:33 【问题描述】:我是 Kivy 的新手,找不到任何关于添加和删除标签的真正答案。我完成了 Pong 教程(您可能已经猜到了),并将其改编为 4 名玩家。现在,我正在尝试添加一个标签来显示文本Winner!
,并单击该文本以重新开始游戏。
到那里为止,它正在工作。问题是,我无法在新游戏开始后让标签再次消失。另外,我不明白格式 - 我似乎无法使我的标签更大或在面板中将其移动到更低的位置。
我将发布所有代码,因为希望您无论如何都想玩游戏(一旦它被修复),我很肯定有一种更好、更简洁的方式来添加和删除文本。
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.properties import NumericProperty, ReferenceListProperty,\
ObjectProperty
from kivy.vector import Vector
from kivy.clock import Clock
from random import randint
class PongPaddle(Widget):
score = NumericProperty(0)
orientation = ObjectProperty([0, 0])
can_move = ObjectProperty(0)
def bounce_ball(self, ball):
if self.collide_widget(ball):
vx, vy = ball.velocity
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)
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)
def initialize(self):
SCORE = 1
self.player1.orientation = [25, 200]
self.player2.orientation = [25, 200]
self.player3.orientation = [200, 25]
self.player4.orientation = [200, 25]
self.player1.score = SCORE
self.player2.score = SCORE
self.player3.score = SCORE
self.player4.score = SCORE
self.player1.can_move = 1
self.player2.can_move = 1
self.player3.can_move = 1
self.player4.can_move = 1
self.serve_ball()
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)
self.player3.bounce_ball(self.ball)
self.player4.bounce_ball(self.ball)
#bounce ball off bottom or top
if ((self.ball.y < self.y) and not self.player3.can_move) \
or ((self.ball.top > self.top) and not self.player4.can_move):
self.ball.velocity_y *= -1
if ((self.ball.x < self.x) and not self.player1.can_move) \
or ((self.ball.right > self.width) and not self.player2.can_move):
self.ball.velocity_x *= -1
#went off to a side to score point?
if self.ball.x < self.x and self.player1.can_move == 1:
self.player1.score -= 1
self.serve_ball(vel=(4, randint(1, 4)))
if self.player1.score <= 0:
self.player1.can_move = 0
elif self.ball.x > self.width and self.player2.can_move == 1:
self.player2.score -= 1
self.serve_ball(vel=(-4, randint(1, 4)))
if self.player2.score <= 0:
self.player2.can_move = 0
elif self.ball.y > self.height and self.player4.can_move == 1:
self.player4.score -= 1
self.serve_ball(vel = (randint(1, 4), -4))
if self.player4.score <= 0:
self.player4.can_move = 0
elif self.ball.y < self.y and self.player3.can_move == 1:
self.player3.score -= 1
self.serve_ball(vel = (randint(1, 4), 4))
if self.player3.score <= 0:
self.player3.can_move = 0
if self.player1.can_move + self.player2.can_move + \
self.player3.can_move + self.player4.can_move == 1:
self.ball.velocity = (0, 0)
global win_label
win_label = Label(size_hint=(None, None),
text='[ref=winner]Winner![/ref]',
markup=True, text_size=(70, None))
#win_label.texture_update()
win_label.pos = (self.width / 2, self.height / 2 - 70)
## win_label.size = win_label.texture_size[0] + 20, \
## win_label.texture_size[1] + 20
win_label.bind(on_ref_press=self.click_win_label)
win_label.texture_update()
self.add_widget(win_label)
def click_win_label(self, instance, value):
self.initialize()
self.remove_widget(win_label)
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 and self.player1.can_move:
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 and self.player2.can_move:
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 and self.player3.can_move:
self.player3.center_x = touch.x
if touch.y > 2* self.height / 3 and touch.x > self.width / 6 \
and touch.x < 5 * self.width / 6 and self.player4.can_move:
self.player4.center_x = touch.x
class PongApp(App):
def build(self):
game = PongGame()
game.initialize()
game.serve_ball()
Clock.schedule_interval(game.update, 1.0 / 60.0)
return game
if __name__ == '__main__':
PongApp().run()
还有.kv文件:
#:kivy 1.0.9
<PongBall>:
size: 50, 50
canvas:
Ellipse:
pos: self.pos
size: self.size
<PongPaddle>:
size: root.orientation[0], root.orientation[1]
canvas:
Rectangle:
pos:self.pos
size:self.size
<PongGame>:
ball: pong_ball
player1: player_left
player2: player_right
player3: player_top
player4: player_bottom
Label:
font_size: 50
center_x: root.width / 6
top: root.top - root.height / 2 + 50
text: str(root.player1.score)
Label:
font_size: 50
center_x: root.width * 5 / 6
top: root.top - root.height / 2 + 50
text: str(root.player2.score)
Label:
font_size: 50
center_x: root.width / 2
top: root.height / 6
text: str(root.player3.score)
Label:
font_size: 50
center_x: root.width / 2
top: 5 * root.height / 6
text: str(root.player4.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
PongPaddle:
id: player_top
y: root.y
center_x: root.center_x
PongPaddle:
id: player_bottom
y: root.height - self.height
center_x: root.center_x
【问题讨论】:
【参考方案1】:Label
正在被删除,问题是你添加了无数个 :) 因为更新方法计划在这里每 1/60 秒调用一次:
Clock.schedule_interval(game.update, 1.0 / 60.0)
如果不是您的计算机会死机,您需要在添加小部件之前取消计划:
Clock.unschedule(self.update)
下面的代码有效。我想建议不要使用全局变量(这只是一个非常糟糕的做法)。我也修改了那个。对于这种情况,您甚至不需要类属性,因为参数instance
包含与self.win_label
完全相同的内容。另外,我改变了你的居中方式(self.win_label.center = self.center
)。最后,使用[Button][1]
而不是Label
会更容易,因为您可以绑定其他方法,例如on_press
或on_release
。实际上,您不需要为此提供ref
。你可以简单地绑定on_touch_down
。
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.properties import NumericProperty, ReferenceListProperty,\
ObjectProperty
from kivy.vector import Vector
from kivy.clock import Clock
from random import randint
class PongPaddle(Widget):
score = NumericProperty(0)
orientation = ObjectProperty([0, 0])
can_move = ObjectProperty(0)
def bounce_ball(self, ball):
if self.collide_widget(ball):
vx, vy = ball.velocity
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)
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)
def initialize(self):
SCORE = 1
self.player1.orientation = [25, 200]
self.player2.orientation = [25, 200]
self.player3.orientation = [200, 25]
self.player4.orientation = [200, 25]
self.player1.score = SCORE
self.player2.score = SCORE
self.player3.score = SCORE
self.player4.score = SCORE
self.player1.can_move = 1
self.player2.can_move = 1
self.player3.can_move = 1
self.player4.can_move = 1
self.serve_ball()
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)
self.player3.bounce_ball(self.ball)
self.player4.bounce_ball(self.ball)
#bounce ball off bottom or top
if ((self.ball.y < self.y) and not self.player3.can_move) \
or ((self.ball.top > self.top) and not self.player4.can_move):
self.ball.velocity_y *= -1
if ((self.ball.x < self.x) and not self.player1.can_move) \
or ((self.ball.right > self.width) and not self.player2.can_move):
self.ball.velocity_x *= -1
#went off to a side to score point?
if self.ball.x < self.x and self.player1.can_move == 1:
self.player1.score -= 1
self.serve_ball(vel=(4, randint(1, 4)))
if self.player1.score <= 0:
self.player1.can_move = 0
elif self.ball.x > self.width and self.player2.can_move == 1:
self.player2.score -= 1
self.serve_ball(vel=(-4, randint(1, 4)))
if self.player2.score <= 0:
self.player2.can_move = 0
elif self.ball.y > self.height and self.player4.can_move == 1:
self.player4.score -= 1
self.serve_ball(vel = (randint(1, 4), -4))
if self.player4.score <= 0:
self.player4.can_move = 0
elif self.ball.y < self.y and self.player3.can_move == 1:
self.player3.score -= 1
self.serve_ball(vel = (randint(1, 4), 4))
if self.player3.score <= 0:
self.player3.can_move = 0
if self.player1.can_move + self.player2.can_move + \
self.player3.can_move + self.player4.can_move == 1:
self.ball.velocity = (0, 0)
Clock.unschedule(self.update)
self.win_label = Label(size_hint=(None, None),
text='[ref=winner]Winner![/ref]',
markup=True, font_size=70, color=[1,0,0,1])
#win_label.texture_update()
#self.win_label.pos = (self.width / 2, self.height / 2 - 70)
self.win_label.center = self.center
## win_label.size = win_label.texture_size[0] + 20, \
## win_label.texture_size[1] + 20
self.win_label.bind(on_ref_press=self.click_win_label)
self.win_label.texture_update()
self.add_widget(self.win_label)
def click_win_label(self, instance, value):
self.remove_widget(self.win_label)
#self.remove_widget(instance) # this should also work:
self.initialize()
Clock.schedule_interval(self.update, 1.0 / 60.0)
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 and self.player1.can_move:
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 and self.player2.can_move:
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 and self.player3.can_move:
self.player3.center_x = touch.x
if touch.y > 2* self.height / 3 and touch.x > self.width / 6 \
and touch.x < 5 * self.width / 6 and self.player4.can_move:
self.player4.center_x = touch.x
class PongApp(App):
def build(self):
game = PongGame()
game.initialize()
#game.serve_ball()
Clock.schedule_interval(game.update, 1.0 / 60.0)
return game
if __name__ == '__main__':
PongApp().run()
【讨论】:
非常感谢您的解释!今晚我才能尝试代码,但我很兴奋。您能否进一步解释一下“实际上,您不需要为此使用ref
。您可以简单地绑定on_touch_down
。”你指的是标签还是按钮?
任何 [Widget][kivy.org/docs/… 有 3 个事件:on_touch_down
、on_touch_move
和 on_touch_up
。 Button
和 Level
都继承自 Widget
。你可以这样做self.win_label.bind(on_touch_down=self.click_win_label)
。优点是您不必一定要点击Label
。您可以单击屏幕上的任意位置,游戏将重新启动。如果你想限制你可以使用collide_points。
还要注意 on_touch_down 只接收一个参数(触摸)而不是两个:instance
和value
,所以你必须在方法click_win_label
中反映这一点。除此之外,Button
有事件on_press
(和on_release
),它们与on_touch_down
和on_touch_up
类似,只是它们已经控制您专门单击Button
本身(可能使用方法collide_points
内部)。以上是关于Kivy - 添加和删除标签的主要内容,如果未能解决你的问题,请参考以下文章
如何在 kivy python 中的标签、文本输入和其他小部件中添加标题