Pygame矩形网格/碰撞

时间:2018-09-02 06:33:07

标签: python pygame

pygame 1.9.4-Python 2.7.15-Kali Linux 2018.2

我整理了一些旧的“平方根”益智游戏的游戏脚本。 我确定可以将它们更好地组合在一起(使用列表),但是我想知道是否以及如何将矩形锁定在网格上,以及使它们在发生任何碰撞时“停止”。感谢您的任何帮助,初学者可以肯定。目的是使红色方块到达底部中心...

import pygame

# --- constants --- (UPPER_CASE names)

SCREEN_WIDTH = 490
SCREEN_HEIGHT = 600
LINE_WIDTH = 10

#BLACK = (  0,   0,   0)
WHITE = (255, 255, 255)
RED   = (255,   0,   0)
BLACK = (0, 0, 0)
LIGHT_BROWN = (153, 102, 51)

FPS = 30

# --- classses --- (CamelCase names)

# empty

# --- functions --- (lower_case names)

# empty

# --- main ---

# - init -

pygame.init()

screen = pygame.display.set_mode((SCREEN_WIDTH+LINE_WIDTH, SCREEN_HEIGHT+LINE_WIDTH))
#screen_rect = screen.get_rect()

pygame.display.set_caption("Game Of Squares")

# - objects -

square = pygame.rect.Rect(150, 50, 200, 200)
square_draging = False

r1 = pygame.rect.Rect(40, 50, 100, 200)
r1_draging = False

r2 = pygame.rect.Rect(40, 260, 100, 200)
r2_draging = False

r3 = pygame.rect.Rect(360, 50, 100, 200)
r3_draging = False

r4 = pygame.rect.Rect(360, 260, 100, 200)
r4_draging = False

r5 = pygame.rect.Rect(150, 260, 200, 100)
r5_draging = False

s1 = pygame.rect.Rect(150, 370, 95, 95)
s1_draging = False

s2 = pygame.rect.Rect(255, 370, 95, 95)
s2_draging = False

s3 = pygame.rect.Rect(45, 470, 95, 95)
s3_draging = False

s4 = pygame.rect.Rect(360, 470, 95, 95)
s4_draging = False

# - mainloop -

clock = pygame.time.Clock()

running = True

