Reputation: 71
I replaced my mouse with a crosshair and I have some targets on the screen. When you shoot a target, it's supposed to disappear from the screen. How can I check if the CENTER of my crosshair (My actual mouse) is in collision with one of the sprites? The following code doesn't precisely check if the center of my crosshair is on one of the targets, so even if you shoot with the empty area in the crosshair it would count, and I don't want that.
import pygame
from random import randrange
class Crosshair(pygame.sprite.Sprite):
def __init__(self, image):
super().__init__()
self.image = image
self.rect = self.image.get_rect()
def update(self):
self.rect.center = pygame.mouse.get_pos()
def shoot(self):
pygame.sprite.spritecollide(self, target_group, True)
class Target(pygame.sprite.Sprite):
def __init__(self, image, x, y):
super().__init__()
self.image = image
self.rect = self.image.get_rect()
self.rect.center = (x, y)
def set_background(background):
(b_width, b_height) = background.get_size()
for x in range(0, screen_width, b_width):
for y in range(0, screen_height, b_height):
screen.blit(background, (x, y))
#General setup
pygame.init()
fps = 60
clock = pygame.time.Clock()
#Background picture
background = pygame.image.load('Art/bg.png')
#Hide mouse
pygame.mouse.set_visible(False)
#Game Screen
screen_width = 1024
screen_height = 576
screen = pygame.display.set_mode((screen_width, screen_height))
#Crosshair
crosshair_image = pygame.image.load('Art/crosshair.png')
crosshair = Crosshair(crosshair_image)
crosshair_group = pygame.sprite.Group()
crosshair_group.add(crosshair)
#Targets
targets = 10
target_image = pygame.image.load('Art/target.png')
new_target_image = pygame.transform.rotozoom(target_image, 0, 0.5)
target_group = pygame.sprite.Group()
while len(target_group)<10:
target = Target(new_target_image,
randrange(0, screen_width),
randrange(0, screen_height))
if pygame.sprite.spritecollide(target, target_group, False):
continue
target_group.add(target)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
crosshair.shoot()
set_background(background)
target_group.draw(screen)
crosshair_group.update()
crosshair_group.draw(screen)
pygame.display.flip()
clock.tick(fps)
pygame.quit()
Upvotes: 2
Views: 908
Reputation: 210889
Since the targets are circular, the collision can b detected by calculating the distance from the mouse pointer to the center of the target.
Compute the square of the Euclidean distance (dx*dx + dy*dy
) from the mouse cursor to the center of the target. Test that the square of the distance is less than the square of the radius:
Pass the mouse position to the Crosshair.shoot
. Go through the targets and kill
a target when a collision is detected:
class Crosshair(pygame.sprite.Sprite):
# [...]
def shoot(self, mouse_pos):
for target in target_group:
dx = target.rect.centerx - mouse_pos[0]
dy = target.rect.centery - mouse_pos[1]
dist_sq = dx*dx + dy*dy
radius = target.image.get_width() / 2
if dist_sq < radius*radius:
target.kill()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
crosshair.shoot(event.pos) # <--- pass event.pos
# [...]
An more elegant solution, however, is to use pygame.sprite.collide_circle()
. This function can be passed to pygame.sprite.spritecollide()
as a callback argument.
For this solution the pygame.sprite.Sprite
objects must have an attribute radius
:
class Crosshair(pygame.sprite.Sprite):
def __init__(self, image):
super().__init__()
self.image = image
self.rect = self.image.get_rect()
self.radius = 1
def update(self):
self.rect.center = pygame.mouse.get_pos()
def shoot(self, mouse_pos):
self.rect.center = mouse_pos
pygame.sprite.spritecollide(self, target_group, True, pygame.sprite.collide_circle)
class Target(pygame.sprite.Sprite):
def __init__(self, image, x, y):
super().__init__()
self.image = image
self.rect = self.image.get_rect()
self.rect.center = (x, y)
self.radius = self.rect.width // 2
Upvotes: 1