How to make object collision in python kivy?

32 Views Asked by At

I want to create a Luckman breed of Pac-Man for Android for phones and tablets. But I can't make a collision for the labyrinth.

I tried to do it as in these files https://drive.google.com/file/d/1pwCDpU1UPzB7V7TV7-WmbyDLkpIDODry/view. But due to the fact that my labyrinth is located not as a picture but as a drawn object in the .kv file, nothing happened.

Here is my program code main.py

from kivy.app import App
from kivy.uix.screenmanager import Screen
from kivy.uix.widget import Widget
from kivy.uix.anchorlayout import AnchorLayout

from player import *
from kivy.clock import Clock

from kivy.core.window import Window

class GamePlay(Screen):
    width = Window.width
    height = Window.height

    pacman = Player()

    def __init__(self, **kwargs):
        super(GamePlay,self).__init__(**kwargs)

    def on_touch_down(self, touch):
        self.start_pos = touch.pos
        return True

    def on_touch_move(self, touch):
        # Calculate swipe distance and direction
        swipe_distance_x = abs(touch.pos[0] - self.start_pos[0])
        swipe_distance_y = abs(touch.pos[1] - self.start_pos[1])
        swipe_threshold = 50  # Adjust threshold based on your needs

        # Detect swipe directions
        if swipe_distance_y > swipe_threshold:
            if touch.pos[1] > self.start_pos[1]:
                self.pacman.velocity = (0, 1)
                self.pacman.number_update_pac_img = "up"
            else:
                self.pacman.velocity = (0, -1)
                self.pacman.number_update_pac_img = "down"
        elif swipe_distance_x > swipe_threshold:
            if touch.pos[0] > self.start_pos[0]:
                self.pacman.velocity = (1, 0)
                self.pacman.number_update_pac_img = "right"
            else:
                self.pacman.velocity = (-1, 0)
                self.pacman.number_update_pac_img = "left"

        return True

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

class LuckmanApp(App):
    def build(self):
        game = GamePlay()
        Clock.schedule_interval(game.update, 1.0/60.0)

        return game

if __name__ == '__main__':
    LuckmanApp().run()

luckman.kv

<Player>:
    Image:
        id: "pacman"
        source: root.pac_img
        allow_stretch: True
        pos: root.pos
        size: self.parent.width / 18, self.parent.height / 18

