滚动对象不流畅,有时会向右跳动几像素 [pygame]

0 投票
1 回答
544 浏览
提问于 2025-04-18 01:45

为了制作一个抽象的、可以滚动的城市天际线原型,我创建了一个类来生成随机的矩形。这些矩形被添加到一个列表中,然后从这个列表中取出要在屏幕上绘制的内容。这些矩形一开始在屏幕右侧外面,然后向左滚动,直到它们离开视野并被丢弃。建筑物的移动看起来有点卡顿,而且在屏幕的某个特定位置,它们还会向右移动几个像素。

这个原型的视频拍得相当准确,几乎没有延迟。请注意建筑物之间的间隙,当它们接近显示区域的最右侧三分之一时,间隙会突然缩小,就好像左边的建筑物突然向右移动了几个像素。间隙越小,这种现象越明显。视频中的其他异常是由于录制者造成的,在应用程序中并不存在。这里有一个很短的视频,清楚地展示了这个现象: https://www.youtube.com/watch?v=0cdhrezjcY8

在大约1秒的时候,你会注意到后面一层建筑物之间有一个非常窄的间隙。在4秒时,这个间隙与蓝色玩家对象平齐,左边的矩形移动,间隙消失了。右边还有一个更大的间隙也发生了同样的情况,但由于间隙较大,它并没有完全消失。我已经多次检查代码,但仍然看不出是什么导致了这个异常。我希望有人能告诉我这是我做错了什么,还是我遇到了某种限制。

我最开始是线性编写这个程序的,没有使用类或函数。后来我重写了它,使用一个类来生成层对象,并处理所有的生成和滚动。在这两种情况下,问题依然存在。弄不明白为什么建筑物移动得不流畅让我很抓狂。我甚至写了一个版本,使用png图片而不是随机生成的矩形。在那个版本中,png图片滚动得非常流畅和无缝: https://www.youtube.com/watch?v=Uiw_giAvbOo(视频有点卡顿,但实际程序运行得很流畅)所以这个问题只出现在这些随机矩形上。

这是程序的代码: https://www.refheap.com/73079

这是类的代码:

class Scroller():
    def __init__(self, speed, color, heightMax):
        # Speed of the layer scroll, the color of the layer and the maximum height for buildings
        # set up the building parameters
        self.buildingHeightMax = heightMax
        self.buildingHeightMin = 100
        self.buildingWidthMax = 125
        self.buildingWidthMin = 75
        self.buildings = []
        self.layerspeed = speed
        self.buildTime = True
        self.buildCountdown = 10
        self.color = color

    def update(self):
        # Check if it's time to build. If not, decrement counter
        if self.buildTime == False:
            self.buildCountdown -= 1
            # If time is 0, time to build, reset counter to a new random time
            if self.buildCountdown <= 0:
                self.buildTime = True
                self.buildCountdown = random.randint(3, self.layerspeed)

        # create building if it's time
        if self.buildTime:
            # generate random width and height of building
            buildingHeight = random.randint(self.buildingHeightMin, self.buildingHeightMax)
            buildingWidth = random.randint(self.buildingWidthMin, self.buildingWidthMax)
            buildingTop = WINDOWHEIGHT - buildingHeight
            # This generates the building object from the above parameters
            building = pygame.Rect(WINDOWWIDTH, buildingTop, buildingWidth, WINDOWHEIGHT)
            self.buildTime = False
            self.buildCountdown = random.randint(3, self.layerspeed * 5)
            # add building to buildings list
            self.buildings.append(building)

        # move all buildings on layer at set speed
        for building in self.buildings:
            # if the building is off the screen, trash it. If not, move it to the
            # right at the objects speed.
            if building.right < 0:
                self.buildings.remove(building)
            else:
                building.left -= self.layerspeed

        # draw the Front buildings
        for i in range(len(self.buildings)):
            pygame.draw.rect(windowSurface, self.color, self.buildings[i])

1 个回答

1

你的问题很可能出在这里:

    # move all buildings on layer at set speed
    for building in self.buildings:
        # if the building is off the screen, trash it. If not, move it to the
        # right at the objects speed.
        if building.right < 0:
            self.buildings.remove(building)
        else:
            building.left -= self.layerspeed

你在遍历列表的时候使用了remove,这会导致跳过下一个建筑物。所以不是右边的建筑物移动得更快,而是左边的建筑物被跳过了。

你可以通过这个简单的例子自己看看:

a = [2, 3, 4, 1.5, 6, 8, 3.2]

for element in a:
    if element == 4:
        a.remove(element)
    else:
        print element

试试看,你会发现不仅4不会被打印出来,1.5也会被跳过。

一个比较好的做法是,先遍历所有建筑物,看看哪些需要被移除,然后再把它们全部移除,最后再移动剩下的建筑物。
你可以查看这个链接,里面有一些不错的建议。

另外,你在倒计时的部分更新了两次,第一次在第47行,第二次在第58行。这样做有什么特别的原因吗?

撰写回答