首页 > 解决方案 > 如何在 pygame 中正确使用遮罩?

问题描述

我一直在尝试用 pygame 制作一个汽车足球游戏,并且几乎完成了,但我想要一些关于进球得分和边界检测的帮助。如果球触网,我将无法发生任何事情(我尝试使用红色网。任何名称为“redsurf”的东西都是目标)。此外,当我试图让球和汽车从边缘反弹时,什么也没有发生,但球在开始时奇怪地移动了。“边界线”是我试图用来让球从侧面反弹的东西”。此外,我无法提高速度来工作,但不知道为什么。我真的希望有人可以帮助并编辑我的代码作品。

import pygame
from pygame.math import Vector2


pygame.init()
WIDTH = 1150
HEIGHT = 800
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()

bgImg = pygame.image.load("Football_pitch.png")
redsurf = pygame.Surface((50,125))
redsurf.fill((255,0,0))
redsurfpos = Vector2(50,125)
bluesurf = pygame.Surface((50,125))
bluesurf.fill((0,0,255))
bluesurfpos = Vector2(50,125)
borderline = pygame.draw.rect(screen, (0,0,0),[10,10,10,10],0)

BLUECAR_ORIGINAL = pygame.Surface((50, 30), pygame.SRCALPHA)
pygame.draw.polygon(
    BLUECAR_ORIGINAL, (0, 0, 255), [(0, 30), (50, 20), (50, 10), (0, 0)])
bluecar = BLUECAR_ORIGINAL
REDCAR_ORIGINAL = pygame.Surface((50, 30), pygame.SRCALPHA)
pygame.draw.polygon(
    REDCAR_ORIGINAL, (255, 0, 0), [(0, 0), (50, 10), (50, 20), (0, 30)])
redcar = REDCAR_ORIGINAL

score = 0
redspeed = 7
bluespeed = 7
ball_x = 575
ball_y = 400
dx = 1
dy = 0

BALL = pygame.Surface((30, 30), pygame.SRCALPHA)
pygame.draw.circle(BALL, [0,0,0], [15, 15], 15)

ball_pos = Vector2(ball_x, ball_y)
ballrect = BALL.get_rect(center=ball_pos)
redsurfrect = redsurf.get_rect(center=redsurfpos)
bluesurfrect = redsurf.get_rect(center=bluesurfpos)
ball_vel = Vector2(dx, dy)

pos_red = Vector2(1000,370)
vel_red = Vector2(redspeed,0)
redrect = redcar.get_rect(center=pos_red)
redangle = 0
pos_blue = Vector2(70,70)
vel_blue = Vector2(bluespeed,0)
bluerect = bluecar.get_rect(center=pos_red)
blueangle = 0

mask_blue = pygame.mask.from_surface(bluecar)
mask_red = pygame.mask.from_surface(redcar)
mask_ball = pygame.mask.from_surface(BALL)
mask_redsurfgoal = pygame.mask.from_surface(redsurf)
mask_bluesurfgoal = pygame.mask.from_surface(bluesurf)


run = True
while run:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False




    ball_x += dx
    ball_y += dy

    if ball_y<0 or ball_y>HEIGHT - 40:
        dy *= -1
    if ball_x<0 or ball_x>WIDTH  - 40:
        dx *= -1

    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT]:
        redangle += 5
        vel_red.rotate_ip(-5)
        redcar = pygame.transform.rotate(REDCAR_ORIGINAL, redangle)
        redrect = redcar.get_rect(center=redrect.center)

        mask_red = pygame.mask.from_surface(redcar)
    elif keys[pygame.K_RIGHT]:
        redangle -= 5
        vel_red.rotate_ip(5)
        redcar = pygame.transform.rotate(REDCAR_ORIGINAL, redangle)
        redrect = redcar.get_rect(center=redrect.center)
        mask_red = pygame.mask.from_surface(redcar)
    elif keys[pygame.K_l]:
        redspeed = 20


    if keys[pygame.K_a]:
        blueangle += 5
        vel_blue.rotate_ip(-5)
        bluecar = pygame.transform.rotate(BLUECAR_ORIGINAL, blueangle)
        bluerect = bluecar.get_rect(center=bluerect.center)
        mask_blue = pygame.mask.from_surface(bluecar)
    elif keys[pygame.K_d]:
        blueangle -= 5
        vel_blue.rotate_ip(5)
        bluecar = pygame.transform.rotate(BLUECAR_ORIGINAL, blueangle)
        bluerect = bluecar.get_rect(center=bluerect.center)
        mask_blue = pygame.mask.from_surface(bluecar)



    pos_red += vel_red
    redrect.center = pos_red
    pos_blue += vel_blue
    bluerect.center = pos_blue

    ball_vel *= .95  
    ball_pos += ball_vel
    ballrect.center = ball_pos


    offset_red = redrect[0] - ballrect[0], redrect[1] - ballrect[1]
    offset_redgoal = ballrect[0] - redsurfrect[0], ballrect[1] - redsurfrect[1]

    overlap_red = mask_ball.overlap(mask_red, offset_red)

    offset_blue = bluerect[0] - ballrect[0], bluerect[1] - ballrect[1]
    overlap_blue = mask_ball.overlap(mask_blue, offset_blue)
    offset_rednetgoal = ballrect[0] - redsurfrect[0], ballrect[1] - redsurfrect[1]
    overlap_redgoal = mask_ball.overlap(redsurfrect, offset_rednetgoal)

    if overlap_red and overlap_blue:  
        ball_vel = vel_red + vel_blue * 1.4
    elif overlap_red:  
        ball_vel = Vector2(vel_red) * 1.4
    elif overlap_blue:  
        ball_vel = Vector2(vel_blue) * 1.4
    elif overlap_redgoal:
        print("goal")



    screen.blit(bgImg, (0, 0))
    screen.blit(BALL, ballrect)
    screen.blit(redcar, redrect)
    screen.blit(bluecar, bluerect)
    screen.blit(redsurf, (0,340))
    screen.blit(bluesurf,(1100,340))

    pygame.display.flip()
    pygame.display.update()
    clock.tick(60)

