На самом деле я работаю над одним игровым приложением, в котором я хочу, чтобы мяч отклонялся прямоугольником в направлении движения шара на 90 градусов. В приведенном ниже коде я выполняю задачу, но это не так, как хотелось бы. Виджет шара, когда нажата кнопка ниже, сталкивается с виджетом прямоугольника, и сначала он немного скользит вместе с ним, а затем отклоняется в нужном направлении. Я просто хочу сделать это реалистичным c, поскольку шар должен отклоняться виджетом прямоугольника, просто сталкиваясь с ним в одной точке. Попробуйте выполнить приведенный ниже код, чтобы лучше понять, чего я хочу достичь и с какой проблемой я сталкиваюсь, поскольку это немного сложно объяснить. Пожалуйста, помогите!
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()