[Python] Collision Changed in Kivy Due to Using ScreenManager

Discussão em 'Python' iniciado por Stack, Agosto 31, 2025.

  1. Stack

    Stack Membro Participativo

    I am attempting to use Kivy to modify the example Pong game to have a main menu. It took me ages, but I finally got the menu system to work and start the game object itself in a new screen. However, this has broken the graphics, and I cannot for the life of me figure out how to restore them. The collision between the ball and paddles still works, but it is badly offset. I understand that this has something to do with the fact that the ScreenManager uses a relative layout, where the default widget I was using before introducing screens was absolute. However, this page describes the exact problem I'm having, where the paddles and ball are offset from their intended center, but the proposed solution of setting pos: 0,0 or just removing pos altogether doesn't help, it just puts everything in the bottom left corner of the screen, and now nothing moves.

    I've tried many solutions involving size and position hinting, but in the end, they all break my game completely. The code provided below is my initial starting code, which is still the most functional of everything I've tried.

    Please keep in mind that I'm relatively new to Python and still experimenting with Kivy.

    Edit: I nearly forgot to include a gif of the offset collision. GIF to incorrect play

    main.py

    from kivy.app import App
    from kivy.properties import NumericProperty, ReferenceListProperty, ObjectProperty
    from kivy.uix.screenmanager import Screen, ScreenManager, NoTransition
    from kivy.uix.widget import Widget
    from kivy.vector import Vector
    from kivy.clock import Clock

    class PongPaddle(Widget):
    score = NumericProperty(0)

    def bounce_ball(self, ball):
    if self.collide_widget(ball):
    vx, vy = ball.velocity
    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

    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)

    def serve_ball(self, vel=(4, 0)):
    self.ball.center = self.center
    self.ball.velocity = vel

    def update(self, dt):
    self.ball.move()

    self.player1.bounce_ball(self.ball)
    self.player2.bounce_ball(self.ball)

    if (self.ball.y < 0) or (self.ball.top > self.height):
    self.ball.velocity_y *= -1

    if self.ball.x < self.x:
    self.player2.score += 1
    self.serve_ball(vel=(4,0))
    if self.ball.x > self.width:
    self.player1.score += 1
    self.serve_ball(vel=(-4,0))

    def on_touch_move(self, touch):
    if touch.x < self.width / 3:
    self.player1.center_y = touch.y
    if touch.x > self.width - self.width / 3:
    self.player2.center_y = touch.y


    class PongScreen(Screen):
    def on_enter(self, *args):
    game = PongGame()
    self.add_widget(game)
    game.serve_ball()
    Clock.schedule_interval(game.update, 1 / 60)
    return game

    class PongMenu(Screen):
    pass

    class PongApp(App):
    def build(self):
    sm = ScreenManager(transition=NoTransition())
    sm.add_widget(PongMenu(name="menu"))
    sm.add_widget(PongScreen(name="game"))
    return sm


    if __name__ == "__main__":
    PongApp().run()


    pong.kv

    #:kivy 2.3.1

    <PongBall>:
    canvas:
    Ellipse:
    pos: self.pos
    size: 50, 50

    <PongPaddle>:
    canvas:
    Rectangle:
    pos: self.pos
    size: 25, 200

    <PongGame>:
    ball: pong_ball
    player1: player_left
    player2: player_right

    canvas:
    Rectangle:
    pos: self.center_x - 5, 0
    size: 10, self.height

    Label:
    font_size: 70
    center_x: root.width / 4
    top: root.top - 50
    text: str(root.player1.score)

    Label:
    font_size: 70
    center_x: root.width * 3 / 4
    top: root.top - 50
    text: str(root.player2.score)

    PongBall:
    id: pong_ball
    center: self.parent.center

    PongPaddle:
    id: player_left
    x: self.parent.x
    center_y: self.parent.center_y

    PongPaddle:
    id: player_right
    x: self.parent.width - self.width
    center_y: self.parent.center_y

    <PongMenu>:
    start_btn: button_start

    BoxLayout:
    orientation: 'vertical'

    Button:
    id: button_start
    text: "Start Game"
    markup: True
    width: 200
    height: 200
    on_press: root.manager.current = "game"

    Continue reading...

Compartilhe esta Página