while running:

    # -square

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

        elif event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:            
                if square.collidepoint(event.pos):
                    square_draging = True
                    mouse_x, mouse_y = event.pos
                    offset_x = square.x - mouse_x
                    offset_y = square.y - mouse_y

        elif event.type == pygame.MOUSEBUTTONUP:
            if event.button == 1:            
                square_draging = False

        elif event.type == pygame.MOUSEMOTION:
            if square_draging:
                mouse_x, mouse_y = event.pos
                square.x = mouse_x + offset_x
                square.y = mouse_y + offset_y

    if square.x > 290:
        square.x = 290
    if square.x < 10:
        square.x = 10
    if square.y > 400:
        square.y = 400
    if square.y < 10:
        square.y = 10

    #r1

        elif event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:            
                if r1.collidepoint(event.pos):
                    r1_draging = True
                    mouse_x, mouse_y = event.pos
                    offset_x = r1.x - mouse_x
                    offset_y = r1.y - mouse_y

        elif event.type == pygame.MOUSEBUTTONUP:
            if event.button == 1:            
                r1_draging = False

        elif event.type == pygame.MOUSEMOTION:
            if r1_draging:
                mouse_x, mouse_y = event.pos
                r1.x = mouse_x + offset_x
                r1.y = mouse_y + offset_y

    if r1.x > 390:
        r1.x = 390
    if r1.x < 10:
        r1.x = 10
    if r1.y > 400:
        r1.y = 400
    if r1.y < 10:
        r1.y = 10

    #r2

    elif event.type == pygame.MOUSEBUTTONDOWN:
        if event.button == 1:
            if r2.collidepoint(event.pos):
                r2_draging = True
                mouse_x, mouse_y = event.pos
                offset_x = r2.x - mouse_x
                offset_y = r2.y - mouse_y

        elif event.type == pygame.MOUSEBUTTONUP:
            if event.button == 1:            
                r2_draging = False

        elif event.type == pygame.MOUSEMOTION:
            if r2_draging:
                mouse_x, mouse_y = event.pos
                r2.x = mouse_x + offset_x
                r2.y = mouse_y + offset_y

    if r2.x > 390:
        r2.x = 390
    if r2.x < 10:
        r2.x = 10
    if r2.y > 395:
        r2.y = 395
    if r2.y < 10:
        r2.y = 10

    #r3

    elif event.type == pygame.MOUSEBUTTONDOWN:
        if event.button == 1:
            if r3.collidepoint(event.pos):
                r3_draging = True
                mouse_x, mouse_y = event.pos
                offset_x = r3.x - mouse_x
                offset_y = r3.y - mouse_y

        elif event.type == pygame.MOUSEBUTTONUP:
            if event.button == 1:            
                r3_draging = False

        elif event.type == pygame.MOUSEMOTION:
            if r3_draging:
                mouse_x, mouse_y = event.pos
                r3.x = mouse_x + offset_x
                r3.y = mouse_y + offset_y

    if r3.x > 390:
        r3.x = 390
    if r3.x < 10:
        r3.x = 10
    if r3.y > 400:
        r3.y = 400
    if r3.y < 10:
        r3.y = 10

    #r4

    elif event.type == pygame.MOUSEBUTTONDOWN:
        if event.button == 1:
            if r4.collidepoint(event.pos):
                r4_draging = True
                mouse_x, mouse_y = event.pos
                offset_x = r4.x - mouse_x
                offset_y = r4.y - mouse_y

        elif event.type == pygame.MOUSEBUTTONUP:
            if event.button == 1:            
                r4_draging = False

        elif event.type == pygame.MOUSEMOTION:
            if r4_draging:
                mouse_x, mouse_y = event.pos
                r4.x = mouse_x + offset_x
                r4.y = mouse_y + offset_y

    if r4.x > 390:
        r4.x = 390
    if r4.x < 10:
        r4.x = 10
    if r4.y > 395:
        r4.y = 395
    if r4.y < 10:
        r4.y = 10

    #r5

    elif event.type == pygame.MOUSEBUTTONDOWN:
        if event.button == 1:
            if r5.collidepoint(event.pos):
                r5_draging = True
                mouse_x, mouse_y = event.pos
                offset_x = r5.x - mouse_x
                offset_y = r5.y - mouse_y

        elif event.type == pygame.MOUSEBUTTONUP:
            if event.button == 1:            
                r5_draging = False

        elif event.type == pygame.MOUSEMOTION:
            if r5_draging:
                mouse_x, mouse_y = event.pos
                r5.x = mouse_x + offset_x
                r5.y = mouse_y + offset_y

    if r5.x > 290:
        r5.x = 290
    if r5.x < 10:
        r5.x = 10
    if r5.y > 500:
        r5.y = 500
    if r5.y < 10:
        r5.y = 10

    #s1

    elif event.type == pygame.MOUSEBUTTONDOWN:
        if event.button == 1:
            if s1.collidepoint(event.pos):
                s1_draging = True
                mouse_x, mouse_y = event.pos
                offset_x = s1.x - mouse_x
                offset_y = s1.y - mouse_y

        elif event.type == pygame.MOUSEBUTTONUP:
            if event.button == 1:            
                s1_draging = False

        elif event.type == pygame.MOUSEMOTION:
            if s1_draging:
                mouse_x, mouse_y = event.pos
                s1.x = mouse_x + offset_x
                s1.y = mouse_y + offset_y

    if s1.x > 395:
        s1.x = 395
    if s1.x < 10:
        s1.x = 10
    if s1.y > 505:
        s1.y = 505
    if s1.y < 10:
        s1.y = 10

    #s2

    elif event.type == pygame.MOUSEBUTTONDOWN:
        if event.button == 1:
            if s2.collidepoint(event.pos):
                s2_draging = True
                mouse_x, mouse_y = event.pos
                offset_x = s2.x - mouse_x
                offset_y = s2.y - mouse_y

        elif event.type == pygame.MOUSEBUTTONUP:
            if event.button == 1:            
                s2_draging = False

        elif event.type == pygame.MOUSEMOTION:
            if s2_draging:
                mouse_x, mouse_y = event.pos
                s2.x = mouse_x + offset_x
                s2.y = mouse_y + offset_y

    if s2.x > 395:
        s2.x = 395
    if s2.x < 10:
        s2.x = 10
    if s2.y > 505:
        s2.y = 505
    if s2.y < 10:
        s2.y = 10

    #s3

    elif event.type == pygame.MOUSEBUTTONDOWN:
        if event.button == 1:
            if s3.collidepoint(event.pos):
                s3_draging = True
                mouse_x, mouse_y = event.pos
                offset_x = s3.x - mouse_x
                offset_y = s3.y - mouse_y

        elif event.type == pygame.MOUSEBUTTONUP:
            if event.button == 1:            
                s3_draging = False

        elif event.type == pygame.MOUSEMOTION:
            if s3_draging:
                mouse_x, mouse_y = event.pos
                s3.x = mouse_x + offset_x
                s3.y = mouse_y + offset_y

    if s3.x > 395:
        s3.x = 395
    if s3.x < 10:
        s3.x = 10
    if s3.y > 505:
        s3.y = 505
    if s3.y < 10:
        s3.y = 10

    #s4

    elif event.type == pygame.MOUSEBUTTONDOWN:
        if event.button == 1:
            if s4.collidepoint(event.pos):
                s4_draging = True
                mouse_x, mouse_y = event.pos
                offset_x = s4.x - mouse_x
                offset_y = s4.y - mouse_y

        elif event.type == pygame.MOUSEBUTTONUP:
            if event.button == 1:            
                s4_draging = False

        elif event.type == pygame.MOUSEMOTION:
            if s4_draging:
                mouse_x, mouse_y = event.pos
                s4.x = mouse_x + offset_x
                s4.y = mouse_y + offset_y

    if s4.x > 395:
        s4.x = 395
    if s4.x < 10:
        s4.x = 10
    if s4.y > 505:
        s4.y = 505
    if s4.y < 10:
        s4.y = 10


    # - updates (without draws) -

    # empty

    # - draws (without updates) -

    screen.fill(BLACK)

    pygame.draw.rect(screen, WHITE, [0,0,SCREEN_WIDTH,LINE_WIDTH])
    # bottom line
    pygame.draw.rect(screen, WHITE, [0,SCREEN_HEIGHT,SCREEN_WIDTH,LINE_WIDTH])
    # left line
    pygame.draw.rect(screen, WHITE, [0,0,LINE_WIDTH, SCREEN_HEIGHT])
    # right line
    pygame.draw.rect(screen, WHITE, [SCREEN_WIDTH,0,LINE_WIDTH, SCREEN_HEIGHT+LINE_WIDTH])

    #Draw Stuffs
    pygame.draw.rect(screen, RED, square)
    pygame.draw.rect(screen, LIGHT_BROWN, r1)
    pygame.draw.rect(screen, LIGHT_BROWN, r2)
    pygame.draw.rect(screen, LIGHT_BROWN, r3)
    pygame.draw.rect(screen, LIGHT_BROWN, r4)
    pygame.draw.rect(screen, LIGHT_BROWN, r5)
    pygame.draw.rect(screen, LIGHT_BROWN, s1)
    pygame.draw.rect(screen, LIGHT_BROWN, s2)
    pygame.draw.rect(screen, LIGHT_BROWN, s3)
    pygame.draw.rect(screen, LIGHT_BROWN, s4)
    pygame.display.flip()

    # - constant game speed / FPS -

    clock.tick(FPS)

