1
votes

I am new to python and am trying to write a game that launches a character and when he interacts with a sprite on the ground, something will change, for example speed. My apologies for the disorganization in my code. I have taken samples from a few tutorials and I can't make them work together.

How do I make the player's collision with the bomb detectable?

import pygame
import random
import math

drag = 1
gravity = (math.pi, .4)
elasticity = .75

# Colors
BLACK    = (   0,   0,   0)
WHITE    = ( 255, 255, 255)
BLUE     = (   0,   0, 255)
RED      = ( 255,   0,   0)
GREEN    = (   0, 255,   0)

# Screen dimensions
SCREEN_WIDTH  = 800
SCREEN_HEIGHT = 600

def addVectors((angle1, length1), (angle2, length2)):
    x = math.sin(angle1) * length1 + math.sin(angle2) * length2
    y = math.cos(angle1) * length1 + math.cos(angle2) * length2

    angle = 0.5 * math.pi - math.atan2(y, x)
    length = math.hypot(x, y)

    return (angle, length)

class Player(pygame.sprite.Sprite):

    change_x = 0
    change_y = 0

    level = None

    def __init__(self, x, y):

        pygame.sprite.Sprite.__init__(self)

        self.image = pygame.image.load('player.png')
        image_rect = self.image.get_rect()
        self.rect = pygame.rect.Rect(x, y, image_rect.width, image_rect.height)

    def update(self):
        pass

    def move(self):
        (self.angle, self.speed) = addVectors((self.angle, self.speed), gravity)
        self.rect.x += math.sin(self.angle) * self.speed
        self.rect.y -= math.cos(self.angle) * self.speed
        self.speed *= drag



    def bounce(self):
        if self.rect.x > 800 - self.rect.width:
            self.rect.x = 2*(800 - self.rect.width) - self.rect.x
            self.angle = - self.angle
            self.speed *= elasticity

        elif self.rect.x < 0:
            self.rect.x = 2*self.rect.width - self.rect.x
            self.angle = - self.angle
            self.speed *= elasticity

        if self.rect.y > SCREEN_HEIGHT - self.rect.height:
            self.rect.y = 2*(SCREEN_HEIGHT - self.rect.height) - self.rect.y
            self.angle = math.pi - self.angle
            self.speed *= elasticity

class Bomb(pygame.sprite.Sprite):

    def __init__(self, x, y):

        pygame.sprite.Sprite.__init__(self)

        self.image = pygame.image.load('cherry.png')
        image_rect = self.image.get_rect()
        self.rect = pygame.rect.Rect(x, y, image_rect.width, image_rect.height)


class Level():

    bomb_list = None
    world_shift = 0

    def __init__(self, player):
        self.bomb_list = pygame.sprite.Group()
        self.player = player

    def update(self):
        self.bomb_list.update()

    def draw(self, screen):
        screen.fill(BLACK)

        self.bomb_list.draw(screen)

    def shift_world(self, shift_x):

        self.world_shift += shift_x

        for bomb in self.bomb_list:
            bomb.rect.x += shift_x

            if bomb.rect.x < 0:
                self.bomb_list.remove(bomb)
                self.bomb_list.add(Bomb(random.randint(SCREEN_WIDTH, 2*SCREEN_WIDTH), 580)) 

I am not sure if this Level_01 class is even necessary:

class Level_01(Level):

    def __init__(self, player):

        Level.__init__(self, player)

        bombs = 0
        for n in range(10):
            self.bomb_list.add(Bomb(random.randint(0, SCREEN_WIDTH), 580))

This was my attempt at a collision detection method. I'm not sure if it should be in a class, in main, or seperate. I can't seem to get the list of bombs, and the player at the same time.

def detectCollisions(sprite1, sprite_group):
    if pygame.sprite.spritecollideany(sprite1, sprite_group):
        sprite_group.remove(pygame.sprite.spritecollideany(sprite1, sprite_group))
        print True
    else:
        print False


def main():

    pygame.init()

    size = [SCREEN_WIDTH, SCREEN_HEIGHT]
    screen = pygame.display.set_mode(size)


    active_sprite_list = pygame.sprite.Group()
    enemy_list = pygame.sprite.Group()

    player = Player(0, 0)
    player.speed = 30
    player.angle = math.radians(45)

    player.rect.x = 500
    player.rect.y = SCREEN_HEIGHT - player.rect.height
    active_sprite_list.add(player)

    done = False

    clock = pygame.time.Clock()

    current_level = Level_01(player)

    while not done:

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                done = True

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    player.go_left()
                if event.key == pygame.K_RIGHT:
                    player.go_right()           

        active_sprite_list.update()
        enemy_list.update()
        player.level = current_level
        player.move()
        player.bounce()

        if player.rect.x >= 500:
            diff = player.rect.x - 500
            player.rect.x = 500
            current_level.shift_world(-diff)

        if player.rect.x <= 120:
            diff = 120 - player.rect.x
            player.rect.x = 120
            current_level.shift_world(diff)

        current_level.draw(screen)
        active_sprite_list.draw(screen)
        enemy_list.draw(screen)

        clock.tick(60)

        pygame.display.flip()

    pygame.quit()

if __name__ == "__main__":
    main()

Thanks for helping me out!

2
What's your question...? - But I'm Not A Wrapper Class
Sorry, I tried to clarify above. I just want to be able to detect when there is a collision between the player and a bomb - Jeremy Thomas
This seems pretty broad. Is there something specific about collision detection that isn't working for you? - skrrgwasme

2 Answers

0
votes

Probably the easiest thing to do is to draw out pixels (or virtual pixels) and if in drawing bomb/person pixels you find an overlap then you know a collision occurred.

You can however get way more complicated (and efficient) in your collision detection if you need a higher performance solution. See Wikipedia Collision Detection for a reference.

0
votes

I suggest creating sprite groups using pygame.sprite.Group() for each class; Bomb and Player. Then, use pygame.sprite.spritecollide().

For example:

def Main()   
    ...
    player_list = pygame.sprite.Group()
    bomb_list = pygame.sprite.Group()
    ...

Then in your logic handling loop, after creating a Player and Bomb instance, you could do something like this:

for bomb in bomb_list:
    # See if the bombs has collided with the player.
        bomb_hit_list = pygame.sprite.spritecollide(bomb, player_list, True)

        # For each bomb hit, remove bomb 
        for bomb in bomb_hit_list:
            bomb_list.remove(bomb)
            # --- Put code here that will trigger with each collision ---