1

I have been trying to solve this for weeks. This is a free-falling pit game, where my character (in this case a chimpanzee png) falls from the top of the screen to the bottom while trying to dodge the random black circles. I have tried so many angles at tackling this, I have tried the standard collision I was taught (pygame.sprite.groupcollide(Group1, Group2, False, True, collided = None) I have tried doing collisions with the colour black only, different formats of spawning my image and all that, and I haven't been able to find anything that works with my code. It has resulted in the code being very messy. I have tried to clean it up for this, but it still might be hard to understand, but if anybody has any solution to this, please let me know as I have been stumped for weeks. I just want the game to close or "game over" when they touch a circle Code:

import sys
import pygame as pg
RED = (255, 0, 0)
GRAY = (150, 150, 150)
GREEN =(34, 177, 76)
BLACK = (0,0,0)

import random
import math




def main():
    width, height = 1024, 768
    hbox, vbox = 80, 80
    w, h = 640, 240
    screen = pg.display.set_mode((width, height))
    BG = pg.image.load('jungle.jpg').convert()
    img = pg.image.load('MONKEY.png')
    img = pg.transform.scale(img, (80, 80))
    img.convert()
    rect = img.get_rect()
    rect.center = w//2, h//2
    clock = pg.time.Clock()
    Score = 0
    class Circle(pg.sprite.Sprite):
        def __init__(self):
            #You can initialise the size to a random value
            self.pos = [random.randint(0, 1000), random.randint(180, 600)]
            self.color = (0,0, 0)
            self.radius = 20

        def draw(self):
            pg.draw.circle(screen, self.color, (self.pos[0], self.pos[1]), self.radius)


    circles = []

    for i in range(20):
        circles.append(Circle())

    def checkIntersection(c1, c2):
        dx = c1.pos[0] - c2.pos[0]
        dy = c1.pos[1] - c2.pos[1]
        d = math.hypot(dx, dy)
        if d < c1.radius + c2.radius:
            return True
        return False


    for i in range(19):
        while checkIntersection(circles[i], circles[i + 1]):
            circles[i].pos = random.randint(0, 1000), random.randint(0, 700)
        
        velocity = (0, 0)
        done = False

    while not done:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                done = True

        keys = pg.key.get_pressed()

        # booster
        move = 8 if keys[pg.K_LSHIFT] else 4

        if keys[pg.K_a]:  #to move left
            rect.x -= move
        if rect.x < 0 : rect.x = 0

        if keys[pg.K_d]: #to move right
            rect.x += move
        if rect.x > width-hbox : rect.x = width - hbox
        
        
        Score += 1
        rect.y += 2.5
        screen.blit(BG, (0,0))    
        screen.blit(img,rect)
        pg.draw.rect(screen, RED, rect, 1)
        pg.draw.polygon(screen, GREEN, ((1024,768), (0,768), (0,640),(1024,640)))
        font = pg.font.SysFont("comicsansms", 45)
        text = font.render (" " + str(Score), 1, BLACK)
        screen.blit(text,(480,700))
        pg.event.get()
        for circle in circles:
            circle.draw()
        pg.display.update()
        clock.tick(30)


if __name__ == '__main__':
    pg.init()
    main()
    pg.quit()
    sys.exit()
Henry Ecker
  • 34,399
  • 18
  • 41
  • 57
Send Help
  • 23
  • 2

1 Answers1

2

Use a "mask" collision. See How can I made a collision mask? and Pygame mask collision

Create a Sprite class with mask (see pygame.mask.from_surface):

class Circle(pg.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.pos = [random.randint(0, 1000), random.randint(180, 600)]
        self.color = (0,0, 0)
        self.radius = 20
        self.image = pg.Surface((self.radius*2, self.radius*2), pg.SRCALPHA)
        pg.draw.circle(self.image , self.color, (self.radius, self.radius), self.radius)
        self.rect = self.image.get_rect(center = self.pos)
        self.mask = pg.mask.from_surface(self.image)

Create a Sprite class for the player (also with a mask)

class Player(pg.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.image = pg.image.load('MONKEY.png')
        self.image = pg.transform.scale(self.image, (80, 80)).convert()
        self.rect = self.image.get_rect()
        self.rect.center = x, y
        self.mask = pg.mask.from_surface(self.image)

Manage the Sprites in pygame.sprite.Group and use pygame.sprite.spritecollide and pygame.sprite.collide_mask() for the collision test:

if pg.sprite.spritecollide(player, circles, False, collided  = pg.sprite.collide_mask):
    done = True

Complete example:

import sys
import pygame as pg
RED = (255, 0, 0)
GRAY = (150, 150, 150)
GREEN =(34, 177, 76)
BLACK = (0,0,0)

import random
import math

class Circle(pg.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.pos = [random.randint(0, 1000), random.randint(180, 600)]
        self.color = (0,0, 0)
        self.radius = 20
        self.image = pg.Surface((self.radius*2, self.radius*2), pg.SRCALPHA)
        pg.draw.circle(self.image , self.color, (self.radius, self.radius), self.radius)
        self.rect = self.image.get_rect(center = self.pos)
        self.mask = pg.mask.from_surface(self.image)

class Player(pg.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.image = pg.image.load('MONKEY.png')
        self.image = pg.transform.scale(self.image, (80, 80)).convert()
        self.rect = self.image.get_rect()
        self.rect.center = x, y
        self.mask = pg.mask.from_surface(self.image)

def main():
    width, height = 1024, 768
    hbox, vbox = 80, 80
    w, h = 640, 240
    screen = pg.display.set_mode((width, height))
    BG = pg.image.load('jungle.jpg').convert()
    clock = pg.time.Clock()
    Score = 0
    player = Player(w//2, h//2)
    all_sprites = pg.sprite.Group(player)
    circles = pg.sprite.Group()

    for i in range(20):
        circle = Circle()
        circles.add(circle)
        all_sprites.add(circle)

    def checkIntersection(c1, c2):
        dx = c1.pos[0] - c2.pos[0]
        dy = c1.pos[1] - c2.pos[1]
        d = math.hypot(dx, dy)
        if d < c1.radius + c2.radius:
            return True
        return False


    c = circles.sprites()
    for i in range(19):
        while checkIntersection(c[i], c[i + 1]):
            c[i].pos = random.randint(0, 1000), random.randint(0, 700)
        
        velocity = (0, 0)
        done = False

    while not done:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                done = True

        keys = pg.key.get_pressed()

        # booster
        move = 8 if keys[pg.K_LSHIFT] else 4

        if keys[pg.K_a]:  #to move left
            player.rect.x -= move
        if player.rect.x < 0 : player.rect.x = 0

        if keys[pg.K_d]: #to move right
            player.rect.x += move
        if player.rect.x > width-hbox : player.rect.x = width - hbox
        
        
        Score += 1
        player.rect.y += 2.5
        screen.blit(BG, (0,0))    
        pg.draw.rect(screen, RED, player.rect, 1)
        pg.draw.polygon(screen, GREEN, ((1024,768), (0,768), (0,640),(1024,640)))
        font = pg.font.SysFont("comicsansms", 45)
        text = font.render (" " + str(Score), 1, BLACK)
        screen.blit(text,(480,700))
        pg.event.get()
        all_sprites.draw(screen)
        pg.display.update()
        clock.tick(30)

        if pg.sprite.spritecollide(player, circles, False, collided  = pg.sprite.collide_mask):
            done = True


if __name__ == '__main__':
    pg.init()
    main()
    pg.quit()
    sys.exit()
Rabbid76
  • 202,892
  • 27
  • 131
  • 174