Я работаю над одним игровым приложением, в котором мне нужно, чтобы виджет шара отклонялся под углом 90 к направлению движения виджета прямоугольника после столкновения. В приведенном ниже коде мяч делает то, что я сказал выше, но он отклоняется на некоторое расстояние до столкновения с прямоугольником. Это было бы связано с функционированием в коде collide_widget (). Пожалуйста, помогите решить эту проблему!
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,
DictProperty
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 Object(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:
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 = DictProperty(False)
def move(self):
self.pos = Vector(*self.velocity) + self.pos
class Game(Widget):
ball = ObjectProperty(None)
object = 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.object.deflect_ball(self.ball)
if (self.ball.y < self.y+50) or self.ball.y > 500:
self.ball.velocity_y = 0
Clock.unschedule(self.update)
print('tested')
self.serve_ball()
sm.current= 'again'
class Object1(Widget):
def __init__(self, *args, **kwargs):
Widget.__init__(self, *args, **kwargs)
self.rect_pos_x = 500
self.rect_pos_y = 400
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[self]:
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[self] = True
else:
ball.collided[self] = 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[self]:
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[self] = True
else:
ball.collided[self] = False
def on_touch_up(self, touch):
if self.collide_point(*touch.pos):
self.rotate()
print(self.angle)
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()