You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pygame相机偏移致玩家矩形错位 求解决方案

相机偏移导致玩家矩形定位错误问题

问题描述

相机偏移设置后,玩家角色的红色基础矩形无法正确显示在角色上方,仅黄色旋转矩形位置正常。将偏移值设为0时,两个矩形都能正确贴合角色,但相机跟随功能失效。需要实现两个矩形都准确覆盖角色的效果。

可复现代码

from sys import exit
import math
import pygame

pygame.init()

# 窗口设置
WIDTH = 1280 
HEIGHT = 720
FPS = 60
screen = pygame.display.set_mode((WIDTH,HEIGHT))
pygame.display.set_caption('Zombie Game')
clock = pygame.time.Clock()

# 加载资源
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 
        self.shoot = False

    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, shoot_key_up):   
        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: # 斜向移动时减速
            self.velocity_x /= math.sqrt(2)
            self.velocity_y /= math.sqrt(2)

        self.shoot = keys[pygame.K_SPACE]
        if shoot_key_up:
            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, camera_offset, shoot_key_up):   
        # 应用相机偏移后绘制矩形
        base_rect_screen = self.base_player_rect.move(-camera_offset.x, -camera_offset.y)
        pygame.draw.rect(screen, 'red', base_rect_screen, width=2)
        rect_screen = self.rect.move(-camera_offset.x, -camera_offset.y)
        pygame.draw.rect(screen, 'yellow', rect_screen, width=2)
        
        self.player_turning()
        self.player_input(shoot_key_up)    
        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.base_player_rect.centerx - (WIDTH // 2)
        self.offset.y = player.base_player_rect.centery - (HEIGHT // 2)

        # 绘制背景
        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
            screen.blit(sprite.image, offset_pos)

# 精灵组
all_sprites_group = pygame.sprite.Group()
obstacles_group = pygame.sprite.Group()

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

while True:
    shoot_key_up = False
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_SPACE:
                shoot_key_up = True
    camera.custom_draw()
    all_sprites_group.update(camera.offset, shoot_key_up)
    pygame.display.update()
    clock.tick(FPS)

解决方案

问题根源

base_player_rect存储的是角色在世界空间的坐标,当前直接绘制它时未应用相机偏移,导致红色矩形停留在世界坐标位置,而角色图像已通过相机转换到屏幕空间,因此出现错位。

修复步骤

  1. 恢复相机偏移计算:在Camera类的custom_draw方法中,基于玩家的base_player_rect计算偏移,确保相机以角色基础位置为中心。
  2. 矩形绘制时应用偏移:在Player的update方法中,将世界空间的矩形坐标通过move(-camera_offset.x, -camera_offset.y)转换为屏幕空间坐标后再绘制。
  3. 修复输入事件问题:将SPACE键的KEYUP事件移到主循环处理,避免Player类直接访问主循环的event变量导致报错。

替代方案(统一绘制逻辑到Camera类)

如果希望统一管理绘制逻辑,可把矩形绘制移到Camera的custom_draw中:

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

    # 绘制背景
    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
        screen.blit(sprite.image, offset_pos)
        
        # 绘制红色基础矩形
        base_rect_screen = sprite.base_player_rect.move(-self.offset.x, -self.offset.y)
        pygame.draw.rect(screen, 'red', base_rect_screen, width=2)
        # 绘制黄色旋转矩形
        rect_screen = sprite.rect.move(-self.offset.x, -self.offset.y)
        pygame.draw.rect(screen, 'yellow', rect_screen, width=2)

同时注释掉Player类update方法中的绘制代码。

内容的提问来源于stack exchange,提问作者juba1029

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 11:45:37