<GamePlay>:
    canvas:
        Rectangle:
            source: "png/bg.png"
            size: self.size
    
    pacman: pacman_player

    FloatLayout:
        # Верхний вход
        canvas:
            Color:
                rgb: [0, 0, 1]
            # Верхний вход - правая стенка
            Rectangle:
                pos: self.width / 1.79, self.height
                size: self.width / -43.2, self.height / -6
            # Верхний вход - левая стенка
            Rectangle:
                pos: self.width / 2.274, self.height
                size: self.width / 43.2, self.height / -6
            # Верхний левый квадрат стенок
            Rectangle:
                pos: self.width / 2.274, self.height / 1.2
                size: self.width / -15, self.height / 96
            Rectangle:
                pos: self.width / 2.52, self.height / 1.2
                size: self.width / -43.2, self.height / 8
            Rectangle:
                pos: self.width / 2.52, self.height / 1.055
                size: self.width / -2.85, self.height / 96
            Rectangle:
                pos: self.width / 15, self.height / 1.0444
                size: self.width / -43.2, self.height / -4.7
            Rectangle:
                pos: self.width / 23.1, self.height / 1.34
                size: self.width / 7.3, self.height / -96
            Rectangle:
                pos: self.width / 2.6, self.height / 1.34
                size: self.width / -7.7, self.height / -96
            Rectangle:
                pos: self.width / 2.68, self.height / 1.359
                size: self.width / 11, self.height / 16.2
            # Верхний левый средний квадрат 
            Rectangle:
                pos: self.width / 7.29, self.height / 1.0948
                size: self.width / 22, self.height / -7.6
            Rectangle:
                pos: self.width / 3.92, self.height / 1.0948
                size: self.width / 22, self.height / -7.6

            # Верхний правый квадрат стенок
            Rectangle:
                pos: self.width / 1.8, self.height / 1.2
                size: self.width / 15, self.height / 96
            Rectangle:
                pos: self.width / 1.631, self.height / 1.2
                size: self.width / 43.2, self.height / 8
            Rectangle:
                pos: self.width / 1.631, self.height / 1.055
                size: self.width / 2.85, self.height / 96
            Rectangle:
                pos: self.width / 1.06, self.height / 1.0444
                size: self.width / 43.2, self.height / -4.7
            Rectangle:
                pos: self.width / 1.035, self.height / 1.34
                size: self.width / -7.3, self.height / -96
            Rectangle:
                pos: self.width / 1.6043, self.height / 1.34
                size: self.width / 7.7, self.height / -96
            Rectangle:
                pos: self.width / 1.57, self.height / 1.359
                size: self.width / -10, self.height / 16.2
            # Верхний правый  средний квадрат 
            Rectangle:
                pos: self.width / 1.207, self.height / 1.0948
                size: self.width / 22, self.height / -7.6
            Rectangle:
                pos: self.width / 1.324, self.height / 1.0948
                size: self.width / -22, self.height / -7.6


            # Нижний вход - правая стенка
            Rectangle:
                pos: self.width / 1.79, self.height * 0
                size: self.width / -43.2, self.height / 6
            # Нижний вход - левая стенка
            Rectangle:
                pos: self.width / 2.274, self.height * 0
                size: self.width / 43.2, self.height / 6
            # Нижний левый квадрат стенок
            Rectangle:
                pos: self.width / 2.274, self.height / 6.4
                size: self.width / -15, self.height / 96
            Rectangle:
                pos: self.width / 2.52, self.height / 6
                size: self.width / -43.2, self.height / -8
            Rectangle:
                pos: self.width / 2.52, self.height / 24
                size: self.width / -2.85, self.height / 96
            Rectangle:
                pos: self.width / 15, self.height / 24
                size: self.width / -43.2, self.height / 4.7
            Rectangle:
                pos: self.width / 23.1, self.height / 3.8
                size: self.width / 7.25, self.height / -96
            Rectangle:
                pos: self.width / 2.6, self.height / 3.8
                size: self.width / -7.7, self.height / -96
            Rectangle:
                pos: self.width / 2.68, self.height / 3.8
                size: self.width / 11, self.height / -16.2
            #Нижний Левый средний квадрат 
            Rectangle:
                pos: self.width / 7.29, self.height / 4.61
                size: self.width / 22, self.height / -7.6
            Rectangle:
                pos: self.width / 3.92, self.height / 4.61
                size: self.width / 22, self.height / -7.6

            # Нижний правый квадрат стенок
            Rectangle:
                pos: self.width / 1.8, self.height / 6.4
                size: self.width / 15, self.height / 96
            Rectangle:
                pos: self.width / 1.631, self.height / 6
                size: self.width / 43.2, self.height / -8
            Rectangle:
                pos: self.width / 1.631, self.height / 24
                size: self.width / 2.85, self.height / 96
            Rectangle:
                pos: self.width / 1.06, self.height / 24
                size: self.width / 43.2, self.height / 4.7
            Rectangle:
                pos: self.width / 1.035, self.height / 3.8
                size: self.width / -7.25, self.height / -96
            Rectangle:
                pos: self.width / 1.6043, self.height / 3.8
                size: self.width / 7.6, self.height / -96
            Rectangle:
                id: stop
                pos: self.width / 1.57, self.height / 3.8
                size: self.width / -10, self.height / -16.2
            #Нижний правый средний квадрат 
            Rectangle:
                pos: self.width / 1.207, self.height / 4.61
                size: self.width / 22, self.height / -7.6
            Rectangle:
                pos: self.width / 1.324, self.height / 4.61
                size: self.width / -22, self.height / -7.6


            #Центральные стороны

            #Центральная левая горизонтальная стенка
            Rectangle:
                pos: self.width / 6.31, self.height / 1.34
                size: self.width / 43.2, self.height / -2.05

            #Центральная правая горизонтальная стенка
            Rectangle:
                pos: self.width / 1.208, self.height / 1.34
                size: self.width / 43.2, self.height / -2.05
            
            #Центальная верхняя стенка
            Rectangle:
                pos: self.width / 3.92, self.height / 1.43
                size: self.width / 2., self.height / -96

            #Центр спавна призраков
            Rectangle:
                pos: self.width / 2.68, self.height / 1.555
                size: self.width / 11, self.height / 96
            Rectangle:
                pos: self.width / 1.57, self.height / 1.555
                size: self.width / -10, self.height / 96
            Rectangle:
                pos: self.width / 2.68, self.height / 1.65
                size: self.width / 43.2, self.height / 27
            Rectangle:
                pos: self.width / 1.57, self.height / 1.65
                size: self.width / -43.2, self.height / 27
            Rectangle:
                pos: self.width / 2.68, self.height / 1.65
                size: self.width / 3.79, self.height / -96
                
            #Центальная средняя стенка
            Rectangle:
                pos: self.width / 3.92, self.height / 1.786
                size: self.width / 2, self.height / -96
                
            #Центральная правая вертекальная стенка
            Rectangle:
                pos: self.width / 1.324, self.height / 1.68
                size: self.width / -22, self.height / 17.5
            #Центральная левая вертекальная стенка
            Rectangle:
                pos: self.width / 3.92, self.height / 1.68
                size: self.width / 22, self.height / 17.5
                
            #Центальная левая нижняя стенка
            Rectangle:
                pos: self.width / 6.31, self.height / 1.945
                size: self.width / 3.25, self.height / -96
            #Центальняя правая нижняя стенка
            Rectangle:
                pos: self.width / 1.208, self.height / 1.945
                size: self.width / -3.5, self.height / -96
            #Центральний нижний квадрат
            Rectangle:
                pos: self.width / 3.92, self.height / 3.8
                size: self.width / 2, self.height / 4.85

        Player:
            id: pacman_player
            pos: self.width / 2.13, self.height / 5.7

