pygame精灵未随self.rect.move_ip移动



我正在pygame中开发一款游戏,我已经在屏幕上画了基本的图形,但用户输入让我很困惑。我有一个玩家类:

class Player(pygame.sprite.Sprite):
def __init__(self):
super(Player, self).__init__()
self.surf = pygame.Surface((75, 25))
self.surf.fill((255, 255, 255))
self.rect = self.surf.get_rect()
def update(self, pressed_keys):
if pressed_keys[K_UP]:
self.rect.move_ip(0, -5)
if pressed_keys[K_DOWN]:
self.rect.move_ip(0, 5)
if pressed_keys[K_LEFT]:
self.rect.move_ip(-5, 0)
if pressed_keys[K_RIGHT]:
self.rect.move_ip(5, 0)
pygame.event.pump()

但每当我按下键时,什么都不会发生。这是剧本的结尾,画出了东西:

while running:
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
running = False
elif event.type == QUIT:
running = False

pressed_keys = pygame.key.get_pressed()
player.update(pressed_keys)
screen.fill((0, 0, 0))
surf = pygame.Surface((50, 50))
surf.fill((0, 0, 0))
rect = surf.get_rect()
screen.blit(player.surf, (SCREEN_WIDTH/2, SCREEN_HEIGHT/2))
pygame.display.flip()

我不知道发生了什么,但我找不到任何东西来解决它。一切都很顺利,但没有其他事情。

问题:在屏幕上进行闪电扫描时的逻辑错误

在你的游戏循环中:

  • player.update通过按键移动播放器
  • blit正在绘制玩家始终固定在中心(SCREEN_WIDTH/2, SCREEN_HEIGHT/2)-,尽管玩家的位置发生了移动

因此,尽管您移动了它,并且它的位置(在rect中(被箭头键更改,但您的玩家在视觉上仍会将固定在屏幕中央

调试

添加一些调试print语句

  • blit之前监视更新后玩家位置是否移动:
  • blit之后监视其作为绘制矩形的返回值
print("player's rect after update:", player.rect)
drawn_rect = screen.blit(player.surf, (SCREEN_WIDTH/2, SCREEN_HEIGHT/2))
print("rect drawn by blit:", drawn_rect)

研究

假设您使用blit的意图是:

  • 初始绘制时将播放器置于屏幕中央
  • 使用blit在屏幕上绘制播放器

让我们咨询PyGame文档以获得一些支持。

使Surface对象居中

阅读关于如何使用get_rect():居中Surface文档

您可以将关键字参数值传递给此函数。在返回Rect之前,这些命名值将应用于Rect的属性。一个例子是mysurf.get_rect(center=(100, 100)),它为位于给定位置中心的曲面创建一个矩形。

使用blit

来自blit(source, dest, area=None, special_flags=0)上的文档

在此曲面上绘制source曲面。绘图可以使用dest参数进行定位。dest自变量可以是表示blit左上角位置的坐标对,也可以是Rect

设计修复

在创建过程中,在初始位置生成玩家,例如centered(在屏幕上(。

然后,您的游戏循环对draw负有单一责任,即screen上的player

玩家:居中、移动、绘制

class Player(pygame.sprite.Sprite):
def __init__(self):
super(Player, self).__init__()
self.surf = pygame.Surface((75, 25))
self.surf.fill((255, 255, 255))
self.rect = self.centered()  # spawn it centerd
def update(self, pressed_keys):
if pressed_keys[K_UP]:
self.move(0, -5)
if pressed_keys[K_DOWN]:
self.move(0, 5)
if pressed_keys[K_LEFT]:
self.move(-5, 0)
if pressed_keys[K_RIGHT]:
self.move(5, 0)
pygame.event.pump()
## added some methods
def centered():
return self.surf.get_rect(center=(SCREEN_WIDTH/2, SCREEN_HEIGHT/2)) 
def move(x, y):
self.rect.move_ip(x,y)
def draw_on(surface):  # visitor-pattern
surface.blit(self.surf, self.rect)

注:为Player添加了一些功能

  • centered定位在恒定屏幕尺寸内的中心
  • move用矢量(x,y(移动玩家
  • draw_on在给定的表面上绘制玩家的精灵/表面,如screen

绘制

然后在你的游戏循环内替换:

screen.blit(player.surf, (SCREEN_WIDTH/2, SCREEN_HEIGHT/2))

通过新命令:

# new player is centered, moved player is located anywhere
player.draw_on(screen)

注意:_visitor-pattern将语句更改为<subject>.<verb>(<object>)形式的可读语句,并且比以前少了一个自变量(内部化(。

奖金:建议

可以改进面向对象的设计,以增强可读性、简化测试和简化使用:

  1. 通过命令等功能控制玩家
  2. 选择一种简单的游戏语言(领域术语(
  3. 并使用它来命名抽象(对象、函数、变量(

示例:Playerscreenmovecentereddraw_to_on(名词、形容词或动词相似,用介词表示关系(

通常,设计改进可以更容易地识别逻辑错误或在调试期间分析控制流——希望如此。

您必须将玩家blit存储在rect属性中的位置:

screen.blit(player.surf, (SCREEN_WIDTH/2, SCREEN_HEIGHT/2))

screen.blit(player.surf, player.rect)

最新更新