如何使球小部件在矩形中被矩形小部件偏转?

问题描述 投票:-2回答:1

实际上,我正在开发一种游戏应用程序,在该应用程序中,我希望球在球的运动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()
python python-3.x kivy kivy-language
1个回答
0
投票

问题是,在检测到碰撞并且改变了球的速度之后,下一个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
© www.soinside.com 2019 - 2024. All rights reserved.