player.py

from kivy.uix.widget import Widget
from kivy.properties import StringProperty, NumericProperty, ReferenceListProperty
from kivy.vector import Vector

class Player(Widget):    
    pac_img = StringProperty("png/pacman/pacman_down.gif")

    number_update_pac_img = "None"

    velocity_x = NumericProperty(0)
    velocity_y = NumericProperty(0)
    velocity = ReferenceListProperty(velocity_x, velocity_y)

    def move(self):
        self.pos = Vector(*self.velocity) + self.pos

        #update pacman gifts
        if self.number_update_pac_img == "up":
            self.pac_img = "png/pacman/pacman_up.gif"
        if self.number_update_pac_img == "down":
            self.pac_img = "png/pacman/pacman_down.gif"
        if self.number_update_pac_img == "left":
            self.pac_img = "png/pacman/pacman_left.gif"
        if self.number_update_pac_img == "right":
            self.pac_img = "png/pacman/pacman_right.gif"
1

There are 1 best solutions below

0
John Anderson On

If you use a Widget for each part of the labryinth, then you can use the collide_widget() method of Widget to detect collisions. Start by defining a class for rectangles:

class MyRectangle(Widget):
    def on_size(self, *args):
        # Make sure sizes are positive
        if self.width < 0:
            self.x += self.width
            self.width = -self.width
        if self.height < 0:
            self.y += self.height
            self.height = -self.height

The on_size() is just to insure that the sizes are greater than 0, since your canvas Rectangles have some negative sizes.

Then, rewrite your luckman.kv file to use MyRectangle classes instead of the canvas Rectangles like this:

<Player>:
    size_hint: None, None
    size: self.parent.width / 18, self.parent.height / 18
    Image:
        id: pacman
        source: root.pac_img
        allow_stretch: True
        pos: root.pos
        size: root.size

