Спрайты с перекрытием Pygame (порядок прорисовки) в зависимости от местоположения - PullRequest
3 голосов
/ 19 марта 2019

Я все еще относительно новичок в Pygame и Python в целом, так что, надеюсь, это не так уж и далеко.

Я делаю нисходящую RPG, и у меня есть два объекта Sprite с изображениями, которые выглядят (например) так:
enter image description here enter image description here

, которые используют фрагменты, которые не представляют всю полноту изображения:

class NPC(pygame.sprite.Sprite):
    def __init__(self, image, pos, *groups):
        super().__init__(*groups)
        self.image = pygame.load(image)
        self.rect = self.image.get_rect()
        self.collisionRect = pygame.Rect(self.rect.left, self.rect.top + 12, self.image.get_width(), self.image.get_width()) 
        #12 is the number of pixels that will overlap in the y-dimension

Я делаю это, потому что хочу, чтобы верхние несколько пикселей NPC перекрывались с другими спрайтами. collisionRect в каждом объекте используется поверх rect всякий раз, когда я обнаруживаю столкновение, чтобы я мог создать этот эффект.

Однако мне нужен способ перерисовать их в моей функции update (), чтобы один рисовал поверх другого в зависимости от их взаимного расположения.

Итак, когда один NPC находится над другим, он выглядит так:

enter image description here

Но, когда все наоборот, это должно выглядеть так:

enter image description here

Это означает, что изображения должны быть нарисованы в другом порядке, в зависимости от того, какой спрайт находится «ниже» другого.

Я думал о возможном разрезании спрайтов на отдельные спрайты и просто рисовал спрайты «головой» в последнюю очередь, но мне было интересно, существует ли более простой (или, по крайней мере, надежный) способ обнаружения следует ли рисовать спрайт последним или нет, в зависимости от того, перекрывает ли он другой спрайт и непосредственно под ним в измерении y.

Прошу прощения, если этот вопрос слишком широкий или требует большего контекста; может предоставить их при необходимости.

1 Ответ

2 голосов
/ 19 марта 2019

Как уже сказал Кингсли в комментарии, обычным способом для этого является сортировка ваших спрайтов по их координате y.

Вот полный, работающий пример (я назвал ваши изображения guy.png и gal.png).Поскольку вы уже используете спрайты, я использовал простой pygame.sprite.Group -подкласс:

import pygame

class Actor(pygame.sprite.Sprite):
    def __init__(self, image, pos):
        super().__init__()
        self.image = image
        self.pos = pygame.Vector2(pos)
        self.rect = self.image.get_rect(center=self.pos)

    def update(self, events, dt):
        pass

class Player(Actor):
    def __init__(self, image, pos):
        super().__init__(image, pos)

    def update(self, events, dt):
        pressed = pygame.key.get_pressed()
        move = pygame.Vector2((0, 0))
        if pressed[pygame.K_w]: move += (0, -1)
        if pressed[pygame.K_a]: move += (-1, 0)
        if pressed[pygame.K_s]: move += (0, 1)
        if pressed[pygame.K_d]: move += (1, 0)
        if move.length() > 0: move.normalize_ip()
        self.pos += move*(dt/5)
        self.rect.center = self.pos

class YAwareGroup(pygame.sprite.Group):
    def by_y(self, spr):
        return spr.pos.y

    def draw(self, surface):
        sprites = self.sprites()
        surface_blit = surface.blit
        for spr in sorted(sprites, key=self.by_y):
            self.spritedict[spr] = surface_blit(spr.image, spr.rect)
        self.lostsprites = []

def main():
    pygame.init()
    screen = pygame.display.set_mode((500, 500))
    clock = pygame.time.Clock()
    dt = 0

    sprites = YAwareGroup(Player(pygame.image.load('guy.png').convert_alpha(), (100, 200)),
                          Actor(pygame.image.load('gal.png').convert_alpha(), (200, 200)))

    while True:
        events = pygame.event.get()
        for e in events:
            if e.type == pygame.QUIT:
                return

        sprites.update(events, dt)
        screen.fill((30, 30, 30))
        sprites.draw(screen)

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

if __name__ == '__main__':
    main()

enter image description here

Если вам нужна пользовательская логика рисования, обычно это нехудшая идея для подкласса Group классов Pygame.Вы можете найти их источник здесь , чтобы увидеть, как они работают.

...