pygame.quit()

标签: pythonpython-3.xpygame

解决方案


要从屏幕边缘反弹,您可以在矩形位于屏幕区域之外时反转球的速度。

if ballrect.top < 0 and ball_vel.y < 0:
    ball_vel.y *= -1
elif ballrect.bottom > screen.get_height() and ball_vel.y > 0:
    ball_vel.y *= -1
if ballrect.left < 0 and ball_vel.x < 0:
    ball_vel.x *= -1
elif ballrect.right > screen.get_width() and ball_vel.x > 0:
    ball_vel.x *= -1

要实现目标碰撞检测,您只需调用colliderect球的矩形和目标的方法。当然,这并不完全准确,但在大多数情况下不会被注意到。

if ballrect.colliderect(redgoal_rect):

如果您想使用蒙版碰撞,则需要通过从另一个对象的坐标中减去一个对象的 x 和 y 坐标来计算偏移量,然后调用overlap第二个对象的蒙版方法并传递第一个对象。

import pygame as pg
from pygame.math import Vector2


pg.init()
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
BG_COLOR = pg.Color(30, 90, 0)

# You need surfaces with an alpha channel to
# create masks, therefore pass `pg.SRCALPHA`.
REDGOAL = pg.Surface((90, 150), pg.SRCALPHA)
REDGOAL.fill((255, 0, 0))
redgoal_rect = REDGOAL.get_rect(topleft=(100, 200))
redgoal_mask = pg.mask.from_surface(REDGOAL)

BALL = pg.Surface((30, 30), pg.SRCALPHA)
pg.draw.circle(BALL, [250, 250, 250], [15, 15], 15)
# Ball variables.
ball_pos = Vector2(275, 200)
ballrect = BALL.get_rect(center=ball_pos)
ball_vel = Vector2(0, 0)
ball_mask = pg.mask.from_surface(BALL)

done = False
while not done:
    for event in pg.event.get():
        if event.type == pg.QUIT:
            done = True
        elif event.type == pg.KEYDOWN:
            if event.key == pg.K_a:
                ball_vel.x = -7
            elif event.key == pg.K_d:
                ball_vel.x = 8
            elif event.key == pg.K_w:
                ball_vel.y = -3
            elif event.key == pg.K_s:
                ball_vel.y = 5

    ball_vel *= .94  # Friction.
    ball_pos += ball_vel
    ballrect.center = ball_pos

    if ballrect.top < 0 and ball_vel.y < 0:
        ball_vel.y *= -1
    elif ballrect.bottom > screen.get_height() and ball_vel.y > 0:
        ball_vel.y *= -1
    if ballrect.left < 0 and ball_vel.x < 0:
        ball_vel.x *= -1
    elif ballrect.right > screen.get_width() and ball_vel.x > 0:
        ball_vel.x *= -1

    # Rect collision.
    # if ballrect.colliderect(redgoal_rect):
    #     print('goal!')

    # Calculate the offset between the objects.
    offset = redgoal_rect[0] - ballrect[0], redgoal_rect[1] - ballrect[1]
    # Pass the offset to the `overlap` method. If the masks collide,
    # overlap will return a single point, otherwise `None`.
    overlap = ball_mask.overlap(redgoal_mask, offset)

    if overlap:
        print('goal!')

    screen.fill(BG_COLOR)
    screen.blit(BALL, ballrect)
    screen.blit(REDGOAL, redgoal_rect)
    pg.display.flip()
    clock.tick(60)

pg.quit()

首先使用实际上是一个好主意colliderect,如果矩形发生碰撞,请使用overlap遮罩的方法(这样会更有效)。


推荐阅读