Pygame 根据位置重叠精灵(绘制顺序)
Pygame overlapping Sprites (draw order) based on location
总的来说,我对 Pygame 和 Python 还是比较陌生,所以希望这不是太过分。
我正在制作一个自上而下的 RPG,我有两个 Sprite 对象,其图像看起来(例如)如下所示:
使用不代表整个图像的矩形:
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 位于另一个 NPC 之上时,它看起来像这样:
但是,如果反过来,它应该是这样的:
这意味着需要以不同的顺序绘制图像,具体取决于哪个精灵是 'below' 另一个。
我考虑过可能将 sprite 切割成单独的 sprite,然后让 'head' sprite 最后绘制,但我想知道是否有更简单(或至少可靠)的方法来 检测 一个精灵是否应该最后绘制,基于它是否与另一个精灵 和 重叠在 y 维度紧挨着它的下方。
如果这个问题过于宽泛或需要更多背景信息,我深表歉意;如果需要可以提供。
正如 Kingsley 在评论中所说,按 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()
如果您需要自定义绘图逻辑,子类化 pygame 的 Group
类 通常不是最糟糕的主意。您可以找到它们的来源 here 以查看它们的工作原理。
总的来说,我对 Pygame 和 Python 还是比较陌生,所以希望这不是太过分。
我正在制作一个自上而下的 RPG,我有两个 Sprite 对象,其图像看起来(例如)如下所示:
使用不代表整个图像的矩形:
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 位于另一个 NPC 之上时,它看起来像这样:
但是,如果反过来,它应该是这样的:
这意味着需要以不同的顺序绘制图像,具体取决于哪个精灵是 'below' 另一个。
我考虑过可能将 sprite 切割成单独的 sprite,然后让 'head' sprite 最后绘制,但我想知道是否有更简单(或至少可靠)的方法来 检测 一个精灵是否应该最后绘制,基于它是否与另一个精灵 和 重叠在 y 维度紧挨着它的下方。
如果这个问题过于宽泛或需要更多背景信息,我深表歉意;如果需要可以提供。
正如 Kingsley 在评论中所说,按 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()
如果您需要自定义绘图逻辑,子类化 pygame 的 Group
类 通常不是最糟糕的主意。您可以找到它们的来源 here 以查看它们的工作原理。