【问题标题】:How to convert a PNG image to boundries (for circle) [pygame]?如何将 PNG 图像转换为边界(用于圆形)[pygame]?
【发布时间】:2017-08-14 11:45:45
【问题描述】:

如何将我在代码中加载的 PNG 文件 (对于 pygame 转换为圆的边界?

我有以下图片(png)

我使用jpeg 文件作为白色背景。

我的意思是,如何防止圆圈进入 PNG 图像?圆圈用箭头键向左、向右、向上、向下移动。

我的代码:

import pygame

def main1():
    width, height = 600, 600
    posx, posy = 300, 300
    screen = pygame.display.set_mode((width, height))
    clock = pygame.time.Clock()
    velocity = (0, 0)
    done = False
    pygame.display.update()
    bg = pygame.image.load("maze1.png")
    bg1 = pygame.image.load("maze2.jpeg")
    while not done:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                done = True

        keys = pygame.key.get_pressed()
        screen.blit(bg1, (0, 0))
        screen.blit(bg, (0, 0))
        if keys[pygame.K_RIGHT]:
            posx += 3
        if keys[pygame.K_UP]:
            posy -= 3
        if keys[pygame.K_LEFT]:
            posx -= 3
        if keys[pygame.K_DOWN]:
            posy += 3
        cir = pygame.draw.circle(screen, (255, 200, 240), (posx,posy), 10)
        pygame.display.flip()
        clock.tick(30)

if __name__ == '__main__':
   pygame.init()
   main1()
   pygame.quit()

【问题讨论】:

标签: python python-3.x pygame


【解决方案1】:

所以 - 事实证明,你想要的比你在那里尝试的要复杂一些。

Pygame 在一个函数中具有像素碰撞检测功能,即“pygame.sprite.collide_mask”。尝试使用 Python 代码自己进行像素验证,使用image.get_at 检查像素以检查透明像素会太慢 - 通过像素的纯 Python 循环可能比在本机代码中检查的代码慢数千倍。这意味着您必须使用pygame.sprite.collide_mask

该函数的问题在于它仅适用于图像蒙版 - 而且它们必须附加到一个精灵对象,该对象还必须具有有效的“矩形”属性。 (https://www.pygame.org/docs/ref/sprite.html#pygame.sprite.collide_mask)

不好的部分是你必须正确地创建所有这些东西。好的部分是您可以从代码中的 Sprite 对象中获得一些额外的好处——比如封装一些逻辑,并且“posx”和“posy”可以自行协调。我保留了单独的变量,以便您可以想出最好的方法。

另一个坏消息是,尽管理论上没问题,并且工作“相当好”,但掩码碰撞检测存在一些极端情况。在运行这些示例时,您会注意到,当您遇到角落时,您可能会被卡住。我试图通过碰撞检测功能中的另一个“向前看”步骤来缓解这种情况——对我来说感觉好一点,但移动的圆圈有时会卡住。

不管怎样,所有的代码都写好了:

"""
Author: Muhammad Nouman
https://stackoverflow.com/questions/45673808/how-to-convert-png-image-to-boundries-for-circle-pygame

"""
import pygame


class GameObject(pygame.sprite.Sprite):
    def __init__(self, image):
        super().__init__()
        self.image = image
        self.rect = self.image.get_rect()
        self.mask = pygame.mask.from_surface(image)

    def can_move(self, delta_pos, wall_map, count=1):
        old_pos = self.rect.center
        self.rect.centerx = self.rect.centerx + delta_pos[0]
        self.rect.centery = self.rect.centery + delta_pos[0]
        result = bool(pygame.sprite.collide_mask(self, wall_map))
        if count:
            result &= not self.can_move(delta_pos, wall_map, count - 1)
        self.rect.center = old_pos
        return not result


def main1():
    width, height = 600, 600
    posx, posy = 300, 300
    screen = pygame.display.set_mode((width, height))
    clock = pygame.time.Clock()
    velocity = (0, 0)
    done = False
    pygame.display.update()
    bg = pygame.image.load("maze1.png")
    bg = pygame.transform.rotozoom(bg, 0, width / bg.get_width())
    bg1 = pygame.image.load("maze2.jpeg")
    character_image = pygame.Surface((20,20), pygame.SRCALPHA)
    pygame.draw.circle(character_image, (255, 200, 240, 255), (10, 10), 10)

    character = GameObject(character_image)
    character.rect.center = (posx, posy)

    tiled_maze = GameObject(bg)

    while not done:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                done = True

        keys = pygame.key.get_pressed()
        screen.fill((255, 255,255))
        screen.blit(bg, (0, 0))
        if keys[pygame.K_RIGHT]:
            if character.can_move((3, 0), tiled_maze):
                posx += 3
        if keys[pygame.K_UP]:
            if character.can_move((0, -3), tiled_maze):
                posy -= 3
        if keys[pygame.K_LEFT]:
            if character.can_move((-3, 0), tiled_maze):
                posx -= 3
        if keys[pygame.K_DOWN]:
            if character.can_move((0, 3), tiled_maze):
                posy += 3
        character.rect.center = ((posx, posy))
        screen.blit(character.image, character.rect)
        pygame.display.flip()
        clock.tick(30)

if __name__ == '__main__':
   pygame.init()
   main1()
   pygame.quit()

所以,只是给出一个大致的概念:“掩码”是图像的简化版本,pygame 可以创建标记,哪些像素确实包含某些东西,哪些像素是完全透明的。它们是从图像创建的。 collide_mask 方法需要一个 Sprite 对象,它有一个 rect 和一个 mask 属性 - rect 包含游戏场上的精灵位置,mask 是从图像创建的蒙版。

迷宫可以被制作成一个覆盖所有领域的单个精灵(此外,它必须按比例缩小以适合您的屏幕尺寸 - 我通过调用 ...rotozoom 来实现它。因为它已经包含透明度,它一切就绪(另外请注意,如果您要使用纯色背景,则不需要第二张图像 - 您可以使用表面的fill 方法)。

现在,“圆”角色必须有一个图像 - 所以我花了一些线创建一个内存表面,并在其上绘制一个圆,并将该表面用作“圆”精灵的图像。

由于我们的精灵必须有一个自己的类,我在那里添加了 colsiion 检测逻辑作为一种方法 - 当精灵要移动时,它基本上需要一个“未来偏移”,而第二个精灵 - 在这种情况下,总是迷宫。它“模拟”新位置,并检查“自我”(即圆形精灵)是否会与该位置的“其他精灵”蒙版发生碰撞。如果是这样,游戏逻辑中的ifstatements 会阻止位置更新。 (稍微调整一下这些 if 语句可能会给您带来更好的体验,防止当前迷宫中存在的“粘性”角落)。

总而言之,我希望你能理解这里做了什么,并且你可以改进这段代码以获得更好的使用体验。

【讨论】:

  • 它很好,但圆圈卡在迷宫中(当它碰到它时)。有什么解决办法吗?
  • 老兄,圆圈卡得太紧了。
  • 是的 - “检查我是否可以去那里,然后才去”的算法中有一些错误 - 因为它应该总是可以退一步,就像一个人进入那里一样.也许保留一个圈子最后位置的列表,并始终将这些可能去的地方列入白名单将是一个合适的解决方法。
猜你喜欢
  • 1970-01-01
  • 2017-10-08
  • 1970-01-01
  • 2013-06-13
  • 1970-01-01
  • 2014-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多