Search code examples
pythonpython-3.xpygamecollision-detectionpygame-surface

How do I get score feature in pygame program?


I have been trying to record score in a variable in a simple game I've been attempting to make. Score gets incremented when distance between bullet and and alien(enemy in code) is less than a certain value (here, 20 units).

When I hit the alien with the bullet, however, the score does not increment. What do I do?

import pygame
import random
import math

# for initialising pygame (req for every pygame app)
pygame.init()

# making the basic window (dimensions must be written inside a tuple )
screen = pygame.display.set_mode((500, 500))

# background
background = pygame.image.load('C:/Users/aryan/Downloads/background.jpg')

# load and set the logo
logo = pygame.image.load('C:/Users/aryan/Downloads/bp.png')  # directory of logo
pygame.display.set_icon(logo)
pygame.display.set_caption("space wars")  # program name

# define a variable to control the main loop
running = True

# player
playerimg = pygame.image.load('C:/Users/aryan/Downloads/spaceship.png')
playerX = 218  # x and y coordinates of image
playerY = 350
playerxchange = 0  # this will be the change in movement in x direction of our image
playerychange = 0  # this will be the change in movement in y direction of our image


def player(x, y):
    screen.blit(playerimg, (x, y))  # blit draws our image on the surface(basically the background)
    # syntax for blit(imagename, (xcoordinate,ycoordinate))


# enemy
enemyimg = pygame.image.load('C:/Users/aryan/Downloads/enemy.png')
enemyX = random.randint(0, 476)
enemyY = 20
enemyxchange = 0.2
enemyychange = 40

# game over
overimg = pygame.image.load('C:/Users/aryan/Downloads/gameover.png')

# bullet
bulletimg = pygame.image.load('C:/Users/aryan/Downloads/bullet.png')
bulletX = 0
bulletY = 350
bulletxchange = 0
bulletychange = 1
bullet_state = "ready"              # "ready" you cant see bullet on screen
                                    # "fire" you can see bullet firing

bullets = []  # Array to store the position of the bullets

score = 0

def enemy(x, y):
    screen.blit(enemyimg, (x, y))  # blit draws our image on the surface(basically the background)
    # syntax for blit(imagename, (xcoordinate,ycoordinate))


def firebullet(x, y):
    global bullet_state
    bullet_state = "ready"
    bullets.append([x + 12, y + 6]) # Creating a new bullet


def iscollision(enemyX, enemyY, bulletX, bulletY):
    distance = math.sqrt(math.pow(enemyX-bulletX, 2)+ math.pow(enemyY-bulletY,2))     # distance formula
    if distance <= 20:
        return True
    else:
        return False



# main loop
while running:
    screen.fill((120, 120, 120))  # in order (r, g, b) . (0, 0, 0) is black (255, 0, 0) is red...
    screen.blit(background, (0, 0))
    # event handling, gets all event from the event queue
    for event in pygame.event.get():
        # only do something if the event is of type QUIT
        if event.type == pygame.QUIT:
            # change the value to False, to exit the main loop
            running = False

        # checking keystroke
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_RIGHT:
                playerxchange += 0.2  # change in movement will be 0.2 towards the right
            if event.key == pygame.K_LEFT:
                playerxchange -= 0.2  # change in movement will be 0.2 towards the right
            if event.key == pygame.K_UP:
                playerychange -= 0.2
            if event.key == pygame.K_DOWN:
               playerychange += 0.2
            if event.key == pygame.K_SPACE:
                bullet_state = "fire"
                firebullet(playerX, playerY)
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT or event.key == pygame.K_DOWN or event.key == pygame.K_UP:
                playerxchange = 0
                playerychange = 0

    playerY += playerychange
    playerX += playerxchange  # the value of playerx changes by +- 0.1 depending on keystroke

    if playerX <= -64:  # this teleports the spaceship from left end to right end
        playerX = 564
    elif playerX >= 564:  # this teleports spaceship from right end to left
        playerX = -64

    if playerY >= 436:  # this prevents spaceship from leaving vertically
        playerY = 436
    if playerY <= 0:
        playerY = 0

    # enemy movement
    enemyX += enemyxchange

    if enemyY >= 476:
        enemyY = 476
        enemyYchange = 0
        enemyXchange = 0

    if enemyX <= 0:
        enemyxchange = 0.1
        enemyY += enemyychange
    elif enemyX >= 465:
        enemyxchange = -0.1
        enemyY += enemyychange

    # bullet movement
    if bullet_state is "fire":
        firebullet(playerX, playerY)


    for bullet in bullets:
        screen.blit(bulletimg, (bullet[0], bullet[1]))  # Print a bullet
        bullet[0] -= bulletxchange  # Updates its position
        bullet[1] -= bulletychange
        if bullet[1] < 0:
            bullets.remove(bullet)

    # collision
    collision = iscollision(enemyX, enemyY, bulletX, bulletY)
    if collision:
        score += 1

    player(playerX, playerY)  # player method is called AFTER screen.fill otherwise the screen will fill after image has been blitted
    enemy(enemyX, enemyY)

    pygame.display.update()  # necessary for events to keep updating


Solution

  • You need to test the actual position of the bullets. Use a for-loop to iterate through all the bullets in the list. Test if a single bullet collides with the enemy inside the loop. Remove the bullet from the list when it collides with the enemy. For this reason, a copy of the list (bullets[:]) must be run through (see How to remove items from a list while iterating?):

    while running:
        # [...]
    
        # collision
    
        #collision = iscollision(enemyX, enemyY, bulletX, bulletY) DELETE
        #if collision:                                             DELETE
        #    score += 1                                            DELETE 
    
        # ADD
        for bullet in bullets[:]:
            collision = iscollision(enemyX, enemyY, bullet[0], bullet[1])
            if collision:
                score += 1
                print(score)
                bullets.remove(bullet)
    

    If you don't remove the bullet, it will hit the enemy multiple times in consecutive frames and the score will be increased multiple times. Alternatively you can remove the enemy or the enemy and the bullet.


    Use pygame.Rect objects and colliderect() to detect the collision between the bounding rectangles of 2 objects or 2 images:
    (see How to detect collisions between two rectangular objects or images in pygame)

    def iscollision(enemyX, enemyY, bulletX, bulletY):
        bullet_rect = bulletimg.get_rect(topleft = (bulletX, bulletY))
        enemy_rect = enemyimg.get_rect(topleft = (enemyX, enemyY))
        return bullet_rect.colliderect(enemy_rect)