'Pygame bounding rect is not on sprite center

I have a problem with pygame.

I'm just trying to understand collisions. I would like to implement a rectangle around my player with self.rect = self.image.get_bounding_rect() but the rectangle is off center and i cant find a way to center it on my player sprite.

This is what the rectangle looks like at the moment:

Player spirte rectangle

Here is my Player class:

import pygame

# Class Variable
player_sprite_group = pygame.sprite.Group()


class Player(pygame.sprite.Sprite):
    def __init__(self, window_size, health, name):
        pygame.sprite.Sprite.__init__(self)
        self.image = self.load_character_sprites()
        self.rect = self.image.get_bounding_rect()
        self.health = health
        self.current_state = "idle"
        self.direction = "right"
        self.name = name
        self.rect.center = window_size[0] / 2, window_size[1] / 2
        self.moving_speed = 6
        self.x_moving_velocity = 0
        self.y_moving_velocity = 0
        self.add_player_to_sprite_group()

    def load_character_sprites(self):
        return pygame.image.load("../Assets/Hero Knight/Sprites/HeroKnight/Idle/HeroKnight_Idle_0.png")

    def state(self, set_state, direction):
        if direction == "right":
            self.direction = "right"
        if direction == "left":
            self.direction = "left"
        if set_state == "idle":
            self.current_state = set_state
        if set_state == "walking":
            self.current_state = set_state
        if set_state == "fight":
            self.current_state = set_state
        if set_state == "jump":
            self.current_state = set_state


    def collision(self):
        pass

    # player movement
    def player_movement(self, keys_pressed):
        if keys_pressed[pygame.K_w] or keys_pressed[pygame.K_s] or keys_pressed[pygame.K_a] or keys_pressed[pygame.K_d]:
            self.state("walking", self.direction)
        if keys_pressed[pygame.K_UP] or keys_pressed[pygame.K_w]:
            self.rect.y -= self.moving_speed
        if keys_pressed[pygame.K_DOWN] or keys_pressed[pygame.K_s]:
            self.rect.y += self.moving_speed
        if keys_pressed[pygame.K_LEFT] or keys_pressed[pygame.K_a]:
            if self.direction != "left":
                self.state("moving", "left")
                self.image = pygame.transform.flip(self.image, True, False)
            self.rect.x -= self.moving_speed
        if keys_pressed[pygame.K_RIGHT] or keys_pressed[pygame.K_d]:
            if self.direction != "right":
                self.state("walking", "right")
                self.image = pygame.transform.flip(self.image, True, False)
            self.rect.x += self.moving_speed

    def set_current_location(self):
        pass

    def update_player(self):
        player_sprite_group.update()

    def draw_player(self, screen):
        pygame.draw.rect(screen, (255, 0, 255), self.rect)
        player_sprite_group.draw(screen)

    def add_player_to_sprite_group(self):
        player_sprite_group.add(self)

And here is my my pygame file with its settings and game loop:

import pygame
import sys
from pygame.locals import *
from debug import debug
from player import Player

# clock implementation
clock = pygame.time.Clock()
# window name
pygame.display.set_caption("Dungeon crawler")
# Set the window size
window_size = [1200, 720]
# no frame window
window_frame_noframe = NOFRAME
# frame window
window_frame_frame = 0
# init the game window
screen = pygame.display.set_mode(window_size, window_frame_noframe, 32)

# create player object
player_one = Player(window_size, 100, "knight")

# test rect
test_rect = pygame.Rect(200, 300, 50, 50)

# game main loop
while True:
    # clear screen
    screen.fill((146, 244, 255))

    # debugging methods
    debug(clock, 10, 10)
    debug(player_one.current_state, 30, 10)
    debug(player_one.direction, 60, 10)
    debug(player_one.rect, 90, 10)

    # player movement
    key_pressed = pygame.key.get_pressed()
    player_one.player_movement(key_pressed)

    # event loop
    for event in pygame.event.get():
        if event.type == QUIT:
            # close the window and end the game
            pygame.quit()
            sys.exit()

    # draw collision rect
    pygame.draw.rect(screen, (255, 255, 255), test_rect)
    # draw and update player
    player_one.update_player()
    player_one.draw_player(screen)

    # show window
    pygame.display.update()
    # set fps to 60 with clock
    clock.tick(60)

I hope you can help me with this problem



Solution 1:[1]

The top left of the rectangle returned by get_bounding_rect() is not (0, 0) and the size of the bounding rectangle is not the size of the image. When using the original image and the bounding rectangle, the offset of the bounding rectangle is not considered. You have to use the bounding rectangle to get a subsurface of the iamge:

class Player(pygame.sprite.Sprite):
    def __init__(self, window_size, health, name):
  
        pygame.sprite.Sprite.__init__(self)
 
        self.image = self.load_character_sprites()
        self.rect = self.image.get_bounding_rect()
        self.image = self.image.subsurface(self.rect)
        self.rect.center = window_size[0] / 2, window_size[1] / 2

        # [...]

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Rabbid76