实际上,我正在开发一种游戏应用程序,在该应用程序中,我希望球在球的运动90度方向上被矩形偏转。在下面的代码中,我正在完成任务,但是并没有达到预期的效果。单击下面的按钮时,球形小部件将与矩形小部件碰撞,然后首先与矩形小部件一起滑动,然后沿所需的方向偏转。我只想使其逼真,因为球应该通过与矩形小部件碰撞而在一个点上发生偏转。尝试执行下面的代码,以了解更多我想要实现的目标以及遇到的问题,因为这很难解释。请帮助!
from kivy.app import App
from kivy.graphics import Rotate, Rectangle, Ellipse, Color
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, CardTransition
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty,
NumericProperty,ReferenceListProperty, ListProperty, BooleanProperty
from kivy.uix.floatlayout import FloatLayout
from kivy.clock import Clock
from kivy.vector import Vector
from kivy.graphics.context_instructions import PopMatrix, PushMatrix
Builder.load_string('''
<PongBall>:
size: 50, 50
canvas:
Color:
rgba: 0,0,1,1
Ellipse:
pos: self.pos
size: self.size
<Game>:
ball: pong_ball
object: Object
FloatLayout:
Button:
pos_hint:{"x":2.6,"y":0}
size_hint: 3, 1
text:"Throw"
background_color: 2,1,190,1
border: 30,30,30,30
on_release:
root.start()
Button:
pos_hint:{'x':7.3, 'y':5.3}
size_hint: 0.5,0.5
text:'restart'
on_release:
root.serve_ball()
PongBall:
id: pong_ball
center: self.center
Object:
id: Object
center: self.rotate_origin
<Game1>:
ball: pong_ball
object1: Object1
object2: Object2
FloatLayout:
Button:
pos_hint:{"x":2.6,"y":0}
size_hint: 3, 1
text:"Throw"
background_color: 2,1,190,1
border: 30,30,30,30
on_release:
root.start()
Button:
pos_hint:{'x':7.3, 'y':5.3}
size_hint: 0.5,0.5
text:'restart'
on_release:
root.serve_ball()
PongBall:
id: pong_ball
center: self.center
Object1:
id: Object1
center: self.rotate_origin
Object2:
id: Object2
center: self.rotate_origin
<Manager>:
id: screen_manager
Screen:
name:"P"
FloatLayout:
Button:
pos_hint:{"x":0.2,"y":0.05}
size_hint: 0.6, 0.2
font_size: (root.width**2 + root.height**2) / 13**4
text: "Play"
background_color: 255,0,1,1
on_release:
root.transition.direction = "up";s3.serve_ball()
root.current = "again"
Screen:
name: 'again'
Game1:
id:s3
''')
class Object1(Widget):
def __init__(self, *args, **kwargs):
Widget.__init__(self, *args, **kwargs)
self.rect_pos_x = 500
self.rect_pos_y = 370
self.rect_pos = self.rect_pos_x, self.rect_pos_y
self.rect_width = 200
self.rect_height = 30
self.rect_size = self.rect_width, self.rect_height
self.rotate_origin_x = self.rect_pos_x + self.rect_width / 2
self.rotate_origin_y = self.rect_pos_y + self.rect_height / 2
self.rotate_origin = self.rotate_origin_x, self.rotate_origin_y
self.angle = 135
print('rect 1')
with self.canvas:
PushMatrix()
Rotate(origin=self.rotate_origin, angle=self.angle)
Color(rgb=(0,197,68))
Rectangle(pos=self.rect_pos, size=self.rect_size)
PopMatrix()
def rotate(self):
self.canvas.clear()
self.angle += 90
if (self.angle > 315):
self.angle = 225
with self.canvas:
Rotate(origin=self.rotate_origin, angle=self.angle)
Color(rgb=(0, 255, 100))
Rectangle(pos=self.rect_pos, size=self.rect_size)
def deflect_ball(self, ball):
if self.collide_widget(ball):
if not ball.collided:
vx, vy = ball.velocity
if self.angle == 135:
ball.velocity = Vector(-vx, vy).rotate(90)
if self.angle == 225:
ball.velocity = Vector(-vx, vy).rotate(270)
if self.angle == 315:
ball.velocity = Vector(-vx, vy).rotate(90)
ball.collided = True
else:
ball.collided = False
def on_touch_up(self, touch):
if self.collide_point(*touch.pos):
self.rotate()
print(self.angle)
class Object2(Widget):
def __init__(self, *args, **kwargs):
Widget.__init__(self, *args, **kwargs)
self.rect_pos_x = 500
self.rect_pos_y = 170
self.rect_pos = self.rect_pos_x, self.rect_pos_y
self.rect_width = 200
self.rect_height = 30
self.rect_size = self.rect_width, self.rect_height
self.rotate_origin_x = self.rect_pos_x + self.rect_width / 2
self.rotate_origin_y = self.rect_pos_y + self.rect_height / 2
self.rotate_origin = self.rotate_origin_x, self.rotate_origin_y
self.angle = 135
print('rect 1')
with self.canvas:
PushMatrix()
Rotate(origin=self.rotate_origin, angle=self.angle)
Color(rgb=(0,197,68))
Rectangle(pos=self.rect_pos, size=self.rect_size)
PopMatrix()
def rotate(self):
self.canvas.clear()
self.angle += 90
if (self.angle > 315):
self.angle = 225
with self.canvas:
PushMatrix()
Rotate(origin=self.rotate_origin, angle=self.angle)
Color(rgb=(0, 255, 100))
Rectangle(pos=self.rect_pos, size=self.rect_size)
PopMatrix()
def deflect_ball(self, ball):
if self.collide_widget(ball):
if not ball.collided:
vx, vy = ball.velocity
if self.angle == 135:
ball.velocity = Vector(-vx, vy).rotate(90)
if self.angle == 225:
ball.velocity = Vector(-vx, vy).rotate(270)
if self.angle == 315:
ball.velocity = Vector(-vx, vy).rotate(90)
ball.collided = True
else:
ball.collided = False
def on_touch_up(self, touch):
if self.collide_point(*touch.pos):
self.rotate()
print(self.angle)
class PongBall(Widget):
velocity_x = NumericProperty(0)
velocity_y = NumericProperty(0)
velocity = ReferenceListProperty(velocity_x, velocity_y)
collided = BooleanProperty(None)
def move(self):
self.pos = Vector(*self.velocity) + self.pos
class Game1(Widget):
ball = ObjectProperty(None)
object1 = ObjectProperty(None)
object2 = ObjectProperty(None)
def start(self):
Clock.schedule_interval(self.update, 1.0 / 60.0)
def serve_ball(self, vel=(5, 0)):
Clock.unschedule(self.update)
self.ball.center = 40, 380
self.ball.velocity = vel
def update(self, dt):
self.ball.move()
self.object1.deflect_ball(self.ball)
self.object2.deflect_ball(self.ball)
if (self.ball.y < self.y+50) or self.ball.x <0:
self.ball.velocity_y = 0
Clock.unschedule(self.update)
print('tested')
self.serve_ball()
class Manager(ScreenManager):
pass
sm = Manager()
class ScreensApp(App):
def build(self):
return sm
if __name__ == '__main__':
ScreensApp().run()
问题是,在检测到碰撞并且改变了球的速度之后,下一个update
并没有将球移动足够远,以至于collide_widget()
方法无法返回False
而不是True
。解决该问题的一种方法是为collided
保留PongBall
属性,该属性可用于避免多次碰撞。因此,您可以将BooleanProperty
添加到PongBall
中,如下所示:
collided = BooleanProperty(False)
并将deflect_ball
修改为:
def deflect_ball(self, ball):
if self.collide_widget(ball):
if not ball.collided:
vx, vy = ball.velocity
if self.angle == 135 :
ball.velocity = Vector(-vx, vy).rotate(90)
if self.angle == 225:
ball.velocity = Vector(-vx, vy).rotate(270)
if self.angle == 315:
ball.velocity = Vector(-vx, vy).rotate(90)
ball.collided = True
else:
ball.collided = False