Skip to content
Advertisement

Drawings rects over the player

EDIT: Reposted question so it is clearer.

My issue is that the player rectangles are not on the player because of the camera offset. As a result, the game looks like this (see image 1). It’s not working because of the camera offset. I successfully repositioned the yellow rect over the player but I am having trouble repositioning the red rectangle.

I have added comments to my Camera class explaining what I tried and noticed. When I remove the offset to 0, the rects are positioned how I want (but obviously the camera doesn’t work anymore). See image 2 for what I am trying to achieve.

This is image 1: https://i.stack.imgur.com/JnFPH.png

This is image 2: https://i.stack.imgur.com/NNw1e.png

Here is the link to the minimum code needed to reproduce my problem (I tried to make it as short as possible):

from sys import exit
import math

pygame.init()

# window and text
WIDTH = 1280 
HEIGHT = 720
FPS = 60
screen = pygame.display.set_mode((WIDTH,HEIGHT))
pygame.display.set_caption('Zombie Game')
clock = pygame.time.Clock()

# loads imgs
background = pygame.image.load("background/gamemap4.png").convert()

class Player(pygame.sprite.Sprite):
    def __init__(self, pos):
        super().__init__()
        self.image = pygame.image.load("handgun/move/survivor-move_handgun_0.png").convert_alpha()
        self.image = pygame.transform.rotozoom(self.image, 0, 0.35)
        self.base_player_image = self.image

        self.pos = pos
        self.base_player_rect = self.base_player_image.get_rect(center = pos)
        self.rect = self.base_player_rect.copy()
 
        self.player_speed = 10 

    def player_turning(self): 
        self.mouse_coords = pygame.mouse.get_pos() 

        self.x_change_mouse_player = (self.mouse_coords[0] - (WIDTH // 2))
        self.y_change_mouse_player = (self.mouse_coords[1] - (HEIGHT // 2))
        self.angle = int(math.degrees(math.atan2(self.y_change_mouse_player, self.x_change_mouse_player)))
        self.angle = (self.angle + 360) % 360

        self.image = pygame.transform.rotate(self.base_player_image, -self.angle)
        self.rect = self.image.get_rect(center=self.base_player_rect.center)

    def player_input(self):   
        self.velocity_x = 0
        self.velocity_y = 0

        keys = pygame.key.get_pressed()
        if keys[pygame.K_w]:
            self.velocity_y = -self.player_speed
        if keys[pygame.K_s]:
            self.velocity_y = self.player_speed
        if keys[pygame.K_d]:
            self.velocity_x = self.player_speed
        if keys[pygame.K_a]:
            self.velocity_x = -self.player_speed
            
        if self.velocity_x != 0 and self.velocity_y != 0: # moving diagonally
            self.velocity_x /= math.sqrt(2)
            self.velocity_y /= math.sqrt(2)

        if keys[pygame.K_SPACE]:
            self.shoot = True
        else:
            self.shoot = False

        if event.type == pygame.KEYUP:
            if event.key == pygame.K_SPACE:
                self.shoot = False

    def move(self):
        self.base_player_rect.centerx += self.velocity_x
        self.base_player_rect.centery += self.velocity_y
                     
    def update(self):   
        pygame.draw.rect(screen, "red", self.base_player_rect, width=2)
        pygame.draw.rect(screen, "yellow", self.rect, width=2)
        
        self.player_turning()
        self.player_input()    
        self.move()

class Camera(pygame.sprite.Group): 
    def __init__(self):
        super().__init__()
        self.offset = pygame.math.Vector2()
        self.floor_rect = background.get_rect(topleft = (0,0))

    def custom_draw(self):
        # self.offset.x = player.rect.centerx - (WIDTH // 2) # if i comment out these 2 lines, it works how I want.
        # self.offset.y = player.rect.centery - (HEIGHT // 2)

        #draw the floor
        floor_offset_pos = self.floor_rect.topleft - self.offset
        screen.blit(background, floor_offset_pos)

        for sprite in all_sprites_group: 
            offset_pos = sprite.rect.topleft - self.offset
            # sprite.rect.x -= self.offset.x # This sets the YELLOW rectangle over the player
            # sprite.rect.y -= self.offset.y # This sets the YELLOW rectangle over the player

            # player.base_player_rect.x -= self.offset.x # Attempting to draw red rectangle over the player - breaks the game
            # player.base_player_rect.y -= self.offset.y # # Attempting to draw red rectangle over the player - breaks the game
               
            screen.blit(sprite.image, offset_pos)

# Groups
all_sprites_group = pygame.sprite.Group()
obstacles_group = pygame.sprite.Group()

player = Player((900,900))
all_sprites_group.add(player)
 
camera = Camera()

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()    
    camera.custom_draw()
    all_sprites_group.update()
    pygame.display.update()
    clock.tick(FPS)```

Advertisement

Answer

Since the player is always in the center of the screen, the rectangles are also always in the center of the screen:

pygame.draw.rect(screen, "red", self.base_player_rect, width=2)
pygame.draw.rect(screen, "yellow", self.rect, width=2)

base_rect = self.base_player_rect.copy()
base_rect.center = (WIDTH // 2), (HEIGHT // 2)
pygame.draw.rect(screen, "red", base_rect, width=2)
rect = self.rect.copy()
rect.center = (WIDTH // 2), (HEIGHT // 2)
pygame.draw.rect(screen, "yellow", rect, width=2)

You can also copy the rectangles, shift them by the offset and draw them in the Camera class:

class Camera(pygame.sprite.Group): 
    def __init__(self):
        super().__init__()
        self.offset = pygame.math.Vector2()
        self.floor_rect = background.get_rect(topleft = (0,0))

    def custom_draw(self):
        self.offset.x = player.rect.centerx - (WIDTH // 2)
        self.offset.y = player.rect.centery - (HEIGHT // 2)

        #draw the floor
        floor_offset_pos = self.floor_rect.topleft - self.offset
        screen.blit(background, floor_offset_pos)

        # draw the rectangles
        base_rect = player.base_player_rect.copy().move(-self.offset.x, -self.offset.y)
        pygame.draw.rect(screen, "red", base_rect, width=2)
        rect = player.rect.copy().move(-self.offset.x, -self.offset.y)
        pygame.draw.rect(screen, "yellow", rect, width=2)

        for sprite in all_sprites_group: 
            offset_pos = sprite.rect.topleft - self.offset
            screen.blit(sprite.image, offset_pos)

Also, you need to synchronize the center of the rectangles after moving the player:

class Player(pygame.sprite.Sprite):
    # [...]

    def move(self):
        self.base_player_rect.centerx += self.velocity_x
        self.base_player_rect.centery += self.velocity_y
        self.rect.center = self.base_player_rect.center          # <---
User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement