Breakout游戏手柄适配问题:松开按键后Paddle自动左移至边界
问题描述
我基于Code with Giovanni的Breakout代码修改适配游戏手柄后,出现如下问题:运行游戏时,未按压手柄左右按键时,Paddle会自动移动至左侧墙壁;按压手柄按键时可正常控制Paddle移动,但松开按键后问题复现。修改后的代码如下:
import pygame pygame.init() pygame.mixer.init() WIDTH = 893 HEIGHT = 1000 size = (WIDTH, HEIGHT) screen = pygame.display.set_mode(size) pygame.display.set_caption("Breakout 1976") clock = pygame.time.Clock() FPS = 60 WHITE = (255, 255, 255) GREY = (212, 210, 212) BLACK = (0, 0, 0) BLUE = (0, 97, 148) RED = (162, 8, 0) ORANGE = (183, 119, 0) GREEN = (0, 127, 33) YELLOW = (197, 199, 37) score = 0 balls = 1 velocity = 4 paddle_width = 65 paddle_height = 20 all_sprites_list = pygame.sprite.Group() # Controller if pygame.joystick.get_count() > 0: joystick = pygame.joystick.Joystick(0) joystick.init() brick_sound = pygame.mixer.Sound('sounds/brick.wav') paddle_sound = pygame.mixer.Sound('sounds/paddle.wav') wall_sound = pygame.mixer.Sound('sounds/wall.wav') class Brick(pygame.sprite.Sprite): def __init__(self, color, width, height): super().__init__() self.image = pygame.Surface([width, height]) pygame.draw.rect(self.image, color, [0, 0, width, height]) self.rect = self.image.get_rect() class Paddle(pygame.sprite.Sprite): def __init__(self, color, width, height): super().__init__() self.image = pygame.Surface([width, height]) pygame.draw.rect(self.image, color, [0, 0, width, height]) self.rect = self.image.get_rect() def moveRight(self, pixels): self.rect.x += pixels if self.rect.x > WIDTH - wall_width - paddle_width: self.rect.x = WIDTH - wall_width - paddle_width def moveLeft(self, pixels): self.rect.x -= pixels if self.rect.x < wall_width: self.rect.x = wall_width class Ball(pygame.sprite.Sprite): def __init__(self, color, width, height): super().__init__() self.image = pygame.Surface([width, height]) pygame.draw.rect(self.image, color, [0, 0, width, height]) self.rect = self.image.get_rect() self.velocity = [velocity, velocity] def update(self): self.rect.x += self.velocity[0] self.rect.y += self.velocity[1] def bounce(self): self.velocity[0] = self.velocity[0] self.velocity[1] = -self.velocity[1] paddle = Paddle(BLUE, paddle_width, paddle_height) paddle.rect.x = WIDTH // 2 - paddle_width // 2 paddle.rect.y = HEIGHT - 65 ball = Ball(WHITE, 10, 10) ball.rect.x = WIDTH // 2 - 5 ball.rect.y = HEIGHT // 2 - 5 all_bricks = pygame.sprite.Group() brick_width = 55 brick_height = 16 x_gap = 7 y_gap = 5 wall_width = 16 def bricks(): for j in range(8): for i in range(14): if j < 2: if i == 0: brick = Brick(RED, brick_width, brick_height) brick.rect.x = wall_width brick.rect.y = 215 + j * (y_gap + brick_height) all_sprites_list.add(brick) all_bricks.add(brick) else: brick = Brick(RED, brick_width, brick_height) brick.rect.x = wall_width + brick_width + x_gap + (i - 1) * (brick_width + x_gap) brick.rect.y = 215 + j * (y_gap + brick_height) all_sprites_list.add(brick) all_bricks.add(brick) if 1 < j < 4: if i == 0: brick = Brick(ORANGE, brick_width, brick_height) brick.rect.x = wall_width brick.rect.y = 215 + j * (y_gap + brick_height) all_sprites_list.add(brick) all_bricks.add(brick) else: brick = Brick(ORANGE, brick_width, brick_height) brick.rect.x = wall_width + brick_width + x_gap + (i - 1) * (brick_width + x_gap) brick.rect.y = 215 + j * (y_gap + brick_height) all_sprites_list.add(brick) all_bricks.add(brick) if 3 < j < 6: if i == 0: brick = Brick(GREEN, brick_width, brick_height) brick.rect.x = wall_width brick.rect.y = 215 + j * (y_gap + brick_height) all_sprites_list.add(brick) all_bricks.add(brick) else: brick = Brick(GREEN, brick_width, brick_height) brick.rect.x = wall_width + brick_width + x_gap + (i - 1) * (brick_width + x_gap) brick.rect.y = 215 + j * (y_gap + brick_height) all_sprites_list.add(brick) all_bricks.add(brick) if 5 < j < 8: if i == 0: brick = Brick(YELLOW, brick_width, brick_height) brick.rect.x = wall_width brick.rect.y = 215 + j * (y_gap + brick_height) all_sprites_list.add(brick) all_bricks.add(brick) else: brick = Brick(YELLOW, brick_width, brick_height) brick.rect.x = wall_width + brick_width + x_gap + (i - 1) * (brick_width + x_gap) brick.rect.y = 215 + j * (y_gap + brick_height) all_sprites_list.add(brick) all_bricks.add(brick) brick_wall = bricks() all_sprites_list.add(paddle) all_sprites_list.add(ball) def main(score, balls): step = 0 run = True while run: for event in pygame.event.get(): if event.type == pygame.QUIT: run = False ###### GAME PAD CONTROLLER ############ axis_x = (joystick.get_axis(0)) if abs(axis_x) > 0.1: paddle.moveRight(10) if abs(axis_x) < 0.1: paddle.moveLeft(10) all_sprites_list.update() if ball.rect.y < 40: ball.velocity[1] = -ball.velocity[1] wall_sound.play() if ball.rect.x >= WIDTH - wall_width - 10: ball.velocity[0] = -ball.velocity[0] wall_sound.play() if ball.rect.x <= wall_width: ball.velocity[0] = -ball.velocity[0] wall_sound.play() if ball.rect.y > HEIGHT: ball.rect.x = WIDTH // 2 - 5 ball.rect.y = HEIGHT // 2 - 5 ball.velocity[1] = ball.velocity[1] balls += 1 if balls == 4: font = pygame.font.Font('text_style/DSEG14Classic-Bold.ttf', 50) text = font.render("GAME OVER", 1, WHITE) text_rect = text.get_rect(center=(WIDTH / 2, HEIGHT / 2)) screen.blit(text, text_rect) pygame.display.update() pygame.time.wait(2000) run = False if pygame.sprite.collide_mask(ball, paddle): ball.rect.x += ball.velocity[0] ball.rect.y -= ball.velocity[1] ball.bounce() paddle_sound.play() brick_collision_list = pygame.sprite.spritecollide(ball, all_bricks, False) for brick in brick_collision_list: ball.bounce() brick_sound.play() if len(brick_collision_list) > 0: step += 1 for i in range(0, 448, 28): if step == i: ball.velocity[0] += 1 ball.velocity[1] += 1 if 380.5 > brick.rect.y > 338.5: score += 1 brick.kill() elif 338.5 > brick.rect.y > 294: score += 3 brick.kill() elif 294 > brick.rect.y > 254.5: score += 5 brick.kill() else: score += 7 brick.kill() if len(all_bricks) == 0: font = pygame.font.Font('text_style/DSEG14Classic-Bold.ttf', 50) text = font.render("SCREEN CLEARED", 1, WHITE) text_rect = text.get_rect(center=(WIDTH / 2, HEIGHT / 2)) all_sprites_list.add(ball) screen.blit(text, text_rect) pygame.display.update() pygame.time.wait(2000) run = False screen.fill(BLACK) pygame.draw.line(screen, GREY, [0, 19], [WIDTH, 19], 40) pygame.draw.line(screen, GREY, [(wall_width / 2) - 1, 0], [(wall_width / 2) - 1, HEIGHT], wall_width) pygame.draw.line(screen, GREY, [(WIDTH - wall_width / 2) - 1, 0], [(WIDTH - wall_width / 2) - 1, HEIGHT], wall_width) pygame.draw.line(screen, BLUE, [(wall_width / 2) - 1, HEIGHT - 65 + paddle_height / 2 - 54 / 2], [(wall_width / 2) - 1, HEIGHT - 65 + paddle_height / 2 - 54 / 2 + 54], wall_width) pygame.draw.line(screen, BLUE, [(WIDTH - wall_width / 2) - 1, HEIGHT - 65 + paddle_height / 2 - 54 / 2], [(WIDTH - wall_width / 2) - 1, HEIGHT - 65 + paddle_height / 2 - 54 / 2 + 54], wall_width) pygame.draw.line(screen, RED, [(wall_width / 2) - 1, 212.5], [(wall_width / 2) - 1, 212.5 + 2 * brick_height + 2 * y_gap], wall_width) pygame.draw.line(screen, RED, [(WIDTH - wall_width / 2) - 1, 212.5], [(WIDTH - wall_width / 2) - 1, 212.5 + 2 * brick_height + 2 * y_gap], wall_width) pygame.draw.line(screen, ORANGE, [(wall_width / 2) - 1, 212.5 + 2 * brick_height + 2 * y_gap], [(wall_width / 2) - 1, 212.5 + 4 * brick_height + 4 * y_gap], wall_width) pygame.draw.line(screen, ORANGE, [(WIDTH - wall_width / 2) - 1, 212.5 + 2 * brick_height + 2 * y_gap], [(WIDTH - wall_width / 2) - 1, 212.5 + 4 * brick_height + 4 * y_gap], wall_width) pygame.draw.line(screen, GREEN, [(wall_width / 2) - 1, 212.5 + 4 * brick_height + 4 * y_gap], [(wall_width / 2) - 1, 212.5 + 6 * brick_height + 6 * y_gap], wall_width) pygame.draw.line(screen, GREEN, [(WIDTH - wall_width / 2) - 1, 212.5 + 4 * brick_height + 4 * y_gap], [(WIDTH - wall_width / 2) - 1, 212.5 + 6 * brick_height + 6 * y_gap], wall_width) pygame.draw.line(screen, YELLOW, [(wall_width / 2) - 1, 212.5 + 6 * brick_height + 6 * y_gap], [(wall_width / 2) - 1, 212.5 + 8 * brick_height + 8 * y_gap], wall_width) pygame.draw.line(screen, YELLOW, [(WIDTH - wall_width / 2) - 1, 212.5 + 6 * brick_height + 6 * y_gap], [(WIDTH - wall_width / 2) - 1, 212.5 + 8 * brick_height + 8 * y_gap], wall_width) font = pygame.font.Font('text_style/DSEG14Classic-Bold.ttf', 70) text = font.render(str(f"{score:03}"), 1, WHITE) screen.blit(text, (80, 120)) text = font.render(str(balls), 1, WHITE) screen.blit(text, (520, 41)) text = font.render('000', 1, WHITE) screen.blit(text, (580, 120)) text = font.render('1', 1, WHITE) screen.blit(text, (20, 40)) all_sprites_list.draw(screen) pygame.display.update() clock.tick(FPS) pygame.quit() main(score, balls)
问题原因
你写的手柄控制逻辑完全错误:
- 当摇杆X轴有输入(绝对值>0.1)时,不管向左还是向右,都只执行向右移动
- 当摇杆无输入(绝对值<0.1)时,反而执行向左移动,这就是松开按键后Paddle自动往左边跑的核心原因
修复代码
把原手柄控制部分的代码替换成下面这段:
###### GAME PAD CONTROLLER ############ axis_x = joystick.get_axis(0) deadzone = 0.1 # 死区,过滤摇杆微小偏移 if axis_x > deadzone: # 摇杆向右推,控制Paddle右移 paddle.moveRight(10) elif axis_x < -deadzone: # 摇杆向左推,控制Paddle左移 paddle.moveLeft(10) # 无输入时什么都不做,Paddle保持原地
额外优化建议
- 可以根据摇杆偏移量动态调整移动速度,让操控更顺滑,比如改成:
paddle.moveRight(int(axis_x * 15)) - 加个手柄未连接时的判断,避免没插手柄时程序崩溃
内容的提问来源于stack exchange,提问作者TMC FAMILY
相关产品推荐
相关产品推荐

