Search code examples
pythonpygamerect

Obscure Pygame Rect error


I've seen some topics here with the error: "TypeError: Argument must be rect style object". I'm having this error endlessly.

I've read the docs:

Rect(left, top, width, height) -> Rect
Rect((left, top), (width, height)) -> Rect
Rect(object) -> Rect

I have a method to extract subsurfaces from a pygame.Surface (It uses the surface's original method):

def getSubSurface(self, rect):

    """
    Returns the subsurface of a specified rect area in the grict surface.
    """

    return self.surface.subsurface(rect)

The problem is when I pass this rect (I've "unclustered" the arguments to make it clearer):

sub = []
w = self.tileWidth
h = self.tileHeight
for i in range((self.heightInPixels/self.heightInTiles)):
    y = self.grid.getY(i)
    for j in range((self.widthInPixels/self.widthInTiles)):
        x = self.grid.getX(j)
        sub.append(self.tileset.getSubSurface(pygame.Rect(x,y,w,h)))

I've explicitly passed a valid pygame.Rect, and I'm blitting nothing nowhere, and I get:

sub.append(self.tileset.getSubSurface(pygame.Rect(x,y,w,h)))
TypeError: Argument must be rect style object

Now, the funny part is: If I change the arguments to arbitrary int values:

sub.append(self.tileset.getSubSurface((1,2,3,4)))

It works perfectly. The pygame subsurfaces method takes it as a valid Rect. Problem is: All my instance-variables are valid ints (Even if they were not, it does not work if I convert them explicitly).

It makes no sense.

Why it takes explicit ints, but does not take my variables? (If the values were of an incorrect type, I would not get a "rectstyle" error, as if I was passing arguments incorrectly).


Solution

  • This error occurs if any of the arguments passed to Rect() are not numeric values.

    To see what's wrong, add the following code to your method:

    import numbers
    ...
    sub = []
    w = self.tileWidth
    h = self.tileHeight
    for i in range((self.heightInPixels/self.heightInTiles)):
        y = self.grid.getY(i)
        for j in range((self.widthInPixels/self.widthInTiles)):
            x = self.grid.getX(j)
            # be 100% sure x,y,w and h are really numbers
            assert isinstance(x, numbers.Number)
            assert isinstance(y, numbers.Number)
            assert isinstance(w, numbers.Number)
            assert isinstance(h, numbers.Number)
            sub.append(self.tileset.getSubSurface(pygame.Rect(x,y,w,h)))