2

I am making a game where there are a bunch of falling circles and the player(the square) needs to avoid them. The problem is I can't find a way to make the circle and player collide to trigger a game over. Is there any way to make the square and circle collide to trigger a game over or that makes the game quit in pygame?

import pygame
from pygame.locals import *
import os
import random
import math
import sys
import time

white = (255,255,255)
blue = (0,0,255)
gravity = 10
size =10
height = 500
width =600
varHeigth = height
ballNum = 5
eBall = []
apGame = pygame.display.set_mode((width, height))
pygame.display.set_caption("AP Project")

clock = pygame.time.Clock()

class Player(object):

  def __init__(self):
    red = (255, 0, 0)
    move_x = 300
    move_y = 400
    self.rect = pygame.draw.rect(apGame,red, (move_x, move_y, 10, 10))
    self.dist = 10

  def handle_keys(self):
    for e in pygame.event.get():
      if e.type == pygame.QUIT:
        pygame.quit();
        exit()
    key = pygame.key.get_pressed()
    if key[pygame.K_LEFT]:
      self.draw_rect(-1, 0)
    elif key[pygame.K_RIGHT]:
      self.draw_rect(1, 0)
    elif key[pygame.K_ESCAPE]:
      pygame.quit();
      exit()
    else:
      self.draw_rect(0, 0)

  def draw_rect(self, x, y):
    red = (255, 0, 0)
    black = (0, 0, 0)
    '''apGame.fill(black)'''
    self.rect = self.rect.move(x * self.dist, y * self.dist);
    pygame.draw.rect(apGame, red , self.rect)
    pygame.display.update()


  def draw(self,surface):
    red = (255, 0, 0)
    move_x = 300
    move_y = 400
    pygame.draw.rect(apGame, red, (move_x, move_y, 10, 10))


move_x = 300
move_y = 400
red = (255, 0, 0)
black = (0, 0, 0)
player = Player()
clock = pygame.time.Clock()
'''apGame.fill(black)'''
player.draw(apGame)
pygame.display.update()

for q in range(ballNum):
  x = random.randrange(0, width)
  y = random.randrange(0, varHeigth)
  eBall.append([x, y])

while True:

  apGame.fill(black)


  for i in range(len(eBall)):

    pygame.draw.circle(apGame, blue, eBall[i], size)

    eBall[i][1] += 5

    if eBall[i][1] > height:

        y = random.randrange(-50, -10)
        eBall[i][1] = y

        x = random.randrange(0, width)
        eBall[i][0] = x

  player.handle_keys()
  pygame.display.flip()
  clock.tick(30)
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
Bogs
  • 69
  • 2

2 Answers2

1

It is sufficient to use the bounding rectangle of the ball for the collision test. The bound pygame.Rect is returned by pygame.draw.circle(). If 2 rectangles are intersecting can be evaluated by colliderect().

For instance:

while True:
  # [...]

  for i in range(len(eBall)):

    ball_rect = pygame.draw.circle(apGame, blue, eBall[i], size)

    if player.rect.colliderect(ball_rect):
        print("hit")

    # [...]

If you want to do the collision test in a separate loop, then you have to construct the bounding rectangle of the ball manually:

while True:
  # [...]

  for ball in eBall:
      ball_rect = pygame.Rect(ball[0]-size, ball[1]-size, size*2, size*2)
      if player.rect.colliderect(ball_rect):
          print("hit")
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
1

There are collision checks for pygame rects that can detect collision between rects or between a rect and a point. There are also collision routines for sprites that will does circle based collision checking (see here). However I do not know of any built in routines that do circle to rect collision checking.

As @rabbid76 said in his answer, usually people just approximate it by using rect for the circle.

If you shrink the circles rect you use for collision detection to be slightly smaller than the rect bounding box of the circle, so that the the corners poke out less (but it is actually slightly inside on the top, bottom, left and right of the circle) it is usually not noticeable that you are not actually using the circle. It is not perfect though.

You can also use masks and do collision checking with those, see here. It is more computationally expensive, so you need to keep that in mind if you go this way.

Glenn Mackintosh
  • 2,765
  • 1
  • 10
  • 18