# - end -

pygame.quit()

1 个答案:

答案 0 :(得分:2)

程序中有很多重复,并且事件不应在while中处理,而应在事件循环中处理。我将所有矩形放入列表,并在for循环中绘制和更新它们。

要选择一个rect,只需在这些rect上循环并将冲突的rect分配给一个变量(在下面的示例中为selected)。当发生pygame.MOUSEMOTION事件时,您只需将event.rel(鼠标相对移动)添加到所选矩形的xy属性中即可。

我们需要分别沿x和y轴移动,以便能够处理与其他矩形的碰撞。如果所选矩形沿x轴移动并且与另一个矩形发生碰撞,我们可以将其rightleft的坐标设置为碰撞的leftright的坐标直肠然后,我们可以对y轴执行相同的操作,并设置topbottom坐标。

对于边界,我将使用与屏幕大小相同的矩形,并将其缩小一点(使用pygame.Rect.inflate),以得到较小的矩形用于边界检查。

import pygame


LINE_WIDTH = 10

WHITE = (255, 255, 255)
RED   = (255,   0,   0)
BLACK = (0, 0, 0)
LIGHT_BROWN = (153, 102, 51)

FPS = 30

pygame.init()
screen = pygame.display.set_mode((490+LINE_WIDTH, 600+LINE_WIDTH))
clock = pygame.time.Clock()
screen_rect = screen.get_rect()
boundary = screen_rect.inflate((-21, -21))
boundary.move_ip(1, 1)

