Sprite mask collision problems in pygame

泄露秘密 提交于 2019-12-20 03:52:35

问题


I am attempting to create a racing game in pygame. I want it such that when the car goes off the track, it slows down. I have tried to do this by having another sprite that is an outline of the track and when the car touches that sprite, it slows down. This does not work and I don't know why. Is there a better way to do this?

Img is the car image

Back is the racetrack

BackHit is the outline

I receive this error code:

Traceback (most recent call last): File "C:\Users\Daniella\Desktop\Python\Games\game.py", line 75, in if pygame.sprite.collide_mask(Img, BackHit): File "C:\Users\Daniella\AppData\Roaming\Python\Python36\site-packages\pygame\sprite.py", line 1470, in collide_mask xoffset = right.rect[0] - left.rect[0] AttributeError: 'pygame.Surface' object has no attribute 'rect'

This is the code:

import pygame

Width = 800
Height = 600

Black = (0, 0, 0)
White = (255, 255, 255)
Red = (255, 0, 0)
Green = (0, 255, 0)
Blue = (0, 0, 255)
Yellow = (255, 255, 0)
BackColour = (198, 151, 107)

pygame.init()
GameDisplay = pygame.display.set_mode((Width, Height))
pygame.display.set_caption("A bit Racey")
Clock = pygame.time.Clock()

Img = pygame.image.load("download.png")
ImgWidth = 46
ImgHeight = 68
Img = pygame.transform.scale(Img, (ImgWidth, ImgHeight))

Back = pygame.image.load("back1.png")
BackWidth = Width*4
BackHeight = Height*4
Back = pygame.transform.scale(Back, (BackWidth, BackHeight))

BackHit = pygame.image.load("back1 hit1.png")
BackHitWidth = Width*4
BackHitHeight = Height*4
BackHit = pygame.transform.scale(BackHit, (BackHitWidth, BackHitHeight))

def Car():
    GameDisplay.blit(Img, (400-ImgWidth/2, 300-ImgHeight/2))

def Background(X, Y):
    GameDisplay.blit(Back, (X, Y))

def BackgroundHit(X, Y):
    GameDisplay.blit(BackHit, (X, Y))

X = (Width*0.45)
Y = (Height*0.5)

XChange = 0
YChange = 0

Changer = 1

Crashed = False

while not Crashed:
    for Event in pygame.event.get():
        if Event.type == pygame.QUIT:
            Crashed = True
        elif Event.type == pygame.KEYDOWN:
            if Event.key == pygame.K_LEFT:
                Img = pygame.transform.rotate(Img, -90)
                XChange = 5 / Changer
            elif Event.key == pygame.K_RIGHT:
                Img = pygame.transform.rotate(Img, 90)
                XChange = -5 / Changer
            elif Event.key == pygame.K_UP:
                Img = pygame.transform.rotate(Img, 0)
                YChange = 5 / Changer
            elif Event.key == pygame.K_DOWN:
                Img = pygame.transform.rotate(Img, 180)
                YChange = -5 / Changer
        if Event.type == pygame.KEYUP:
            if Event.key == pygame.K_LEFT or Event.key == pygame.K_RIGHT:
                XChange = 0
            elif Event.key == pygame.K_UP or Event.key == pygame.K_DOWN:
                YChange = 0
    if pygame.sprite.collide_mask(Img, BackHit):
        Changer = 2
    Y += YChange
    X += XChange
    GameDisplay.fill(White)
    BackgroundHit(X, Y)
    Background(X, Y)
    Car()
    pygame.display.update()
    Clock.tick(200)

pygame.quit()
quit()

回答1:


Here's a little example that shows you how you can use pygame.mask.from_surface and pygame.Mask.overlap for pixel perfect collision detection.

import pygame as pg

# Transparent surfaces with a circle and a triangle.
circle_surface = pg.Surface((60, 60), pg.SRCALPHA)
pg.draw.circle(circle_surface, (30, 90, 200), (30, 30), 30)
triangle_surface = pg.Surface((60, 60), pg.SRCALPHA)
pg.draw.polygon(triangle_surface, (160, 250, 0), ((30, 0), (60, 60), (0, 60)))


def main():
    screen = pg.display.set_mode((640, 480))
    clock = pg.time.Clock()

    # Use `pygame.mask.from_surface` to get the masks.
    circle_mask = pg.mask.from_surface(circle_surface)
    triangle_mask = pg.mask.from_surface(triangle_surface)

    # Also create rects for the two images/surfaces.
    circle_rect = circle_surface.get_rect(center=(320, 240))
    triangle_rect = triangle_surface.get_rect(center=(0, 0))

    done = False

    while not done:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                done = True
            elif event.type == pg.MOUSEMOTION:
                triangle_rect.center = event.pos

        # Now calculate the offset between the rects.
        offset_x = triangle_rect.x - circle_rect.x
        offset_y = triangle_rect.y - circle_rect.y

        # And pass the offset to the `overlap` method of the mask.
        overlap = circle_mask.overlap(triangle_mask, (offset_x, offset_y))
        if overlap:
            print('The two masks overlap!', overlap)

        screen.fill((30, 30, 30))
        screen.blit(circle_surface, circle_rect)
        screen.blit(triangle_surface, triangle_rect)

        pg.display.flip()
        clock.tick(30)


if __name__ == '__main__':
    pg.init()
    main()
    pg.quit()

To create a mask for the background or track you need to create an extra image and either leave the track transparent or the area where the car should slow down and then check if the car collides with the track or with the outside area. Here I check if the green triangle collides with the "track" (the blue lines), and in your game you would then slow the car down if it doesn't collide with the track.

import pygame as pg


bg_surface = pg.Surface((640, 480), pg.SRCALPHA)
pg.draw.lines(
    bg_surface, (30, 90, 200), True,
    ((60, 130), (300, 50), (600, 200), (400, 400), (150, 300)),
    12)
triangle_surface = pg.Surface((60, 60), pg.SRCALPHA)
pg.draw.polygon(triangle_surface, (160, 250, 0), ((30, 0), (60, 60), (0, 60)))


def main():
    screen = pg.display.set_mode((640, 480))
    clock = pg.time.Clock()

    bg_mask = pg.mask.from_surface(bg_surface)
    triangle_mask = pg.mask.from_surface(triangle_surface)

    bg_rect = bg_surface.get_rect(center=(320, 240))
    triangle_rect = triangle_surface.get_rect(center=(0, 0))

    done = False

    while not done:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                done = True
            elif event.type == pg.MOUSEMOTION:
                triangle_rect.center = event.pos

        offset_x = triangle_rect.x - bg_rect.x
        offset_y = triangle_rect.y - bg_rect.y

        overlap = bg_mask.overlap(triangle_mask, (offset_x, offset_y))
        if overlap:
            print('The two masks overlap!', overlap)

        screen.fill((30, 30, 30))
        screen.blit(bg_surface, bg_rect)
        screen.blit(triangle_surface, triangle_rect)

        pg.display.flip()
        clock.tick(30)


if __name__ == '__main__':
    pg.init()
    main()
    pg.quit()


来源:https://stackoverflow.com/questions/46862739/sprite-mask-collision-problems-in-pygame

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!