问题
I was wondering how collision detection worked in pygame, between a polygon and a circle, for a football game. What I am trying to do, is make a ball move in the direction that the car hit it in. Please can somebody fix my code, I'm very stuck!!. If you run the following code, two cars will move, but nothing will happen if they hit the ball, and no error messages(Line 26 for my attempt at making it work). For starters, I just want it to print("Hello"). I would really appreciate if someone could help. Thank You
import pygame
from pygame.math import Vector2
pygame.init()
screen = pygame.display.set_mode((1150, 800))
redx = 50
redy = 30
bluex = 100
bluey = 30
clock = pygame.time.Clock()
BLUECAR_ORIGINAL = pygame.Surface((bluex, bluey), pygame.SRCALPHA)
pygame.draw.polygon(
BLUECAR_ORIGINAL, (0, 0, 255), [(0, 30), (50, 20), (50, 10), (0, 0)])
bluecar = BLUECAR_ORIGINAL
REDCAR_ORIGINAL = pygame.Surface((redx,redy), pygame.SRCALPHA)
pygame.draw.polygon(
REDCAR_ORIGINAL, (255, 0, 0), [(0, 0), (50, 10), (50, 20), (0, 30)])
redcar = REDCAR_ORIGINAL
def paddle_hit():
if pygame.sprite.collide_rect(ball, bluerect):
print("HI")
elif pygame.sprite.collide_rect(ball, redrect):
print("hello")
pos = Vector2(70, 70)
vel = Vector2(7, 0)
poss = Vector2(70,70)
vell = Vector2(7,0)
redrect = redcar.get_rect(center=pos)
redangle = 0
bluerect = bluecar.get_rect(center=pos)
blueangle = 0
ballx = 575
bally = 400
run = True
while run:
ball = pygame.draw.circle(screen, [0,0,0],[ballx,bally],30)
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
redangle += 5
vel.rotate_ip(-5)
redcar = pygame.transform.rotate(REDCAR_ORIGINAL, redangle)
redrect = redcar.get_rect(center=pos)
elif keys[pygame.K_RIGHT]:
redangle -= 5
vel.rotate_ip(5)
redcar = pygame.transform.rotate(REDCAR_ORIGINAL, redangle)
redrect = redcar.get_rect(center=pos)
if keys[pygame.K_a]:
blueangle += 5
vell.rotate_ip(-5)
bluecar = pygame.transform.rotate(BLUECAR_ORIGINAL, blueangle)
bluerect = bluecar.get_rect(center=pos)
elif keys[pygame.K_d]:
blueangle -= 5
vell.rotate_ip(5)
bluecar = pygame.transform.rotate(BLUECAR_ORIGINAL, blueangle)
bluerect = bluecar.get_rect(center=poss)
pos += vel
redrect.center = pos
poss += vell
bluerect.center = poss
bgImg = pygame.image.load("Football_pitch.png")
screen.blit(bgImg, (0,0))
screen.blit(redcar, redrect)
screen.blit(bluecar, bluerect)
pygame.display.flip()
clock.tick(60)
pygame.quit()
回答1:
You could use masks for the collision detection and set the velocity of the ball to the velocity of the colliding player.
Create pygame.mask.Mask objects (with pygame.mask.from_surface) for the ball, the red and the blue car (when the cars rotate, you have to create new masks).
In the while loop, calculate the offsets between the cars and the ball and then call the overlap method to see if they overlap. It returns the point of collision if the masks collide, otherwise None. So if overlap doesn't return None, you can set the velocity of the ball to the velocity of the player and it will move in the same direction. Scale the velocity vector to kick the ball.
import pygame
from pygame.math import Vector2
pygame.init()
screen = pygame.display.set_mode((1150, 800))
clock = pygame.time.Clock()
# Images.
BG_IMG = pygame.Surface((1150, 800))
BG_IMG.fill((30, 120, 30))
BLUECAR_ORIGINAL = pygame.Surface((50, 30), pygame.SRCALPHA)
pygame.draw.polygon(
BLUECAR_ORIGINAL, (0, 0, 255), [(0, 30), (50, 20), (50, 10), (0, 0)])
bluecar = BLUECAR_ORIGINAL
REDCAR_ORIGINAL = pygame.Surface((50, 30), pygame.SRCALPHA)
pygame.draw.polygon(
REDCAR_ORIGINAL, (255, 0, 0), [(0, 0), (50, 10), (50, 20), (0, 30)])
redcar = REDCAR_ORIGINAL
BALL = pygame.Surface((30, 30), pygame.SRCALPHA)
pygame.draw.circle(BALL, [250,250,250], [15, 15], 15)
# Ball variables.
ball_pos = Vector2(575, 400)
ballrect = BALL.get_rect(center=ball_pos)
ball_vel = Vector2(0, 0)
# Car variables.
pos_red = Vector2(470, 370)
vel_red = Vector2(3, 0)
redrect = redcar.get_rect(center=pos_red)
redangle = 0
pos_blue = Vector2(70,70)
vel_blue = Vector2(3,0)
bluerect = bluecar.get_rect(center=pos_red)
blueangle = 0
# Masks.
mask_blue = pygame.mask.from_surface(bluecar)
mask_red = pygame.mask.from_surface(redcar)
mask_ball = pygame.mask.from_surface(BALL)
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
redangle += 5
vel_red.rotate_ip(-5)
redcar = pygame.transform.rotate(REDCAR_ORIGINAL, redangle)
redrect = redcar.get_rect(center=redrect.center)
# We need a new mask after the rotation.
mask_red = pygame.mask.from_surface(redcar)
elif keys[pygame.K_RIGHT]:
redangle -= 5
vel_red.rotate_ip(5)
redcar = pygame.transform.rotate(REDCAR_ORIGINAL, redangle)
redrect = redcar.get_rect(center=redrect.center)
mask_red = pygame.mask.from_surface(redcar)
if keys[pygame.K_a]:
blueangle += 5
vel_blue.rotate_ip(-5)
bluecar = pygame.transform.rotate(BLUECAR_ORIGINAL, blueangle)
bluerect = bluecar.get_rect(center=bluerect.center)
mask_blue = pygame.mask.from_surface(bluecar)
elif keys[pygame.K_d]:
blueangle -= 5
vel_blue.rotate_ip(5)
bluecar = pygame.transform.rotate(BLUECAR_ORIGINAL, blueangle)
bluerect = bluecar.get_rect(center=bluerect.center)
mask_blue = pygame.mask.from_surface(bluecar)
# Move the cars.
pos_red += vel_red
redrect.center = pos_red
pos_blue += vel_blue
bluerect.center = pos_blue
# Move the ball.
ball_vel *= .99 # Friction.
ball_pos += ball_vel
ballrect.center = ball_pos
# Red car collision.
# We need the offset between the redrect and the ballrect.
offset_red = redrect[0] - ballrect[0], redrect[1] - ballrect[1]
# Pass the offset to the `overlap` method. If the masks collide,
# overlap will return a single point, otherwise `None`.
overlap_red = mask_ball.overlap(mask_red, offset_red)
# Blue car collision.
offset_blue = bluerect[0] - ballrect[0], bluerect[1] - ballrect[1]
overlap_blue = mask_ball.overlap(mask_blue, offset_blue)
if overlap_red and overlap_blue: # Both collide with the ball.
# Not sure what should happen here.
ball_vel = vel_red + vel_blue * 1.4
elif overlap_red: # Red collides with the ball.
ball_vel = Vector2(vel_red) * 1.4
elif overlap_blue: # Blue collides with the ball.
ball_vel = Vector2(vel_blue) * 1.4
# Drawing.
screen.blit(BG_IMG, (0, 0))
screen.blit(BALL, ballrect)
screen.blit(redcar, redrect)
screen.blit(bluecar, bluerect)
pygame.display.flip()
clock.tick(60)
pygame.quit()
回答2:
I've written a new python lib for collision detection between concave/convex polygons, and circles. It works very well, and is pretty efficient. It's pretty simple to use, and there are examples in the repository, as well as documentation.
https://github.com/QwekoDev/collision
来源:https://stackoverflow.com/questions/51705239/collision-detection-between-a-polygon-and-a-circle