# Keep the square as a separate variable, so that we can
# draw it with a different color.
square = pygame.rect.Rect(150, 50, 200, 200)
# Put all rects (the square as well) into a list.
rects = [
    pygame.rect.Rect(40, 50, 100, 200),
    pygame.rect.Rect(40, 260, 100, 200),
    pygame.rect.Rect(360, 50, 100, 200),
    pygame.rect.Rect(360, 260, 100, 200),
    pygame.rect.Rect(150, 260, 200, 100),
    pygame.rect.Rect(150, 370, 95, 95),
    pygame.rect.Rect(255, 370, 95, 95),
    pygame.rect.Rect(45, 470, 95, 95),
    pygame.rect.Rect(360, 470, 95, 95),
    square,
    ]

selected = None  # The currently selected rect.

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:
                for rect in rects:
                    if rect.collidepoint(event.pos):
                        selected = rect  # Select the colliding rect.
        elif event.type == pygame.MOUSEBUTTONUP:
            if event.button == 1:
                selected = None  # Deselect the rect.
        elif event.type == pygame.MOUSEMOTION:
            if selected:  # Move the selected rect.
                # Move along the x-axis first.
                selected.x += event.rel[0]
                selected.clamp_ip(boundary)

                for rect in rects:
                    # Skip the selected rect.
                    if rect is not selected and selected.colliderect(rect):
                        # Set the selected rect's position if it collides
                        # with another rect.
                        if event.rel[0] > 0:
                            selected.right = rect.left
                        elif event.rel[0] < 0:
                            selected.left = rect.right

                # Do the same as above for the y-axis.
                selected.y += event.rel[1]
                selected.clamp_ip(boundary)

                for rect in rects:
                    if rect is not selected and selected.colliderect(rect):
                        if event.rel[1] < 0:
                            selected.top = rect.bottom
                        elif event.rel[1] > 0:
                            selected.bottom = rect.top

    screen.fill(BLACK)
    pygame.draw.rect(screen, WHITE, screen_rect, 20)  # Boundary.
    # Draw the rects.
    for rect in rects:
        pygame.draw.rect(screen, LIGHT_BROWN, rect)
    pygame.draw.rect(screen, RED, square)  # Draw the red square separately.

    pygame.display.flip()
    clock.tick(FPS)

pygame.quit()