python中精灵类碰撞检测的问题

问题描述

我在尝试计算 python3 中精灵类之间的掩码碰撞检测时遇到问题。我对 pygame 了解不多,因为这是我使用它的第一个项目。任何关于如何检测碰撞的建议将不胜感激。 Racecar 类似乎存在问题,因为它似乎只在显示器的左上角 (0,0) 处闪烁。我已经尝试了一些碰撞方法,但是我似乎无法让它们中的任何一个工作

import pygame

from pygame.math import Vector2

from math import radians,tan,degrees,copysign

pygame.init()

width = 1920
height = 900
hWidth = width/2
hHeight = height/2

SURFACE = pygame.HWSURFACE | pygame.DOUBLEBUF
global screen
screen = pygame.display.set_mode((width,height),SURFACE)

time = pygame.time.Clock()
clock = pygame.time.Clock()

white = (255,255,255)
grey = (105,105,105)

class Race_car(pygame.sprite.Sprite):
    def __init__(self,car_image,x,y):
        pygame.sprite.Sprite.__init__(self)
        self.x = x
        self.y = y
        self.pos = Vector2(x,y)
        self.veLocity = Vector2(0.0,0.0)
        self.angle = 0.0
        self.length = 4
        self.maxacceleration = 10
        self.maxSteering = 50
        self.maxVeLocity = 17
        self.brakeDeceleration = 20
        self.freeDeceleration = 6
        self.acceleration = 0.0
        self.steering = 0.0
        self.dt = clock.get_time() / 1000
        self.image = pygame.image.load(car_image).convert_alpha()
        self.mask = pygame.mask.from_surface(self.image)
        self.rotated = pygame.transform.rotate(self.image,self.angle)
        self.rect = self.rotated.get_rect()

    def update(self):
        self.dt = clock.get_time() / 1000

        self.veLocity += (self.acceleration * self.dt,0)
        self.veLocity.x = max(-self.maxVeLocity,min(self.veLocity.x,self.maxVeLocity))

        if self.steering:
            turningRadius = self.length / tan(radians(self.steering))
            angular_veLocity = self.veLocity.x / turningRadius
        else:
            angular_veLocity = 0

        self.pos += self.veLocity.rotate(-self.angle) * self.dt
        self.angle += degrees(angular_veLocity) * self.dt
        self.rect = self.rotated.get_rect()
        self.rotated = pygame.transform.rotate(self.image,self.angle)
        screen.blit(self.rotated,self.pos * 32 - (self.rect.width / 2,self.rect.height / 2))

        pressed = pygame.key.get_pressed()

        if pressed[pygame.K_UP]:
            if self.veLocity.x < 0:
                self.acceleration = +self.brakeDeceleration
            self.acceleration += 400 * self.dt
        elif pressed[pygame.KEYDOWN]:
            if self.veLocity.x < 0:
                self.acceleration = -self.brakeDeceleration
            else:
                self.acceleration -= 5 * self.dt
        elif pressed[pygame.K_SPACE]:
            if abs(self.veLocity.x) > self.dt * self.brakeDeceleration:
                self.acceleration = -copysign(self.brakeDeceleration,self.veLocity.x)
            else:
                self.acceleration = -self.veLocity.x / self.dt
        else:
            if abs(self.veLocity.x) > self.dt * self.freeDeceleration:
                self.acceleration = -copysign(self.freeDeceleration,self.veLocity.x)
            else:
                if self.dt != 0:
                    self.acceleration = -self.veLocity.x / self.dt
        self.acceleration = max(-self.maxacceleration,min(self.acceleration,self.maxacceleration))

        if pressed[pygame.K_RIGHT]:
            self.steering -= 400 * self.dt
        elif pressed[pygame.K_LEFT]:
            self.steering += 400 * self.dt
        else:
            self.steering = 0
        self.steering = max(-self.maxSteering,min(self.steering,self.maxSteering))


class Finish_Line(pygame.sprite.Sprite):
    def __init__(self,finish_image):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(finish_image).convert_alpha()
        self.mask = pygame.mask.from_surface(self.image)
        self.rect = self.image.get_rect(topleft=(1190,803))

    def update(self):
        screen.blit(self.image,self.rect)

class Racetrack(pygame.sprite.Sprite):
    def __init__(self,track_image):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(track_image).convert_alpha()
        self.mask = pygame.mask.from_surface(self.image)
        self.rect = self.image.get_rect(topleft=(0,0))

    def update(self):
        screen.blit(self.image,self.rect)


finish = Finish_Line('FinishSt.jpg')
car = Race_car("F1 Car1.png",32.6,26.3)
track = Racetrack('pixil mask.png')

sprite_group = pygame.sprite.Group()        # All sprites for updating and drawing
sprite_group.add(track)
sprite_group.add(finish)
sprite_group.add(car)
car_group = pygame.sprite.GroupSingle(car)

markings = pygame.image.load('markings (1).png')


class Game:    # initialize game class
    def __init__(self):

        pygame.display.set_caption("2D Racer")

        self.running = True

    def run(self):

        while self.running:

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

            if pygame.sprite.spritecollide(track,car_group,False,collided=pygame.sprite.collide_mask):
                print('collision')

            sprite_group.update()
            screen.fill(grey)
            sprite_group.draw(screen)
            screen.blit(markings,(974,812))

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

        pygame.quit()


g = Game()

if __name__ == '__main__':
    game = Game()
    g.run()

解决方法

pygame.sprite.spritecollide 使用 pygame.sprite.Sprite 对象的 .rect 属性来标识对象的位置。即使您使用蒙版碰撞,也必须知道对象的大致位置。

在更改位置 (.rect) 后,您必须更新存储在 Race_carpos 属性中的位置:

class Race_car(pygame.sprite.Sprite):
    # [...]

    def update(self):
        # [...]

        self.pos += self.velocity.rotate(-self.angle) * self.dt
        self.angle += degrees(angular_velocity) * self.dt

        center_x = round(self.pos.x)
        center_y = round(self.pos.y)
        self.rect = self.rotated.get_rect(center = (center_x,center_y))

        # [...]