PyGame中使用Rect类的与帧无关的运动问题

时间:2014-10-26 20:26:58

标签: python pygame

我正在用PyGame写一个简单的游戏,而且我遇到了让事情正常运转的问题。我对游戏编程没有经验,所以我不确定我的方法是否正确..

我有一个Ball类,它扩展了PyGame的Sprite类。每个帧,Ball对象应该在屏幕上移动。我使用帧独立(?)/基于时间的移动,每次使用PyGame的Clock对象返回的时间增量。如,

class Ball(pygame.sprite.Sprite):
   # . . .
   def update(self, delta):
       self.rect.x += delta * self.speed  # speed is pixels per second
       self.rect.y += delta * self.speed  # ... or supposed to be, anyway

......和......

class Game(object):
    # . . .
    def play(self):
        self.clock = pygame.time.Clock()
        while not self.done:
            delta = self.clock.tick(self.fps) / 1000.0  # time is seconds
            self.ball.update(delta)

PyGame的Sprite类由一个跟踪精灵位置的Rect对象(rect)支持。每当更新值时,Rect的坐标都会自动转换为整数。所以,我的问题是每次调用update()时,任何额外的像素运动都会丢失,而不是随着时间的推移而累积。速度为"每秒像素数"这种方式并不准确。更糟糕的是,如果每帧的移动量小于一个像素,那么对于那些帧,球根本不会移动,因为它总是向下舍入到零。 (即,如果pps< fps则没有移动)

我不知道如何处理这件事。我尝试向Ball添加单独的x和y值,这些值不会被强制为整数,并且每次更改时都会更新rect。这样,x和y值就像正常一样累积像素的分数。如,

class Ball(pygame.sprite.Sprite):
    #  . . .
    def update(self, delta):
        self.x += delta * self.speed
        self.y += delta * self.speed
    def getx(self):
        return self._x
    def setx(self, val):
        self._x = val      # this can be a float
        self.rect.x = val  # this is converted to int
    def gety(self):
        return self._y
    def sety(self, val):
        self._y = val      # this can be a float
        self.rect.y = val  # this is converted to int
    x = property(getx,setx)
    y = property(gety,sety)

但最终会变得混乱:当x和y改变时,更新rect对象很容易,但不是相反。更不用说Rect对象有许多其他有用的坐标可以操作(如centerx,top,bottomleft等 - 这就是为什么人们还想直接移动矩形)。我或多或少最终不得不重新实现Ball中的整个Rect类,在将它们传递给rect对象之前存储浮点数,或者只根据x和y执行所有操作,牺牲一些方便的Rect类方便。

有更智能的方法来解决这个问题吗?

1 个答案:

答案 0 :(得分:0)

我不知道你是否仍然需要这个答案,但我在一段时间之前想到了这一点并认为我会给这个问题一个答案,因为我试图弄清楚发生了什么。 (顺便说一下,谢谢你帮我确认一下这个问题。)

您可以使用Python的round函数。差不多,只要把你想要的东西扔到那个函数中,它就会吐出一个正确的数字。

我开始工作的第一种方式就是这样:

x = box['rect'].x
if leftDown:
   x -= 300 * deltaTime
if rightDown:
   x += 300 * deltaTime

box['rect'].x = round(x)

(我的deltaTime是浮点数,只是一小部分。)

只要你在应用它之前通过round函数放置浮点值,就应该这样做。它不必使用单独的变量或任何东西。

值得注意的是,您无法绘制像素的分数。永远。如果您熟悉Lite-Brite,像素就会以这种方式工作,成为一盏明灯。这就是为什么你最后使用的数字必须是一个整数。