基于Pygame的Pong游戏问题求助:修正击球判定与容错问题
Hey there! Let's fix those two annoying issues in your Pygame Pong game. I'll break down each problem, explain what's causing it, and show you the updated code with clear explanations.
Fix 1: Stop Collision Detection When the Ball Is Below the Paddle
The original collision check circle_y >= 500 is way too broad—it triggers even when the ball is fully below the paddle (since the paddle starts at y=500 and is only 10px tall, the ball could be at y=550 and still trigger the hit).
We need to narrow the y-range to only detect when the ball is actually touching the top of the paddle. Since the ball has a radius of 20px, its bottom edge is circle_y + 20. We'll only trigger the collision if this bottom edge hits the paddle's top (y=500) while the ball is still above or at the paddle's top:
# Replace the original collision check with this if (circle_y + 20 >= 500 and circle_y <= 500) and (mouse_x <= circle_x <= mouse_x + 100): if move_y > 0: score += 5 move_y = minus3 # Use your level-based speed value instead of hardcoding -1
Fix 2: Reduce Fault Tolerance for Paddle Movement
Right now, waving the paddle back and forth catches almost every ball because the collision only checks if the ball's x is within the paddle's width—no consideration for paddle movement speed or precise timing.
To fix this, we'll:
- Track the paddle's previous position to calculate its movement direction/speed
- Adjust the ball's x-direction speed based on how the paddle is moving, making off-center hits or fast moves change the ball's trajectory more drastically
- Keep the collision check tight to only valid contact moments
First, add a variable to track the previous mouse x-position near your initial variables:
prev_mouse_x = 0 # Track previous paddle position to calculate movement speed
Then update the mouse logic and collision handling:
mouse_x, mouse_y = pygame.mouse.get_pos() # Calculate how much the paddle moved since last frame paddle_delta = mouse_x - prev_mouse_x prev_mouse_x = mouse_x # ... (keep your drawing code here) # Updated collision check with paddle movement influence if (circle_y + 20 >= 500 and circle_y <= 500) and (mouse_x <= circle_x <= mouse_x + 100): if move_y > 0: score += 5 move_y = minus3 # Shift ball's x speed based on paddle movement—makes random waves less effective move_x += paddle_delta * 0.1 # Clamp x speed to prevent it from getting too extreme move_x = max(min(move_x, 5), -5)
Now, if you move the paddle left quickly, the ball bounces left faster; move right, and it bounces right faster. Random, fast movements won't catch every ball anymore—you'll need precise positioning to make consistent hits.
Full Updated Code
Here's the complete fixed code with both changes plus a few extra quality-of-life tweaks:
import pygame import sys import pygame.freetype # Initialize game variables circle_x = 250 circle_y = 250 move_x = 2 move_y = 2 score = 0 deaths = 0 level = 1 minus1 = -1 minus2 = -1 plus1 = 1 plus2 = 1 minus3 = -1 prev_mouse_x = 0 # Track previous paddle position for movement delta # Initialize Pygame pygame.init() pygame.mixer.init() try: pygame.mixer.music.load("nana.mp3") pygame.mixer.music.play() except: print("Couldn't load audio file 'nana.mp3'") # Add error handling for missing audio font = pygame.freetype.Font("msyh.ttc") screen = pygame.display.set_mode((800, 600)) pygame.display.set_caption("Pong Game") while True: # Level progression logic if score >= 50: level = 2 minus1 = -2 minus2 = -2 plus1 = 2 plus2 = 2 minus3 = -2 # Handle mouse input and paddle movement mouse_x, mouse_y = pygame.mouse.get_pos() paddle_delta = mouse_x - prev_mouse_x prev_mouse_x = mouse_x # Draw everything screen.fill((255, 255, 255)) pygame.draw.circle(screen, (100, 100, 100), (circle_x, circle_y), 20) pygame.draw.rect(screen, (255, 0, 0), (mouse_x, 500, 100, 10)) # Update ball position circle_x += move_x circle_y += move_y # Draw UI text font_image, font_rect = font.render('Score: ' + str(score), fgcolor=(0, 0, 0), size=30) font_image1, font_rect1 = font.render('Deaths: ' + str(deaths), fgcolor=(0, 0, 0), size=30) font_image2, font_rect2 = font.render('Level: ' + str(level), fgcolor=(0, 0, 0), size=30) screen.blit(font_image, (20, 10)) screen.blit(font_image1, (600, 10)) screen.blit(font_image2, (300, 10)) # Ball boundary checks if circle_x > 800: move_x = minus1 if circle_y > 600: score = 0 deaths += 1 # Reset ball to center instead of weird speed jumps circle_x = 250 circle_y = 250 move_x = 2 if level == 1 else 2 move_y = 2 if level == 1 else 2 if circle_y < 0: move_y = plus1 if circle_x < 0: move_x = plus2 # Fixed collision detection with paddle movement influence if (circle_y + 20 >= 500 and circle_y <= 500) and (mouse_x <= circle_x <= mouse_x + 100): if move_y > 0: score += 5 move_y = minus3 # Adjust x speed based on paddle movement move_x += paddle_delta * 0.1 # Keep x speed within reasonable bounds move_x = max(min(move_x, 5), -5) # Handle quit event for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() # Update display (fixed: moved pygame.quit() to quit event to prevent crashes) pygame.display.update()
Extra Notes
- Added error handling for the audio file in case "nana.mp3" is missing
- Fixed the ball reset logic (setting
move_y = -50caused weird jumps; now we reset to the center) - Moved
pygame.quit()to the quit event handler—your original code was calling it every frame, which would crash the game quickly! - The
paddle_delta * 0.1multiplier controls how much the paddle's movement affects the ball—tweak it to make the game easier/harder as needed.
内容的提问来源于stack exchange,提问作者BanButton

