如何在Pygame中检查特定屏幕颜色,并带有一定的容差?

3

晚上好!我正在使用Pygame中的Surface.get_at()函数,通过角色坐标来检查玩家是否处于可行走的表面上。我选择黑色(0, 0, 0)作为行走表面,但有时Pygame会返回颜色(1, 0, 0),因此,玩家无法站在该表面上。是否有一种方法可以使用一系列数字作为整数,以便任何接近黑色的颜色都可以用作行走表面?是否有更简单的方法来实现这一点?以下是我正在开发的程序部分:

groundcolor = disp.get_at((int(playerx), int(playery)-1))
    if groundcolor == black1 or groundcolor == black0:
        groundlim = int(playery)
        print(groundcolor)

    if groundcolor != black1 and groundcolor != black0:
        groundlim = 695
        if playery != 695:
            jumping = True
            print(groundcolor)

注意:black1是(1,0,0),而black0是(0,0,0)。我这样做只是为了尝试解决我的问题,但是有太多接近黑色的颜色不能全部定义。
除了我提出的问题之外,如果您有其他建议,将不胜感激。谢谢您抽出时间阅读。
2个回答

2
你可以检查颜色值是否低于某个点,例如:
if groundcolor[0] < 5 and groundcolor[1] < 5 and groundcolor[2] < 5:
    #walkable

您也可以使用遮罩。使用遮罩,您可以获得与任何形状的像素完美碰撞。并且您可以从颜色中创建屏幕的遮罩,这正是您想要的。

使用遮罩的示例。

#create the screen
screen = pygame.display.set_mode((width, height))

#draw background object white
pygame.draw.rect(screen,(255,255,255),(100,100,200,50))
pygame.draw.rect(screen,(255,255,255),(400,40,60,200))
pygame.draw.rect(screen,(255,255,255),(200,300,200,50))

#create mask using white as the collision areas, (1,1,1) is the threshold
#so (1,1,1) is an exact match so mabye change to (0.9, 0.9, 0.9)
screen_mask = pygame.mask.from_threshold(screen,(255,255,255),(1,1,1))

#do the same for the player
class player:
    def __init__(self):
        ...
        self.mask = pygame.mask.from_threshold(self.image,(0,255,0),(1,1,1))
        ...
        #if your player is an image, not one colour, then you can do 
        self.mask = pygame.mask.from_surface(self.image)
        #which goes off transparency

然后检查碰撞。
if screen_mask.overlap(player.mask,(player.rect.x,player.rect.y))

1
@NicholasPlasmodiumViCannonPl 当你开始涉及面积时,get_at 函数变得非常低效,这甚至在文档中都有说明。我建议使用 masks,我会更新答案并展示使用 masks 的例子。 - The Big Kahuna
1
没问题,如果您无法让它正常工作,只需发表评论并更新问题,如果需要,我会查看。 - The Big Kahuna
1
其实,我可以再问一件事吗?我的背景是一张图像(PNG),我使用pygame将其适配到屏幕上。是否有一种方法可以为任何黑色或接近黑色的颜色创建掩码?我是在MS Paint中制作的背景,黑色线条是我希望成为平台的部分(这也使得调整平台变得更加容易,因为我只需画更多的黑色线条)。因此,我能否遮蔽屏幕上每个接近黑色的像素? - PlasmodiumFalciparum
1
是的。一旦你使用pygame.image.load加载了png图像,它将返回一个surface,然后你可以使用它来创建掩码。就像上面的例子一样,你可以使用pygame.mask.from_threshold(image, (0,0,0), (0.9, 0.9, 0.9))。这将创建一个与图像大小相同的掩码,碰撞区域为任何90%以上为黑色的像素。然后,如果你想创建更多的平台,你可以更新你的图片或在pygame中绘制。 - The Big Kahuna
1
不用太担心,最多可能需要添加几行代码。但导入图像可能是最简单的。然后您就不必担心屏幕上的其他对象会妨碍视线。因为整个时间图像都是相同的。而且您仍然可以轻松更改图像以创建/销毁平台。 - The Big Kahuna
显示剩余6条评论

1
你可以使用numpy.linalg.norm来计算向量与原点(0,0,0)之间的欧几里得距离,并设置一个阈值。例如,以下代码:
import numpy as np

a = (1,0,0)
b = (1,1,0)
c = (2,0,0)
d = (1,2,3)

print(np.linalg.norm(a))
print(np.linalg.norm(b))
print(np.linalg.norm(c))
print(np.linalg.norm(d))

将输出
1.0
1.4142135623730951
2
3.7416573867739413

因此,您可以将数字定义为阈值,并像这样修改代码中的条件语句:

if np.linalg.norm(groundcolor) < threshold:

"and" (并且)
if np.linalg.norm(groundcolor) >= threshold:

如果您想计算与非(0,0,0)颜色的距离,只需将该颜色从基准颜色中减去。例如:
if np.linalg.norm(groundcolor-green) < threshold:

请注意,如果减法的结果包含负值也不会影响范数函数的运算结果,根据定义,范数函数总是产生大于或等于零的实数:
print(np.linalg.norm((-1,0,0)))

会输出:
1.0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接