<GamePlay>:
    canvas:
        Rectangle:
            source: "png/bg.png"
            size: self.size
    
    pacman: pacman_player

    FloatLayout:
        id: flt
        # Верхний вход
        # canvas:
        #     Color:
        #         rgb: [0, 0, 1]
        # Верхний вход - правая стенка
        MyRectangle:
            pos: flt.width / 1.79, flt.height
            size: flt.width / -43.2, flt.height / -6
        # Верхний вход - левая стенка
        MyRectangle:
            pos: flt.width / 2.274, flt.height
            size: flt.width / 43.2, flt.height / -6
        # Верхний левый квадрат стенок
        MyRectangle:
            pos: flt.width / 2.274, flt.height / 1.2
            size: flt.width / -15, flt.height / 96
        MyRectangle:
            pos: flt.width / 2.52, flt.height / 1.2
            size: flt.width / -43.2, flt.height / 8
        MyRectangle:
            pos: flt.width / 2.52, flt.height / 1.055
            size: flt.width / -2.85, flt.height / 96
        MyRectangle:
            pos: flt.width / 15, flt.height / 1.0444
            size: flt.width / -43.2, flt.height / -4.7
        MyRectangle:
            pos: flt.width / 23.1, flt.height / 1.34
            size: flt.width / 7.3, flt.height / -96
        MyRectangle:
            pos: flt.width / 2.6, flt.height / 1.34
            size: flt.width / -7.7, flt.height / -96
        MyRectangle:
            pos: flt.width / 2.68, flt.height / 1.359
            size: flt.width / 11, flt.height / 16.2
        # Верхний левый средний квадрат 
        MyRectangle:
            pos: flt.width / 7.29, flt.height / 1.0948
            size: flt.width / 22, flt.height / -7.6
        MyRectangle:
            pos: flt.width / 3.92, flt.height / 1.0948
            size: flt.width / 22, flt.height / -7.6

        # Верхний правый квадрат стенок
        MyRectangle:
            pos: flt.width / 1.8, flt.height / 1.2
            size: flt.width / 15, flt.height / 96
        MyRectangle:
            pos: flt.width / 1.631, flt.height / 1.2
            size: flt.width / 43.2, flt.height / 8
        MyRectangle:
            pos: flt.width / 1.631, flt.height / 1.055
            size: flt.width / 2.85, flt.height / 96
        MyRectangle:
            pos: flt.width / 1.06, flt.height / 1.0444
            size: flt.width / 43.2, flt.height / -4.7
        MyRectangle:
            pos: flt.width / 1.035, flt.height / 1.34
            size: flt.width / -7.3, flt.height / -96
        MyRectangle:
            pos: flt.width / 1.6043, flt.height / 1.34
            size: flt.width / 7.7, flt.height / -96
        MyRectangle:
            pos: flt.width / 1.57, flt.height / 1.359
            size: flt.width / -10, flt.height / 16.2
        # Верхний правый  средний квадрат 
        MyRectangle:
            pos: flt.width / 1.207, flt.height / 1.0948
            size: flt.width / 22, flt.height / -7.6
        MyRectangle:
            pos: flt.width / 1.324, flt.height / 1.0948
            size: flt.width / -22, flt.height / -7.6


        # Нижний вход - правая стенка
        MyRectangle:
            pos: flt.width / 1.79, flt.height * 0
            size: flt.width / -43.2, flt.height / 6
        # Нижний вход - левая стенка
        MyRectangle:
            pos: flt.width / 2.274, flt.height * 0
            size: flt.width / 43.2, flt.height / 6
        # Нижний левый квадрат стенок
        MyRectangle:
            pos: flt.width / 2.274, flt.height / 6.4
            size: flt.width / -15, flt.height / 96
        MyRectangle:
            pos: flt.width / 2.52, flt.height / 6
            size: flt.width / -43.2, flt.height / -8
        MyRectangle:
            pos: flt.width / 2.52, flt.height / 24
            size: flt.width / -2.85, flt.height / 96
        MyRectangle:
            pos: flt.width / 15, flt.height / 24
            size: flt.width / -43.2, flt.height / 4.7
        MyRectangle:
            pos: flt.width / 23.1, flt.height / 3.8
            size: flt.width / 7.25, flt.height / -96
        MyRectangle:
            pos: flt.width / 2.6, flt.height / 3.8
            size: flt.width / -7.7, flt.height / -96
        MyRectangle:
            pos: flt.width / 2.68, flt.height / 3.8
            size: flt.width / 11, flt.height / -16.2
        #Нижний Левый средний квадрат 
        MyRectangle:
            pos: flt.width / 7.29, flt.height / 4.61
            size: flt.width / 22, flt.height / -7.6
        MyRectangle:
            pos: flt.width / 3.92, flt.height / 4.61
            size: flt.width / 22, flt.height / -7.6

        # Нижний правый квадрат стенок
        MyRectangle:
            pos: flt.width / 1.8, flt.height / 6.4
            size: flt.width / 15, flt.height / 96
        MyRectangle:
            pos: flt.width / 1.631, flt.height / 6
            size: flt.width / 43.2, flt.height / -8
        MyRectangle:
            pos: flt.width / 1.631, flt.height / 24
            size: flt.width / 2.85, flt.height / 96
        MyRectangle:
            pos: flt.width / 1.06, flt.height / 24
            size: flt.width / 43.2, flt.height / 4.7
        MyRectangle:
            pos: flt.width / 1.035, flt.height / 3.8
            size: flt.width / -7.25, flt.height / -96
        MyRectangle:
            pos: flt.width / 1.6043, flt.height / 3.8
            size: flt.width / 7.6, flt.height / -96
        MyRectangle:
            id: stop
            pos: flt.width / 1.57, flt.height / 3.8
            size: flt.width / -10, flt.height / -16.2
        #Нижний правый средний квадрат 
        MyRectangle:
            pos: flt.width / 1.207, flt.height / 4.61
            size: flt.width / 22, flt.height / -7.6
        MyRectangle:
            pos: flt.width / 1.324, flt.height / 4.61
            size: flt.width / -22, flt.height / -7.6


        #Центральные стороны

        #Центральная левая горизонтальная стенка
        MyRectangle:
            pos: flt.width / 6.31, flt.height / 1.34
            size: flt.width / 43.2, flt.height / -2.05

        #Центральная правая горизонтальная стенка
        MyRectangle:
            pos: flt.width / 1.208, flt.height / 1.34
            size: flt.width / 43.2, flt.height / -2.05
        
        #Центальная верхняя стенка
        MyRectangle:
            pos: flt.width / 3.92, flt.height / 1.43
            size: flt.width / 2., flt.height / -96

        #Центр спавна призраков
        MyRectangle:
            pos: flt.width / 2.68, flt.height / 1.555
            size: flt.width / 11, flt.height / 96
        MyRectangle:
            pos: flt.width / 1.57, flt.height / 1.555
            size: flt.width / -10, flt.height / 96
        MyRectangle:
            pos: flt.width / 2.68, flt.height / 1.65
            size: flt.width / 43.2, flt.height / 27
        MyRectangle:
            pos: flt.width / 1.57, flt.height / 1.65
            size: flt.width / -43.2, flt.height / 27
        MyRectangle:
            pos: flt.width / 2.68, flt.height / 1.65
            size: flt.width / 3.79, flt.height / -96
            
        #Центальная средняя стенка
        MyRectangle:
            pos: flt.width / 3.92, flt.height / 1.786
            size: flt.width / 2, flt.height / -96
            
        #Центральная правая вертекальная стенка
        MyRectangle:
            pos: flt.width / 1.324, flt.height / 1.68
            size: flt.width / -22, flt.height / 17.5
        #Центральная левая вертекальная стенка
        MyRectangle:
            pos: flt.width / 3.92, flt.height / 1.68
            size: flt.width / 22, flt.height / 17.5
            
        #Центальная левая нижняя стенка
        MyRectangle:
            pos: flt.width / 6.31, flt.height / 1.945
            size: flt.width / 3.25, flt.height / -96
        #Центальняя правая нижняя стенка
        MyRectangle:
            pos: flt.width / 1.208, flt.height / 1.945
            size: flt.width / -3.5, flt.height / -96
        #Центральний нижний квадрат
        MyRectangle:
            pos: flt.width / 3.92, flt.height / 3.8
            size: flt.width / 2, flt.height / 4.85

        Player:
            id: pacman_player
            pos: flt.width / 2.13, flt.height / 5.7
            
<MyRectangle>:
    size_hint: None, None
    canvas:
        Color:
            rgb: [0, 0, 1]
        Rectangle:
            pos: root.pos
            size: root.size

Note that the size of the Player is defined in the kv, and the Image uses the same size. This is important for the collide_widget() method.

Also, the FloatLayout now has an id for easy reference. The canvas instructions are replaced by MyRectangle instances, and the <MyRectangle> rule does the canvas instruction for each instance of MyRectangle.

Now the update() method can be modified to detect collisions:

def update(self, _dt):
    self.pacman.move()
    flt = self.ids.flt
    for w in flt.children:
        if w == self.pacman:
            continue
        if w.collide_widget(self.pacman):
            print('collision:', w.pos, w.size, self.pacman.pos, self.pacman.size)
            return