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 # <---