如何处理pygame中的像素?

时间:2015-01-31 22:28:10

标签: python-3.x pygame pixel

在pygame中使用精灵时,我最终意识到(由于差异最小),人们无法将精灵移动一小部分像素。虽然这是一个合乎逻辑的过程,但我得出的结论是,在不同的角度上无法达到相等的速度。

例如:

xmove = 5
ymove = -5

我定义了精灵ball的两个坐标的移动增量,它们以45°的角度离开屏幕底部的平台。我希望这个方向相对于它将遇到的障碍而改变。

以下确定精灵与屏幕“墙”的碰撞:

if ball.rect.left<=0:
    xmove = 5
elif ball.rect.right>=700:
    xmove = -5  
elif ball.rect.top<=0:
    ymove = 5
elif ball.rect.bottom>=400:
    ymove = -5

以下是一些代码,用于确定在检测到与player sprite(平台)发生冲突后会发生什么:

if pygame.sprite.spritecollide(ball, player_sprite, False):# and ball.rect.bottom>=player.rect.top:
    ymove=-5
    if ball.rect.bottomright [0] in range (player.rect.topleft [0], player.rect.topleft [0] + 15):
        xmove = -5
    elif ball.rect.bottomleft [0] in range (player.rect.topright [0] - 14, player.rect.topright [0] + 1):
        xmove = +5
    elif ball.rect.bottomright [0] in range (player.rect.topleft [0] + 15, player.rect.topleft [0] + 26):
        xmove = -4
        ymove = -5.83
    elif ball.rect.bottomleft [0] in range (player.rect.topright [0] - 26, player.rect.topright [0] - 15):
        xmove = +4
        ymove = -5.83
  

这里的想法是让球根据撞击平台的位置以不同的角度反弹,同时保持相同的速度(每个刻度的行进距离)

所以这里的问题是为了补偿x坐标上一个像素的减少,我使用毕达哥拉斯定理来输出y坐标(-5.83)。由于pygame不会记录像素的分数,这实际上会显着降低球的速度。

所以我的问题是,如何解决这个问题(因为我不想限制在45°角度......)?

2 个答案:

答案 0 :(得分:2)

您应该跟踪对象的“真实”位置,并且只在您在屏幕上绘制对象的那一刻。这可以防止舍入错误加起来。


另外,考虑使用矢量来跟踪物体的方向,因为它可以很容易地用角度改变方向并保持恒定的速度。

这是一个可以使用的示例类:

import math

# some simple vector helper functions, stolen from http://stackoverflow.com/a/4114962/142637
def magnitude(v):
    return math.sqrt(sum(v[i]*v[i] for i in range(len(v))))

def add(u, v):
    return [ u[i]+v[i] for i in range(len(u)) ]

def sub(u, v):
    return [ u[i]-v[i] for i in range(len(u)) ]    

def dot(u, v):
    return sum(u[i]*v[i] for i in range(len(u)))

def normalize(v):
    vmag = magnitude(v)
    return [ v[i]/vmag  for i in range(len(v)) ]

class Ball(object):

    def __init__(self):
        self.x, self.y = (0, 0)
        self.speed = 2.5
        self.color = (200, 200, 200)
        self._direction = (1, 0)

    # the "real" position of the object
    @property
    def pos(self):
        return self.x, self.y

    # for drawing, we need the position as tuple of ints
    # so lets create a helper property
    @property
    def int_pos(self):
        return map(int, self.pos)

    def set_dir(self, direction):
        self._direction = normalize(direction)

    def set_dir_d(self, degrees):
        self.set_dir_r(math.radians(degrees))

    def set_dir_r(self, radians):
        self._direction = (math.cos(radians), math.sin(radians))

    def update(self):
        # apply the balls's speed to the vector
        move_vector = [c * self.speed for c in self._direction]
        # update position
        self.x, self.y = add(self.pos, move_vector)

    def draw(self):
        pygame.draw.circle(screen, self.color, self.int_pos, 4)

这样,你可以通过调用set_dir(提供矢量),set_dir_d(提供所需的度数方向)或set_dir_r来改变球的方向(提供期望的弧度方向)。

调用update将根据当前方向以恒定速度(speed字段)移动球。

答案 1 :(得分:1)

因为Pygame的Rect用于处理像素,而像素基本上是不可分割的,所以您必须使用浮点数存储ball的精确位置。 pygame.Rect 接受浮动,但只有存储整数楼层值。

考虑提供ball个新float属性ball.xball.y(如果尚未分配)保留精确(十进制)位置,然后应用{更新后的值为{1}}和xmove。在每次移动之后(可能是同一更新的一部分),修改ymove以使其ball.rect与x和y值匹配,使用您最喜欢的舍入方法来topleft值。您也可以int ball.rect property,无论何时调用,都会生成新的Rect。考虑:

class MyBall:
    @property
    def rect(self):
        return pygame.Rect(round(self.x), round(self.y), *self.size)

    def __init__(self, startingLoc, size, *args, **kwargs):
        self.x = float(startingLoc[0])
        self.y = float(startingLoc[1])
        self.size = size  # Size does not need to be floats, but can be.
          # ...

请注意,如果您使ball.rect成为property,就地pygame.Rect操作将无效,自生成ball.rect以来-{-1}}不保存该地点及其属性。只能通过改变ballball.x来完成直线移动,但只要您不直接对y采取行动(或致电ball.rect这样做),它不重要,您将拥有pygame的精确x和y位置。

如果你想要超精确,你甚至可以在ball - player碰撞检测中使用浮点数,将ball替换为if ball.rect.bottomright [0] in range (player.rect.topleft [0], player.rect.topleft [0] + 15):(和等等)。请注意,if player.left <= ball.x <= player.left + 15:无法与range(..)值一起使用,因为该范围仅包含整数。

当您float blit时,您必须为其xy位置发送ball值。 int仍然可能是要走的路(因为它会在ball.rect.topleftball.x间接地间接提取这些值。

yxmove需要成为花车;只要操作中至少有一个元素是ymove,结果也将是float。根据球的速度和方向计算球的x和y位移后,您可以将这些浮点值发送到floatball.x,它将保持帧之间的精度。