pythonpygamecharactergame-developmentpls

Pygame Character wont move left or right


In my below code using PyGame, the character won't move left or right and the bullet won't shoot. I'm not sure what's causing this. It works without the whole start menu with buttons concept so I was wondering if that is the issue?

import pygame
from pygame import mixer
import math
import random
import time

# Initialize pygame module
pygame.init()

# Create the screen
screen = pygame.display.set_mode((800, 600))
display_width = 800
display_height = 600

# Background
background = pygame.image.load('space1.jpg')

# Background Sound
mixer.music.load('background.wav')
mixer.music.play(-1)

# Title and Icon
pygame.display.set_caption('Space Invaders')
icon = pygame.image.load('ufo.png')
pygame.display.set_icon(icon)

# Player
playerImg = pygame.image.load('space-invaders.png')
playerX = 370
playerY = 480
player_change = 0
playerX += player_change

# Enemy
enemyImg = []
enemyX = []
enemyY = []
enemyX_change = []
enemyY_change = []
num_of_enemies = 6

# Colours
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (150, 0, 0)
GREEN = (0, 150, 0)
BRIGHT_RED = (255, 0,0)
BRIGHT_GREEN = (0, 255, 0)


for i in range(num_of_enemies):
    enemyImg.append(pygame.image.load('alien.png'))
    enemyX.append(random.randint(0, 736))
    enemyY.append(random.randint(50, 150))
    enemyX_change.append(2)
    enemyY_change.append(40)

# Bullet

# Ready - You cant see the bullet on the screen
# Fire - The bullet is current moving
bulletImg = pygame.image.load('bullet.png')
bulletX = 0
bulletY = 480

bulletY_change = 10
bullet_state = 'ready'

# Score
score_value = 0
font = pygame.font.Font('freesansbold.ttf', 32)

textX = 10
textY = 10

# Game Over Text
over_font = pygame.font.Font('freesansbold.ttf', 64)

# Clock
clock = pygame.time.Clock()

def show_score(x, y):
    score = font.render('score : ' + str(score_value), True, (0, 255, 0))
    screen.blit(score, (x, y))

def game_over_text():
    over_text = over_font.render('GAME OVER', True, (0, 255, 0))
    screen.blit(over_text, (200, 250))

def player(x, y):
    screen.blit(playerImg, (x, y))


def enemy(x, y, i):
    screen.blit(enemyImg[i], (x, y))


def fire_bullet(x, y):
    global bullet_state
    bullet_state = 'fire'
    screen.blit(bulletImg, (x + 16, y + 10))

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

def text_objects(text, font):
    textSurface = font.render(text, True, WHITE)
    return textSurface, textSurface.get_rect()

def game_intro():
    intro = True

    while intro:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            screen.fill(BLACK)
            largeText = pygame.font.Font('freesansbold.ttf', 105)
            TextSurf, TextRect = text_objects('Space Invaders', largeText)
            TextRect.center = ((display_width/2), 200)
            screen.blit(TextSurf, TextRect)

            button('Start Invasion', 325, 350, 150, 50, GREEN, BRIGHT_GREEN, 'play')
            button('Quit Mission', 325, 450, 150, 50, RED, BRIGHT_RED, 'quit')

            pygame.display.update()
            clock.tick(15)

#Game Loop

def game_loop(playerX, playerY, player_change, bulletX, bulletY, bulletX_change, bulletY_change, bullet_state, bulletImg):
    running = True
    while running:
        playerX = 370
        playerY = 480
        player_change = 0
        playerX += player_change

        # RGB         R    G    B
        screen.fill((0, 0, 0))
        # Background Image
        screen.blit(background, (0, 0))
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False

            # If keystroke is pressed check whether its left or right
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    player_change = -5
                if event.key == pygame.K_RIGHT:
                    player_change = 5
                if event.key == pygame.K_SPACE:
                    if bullet_state is 'ready':
                        bullet_sound = mixer.Sound('laser.wav')
                        bullet_sound.play()
                        # Get the current x coordinate of the spaceship
                        bulletX = playerX
                        fire_bullet(bulletX, bulletY)

            if event.type == pygame.KEYUP:
                if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
                    player_change = 0

        # boundary for spaceship
        if playerX <= 0:
            playerX = 0
        elif playerX >= 736:
            playerX = 736

        # Enemy movement
        for i in range(num_of_enemies):

            # Game Over
            if enemyY[i] > 440:
                for j in range(num_of_enemies):
                    enemyY[j] = 2000
                game_over_text()
                break

            enemyX[i] += enemyX_change[i]
            if enemyX[i] <= 0:
                enemyX_change[i] = 2
                enemyY[i] += enemyY_change[i]
            elif enemyX[i] >= 736:
                enemyX_change[i] = -2
                enemyY[i] += enemyY_change[i]
            # Collision
            collision = isCollision(enemyX[i], enemyY[i], bulletX, bulletY)
            if collision:
                explosion_sound = mixer.Sound('explosion.wav')
                explosion_sound.play()
                bulletY = 480
                bullet_state = "ready"
                score_value += 1
                enemyX[i] = random.randint(0, 736)
                enemyY[i] = random.randint(50, 150)

            enemy(enemyX[i], enemyY[i], i)

        # Bullet movement
        if bulletY <= 0:
            bulletY = 480
            bullet_state = 'ready'
        if bullet_state is 'fire':
            fire_bullet(bulletX, bulletY)
            bulletY -= bulletY_change

        player(playerX, playerY)
        show_score(textX, textY)
        pygame.display.update()

def button(msg, x, y, w, h, inactivecolour, activecolour, action=None):
    mouse = pygame.mouse.get_pos()
    click = pygame.mouse.get_pressed()
    if x + w > mouse[0] > x and y + h > mouse[1] > y:
        pygame.draw.rect(screen, activecolour, (x, y, w, h))
        if click[0] == 1 and action != None:
            if action == 'play':
                game_loop(370, 480, 0, 0, 480, 0, 10, 'ready', pygame.image.load('bullet.png'))
            if action == 'quit':
                pygame.quit()
                quit()

    else:
        pygame.draw.rect(screen, inactivecolour, (x, y, w, h))

    smallText = pygame.font.Font('freesansbold.ttf', 20)
    textSurf, textRect = text_objects(msg, smallText)
    textRect.center = ((x + (w / 2)), (y + (h / 2)))
    screen.blit(textSurf, textRect)

game_intro()

Solution

  • the character won't move

    The movement of the player player_change is continuously set 0, in the main application loop. Further more, the position of the player is continuously initialized:

    def game_loop(playerX, playerY, player_change, bulletX, bulletY, bulletX_change, >bulletY_change, bullet_state, bulletImg):
       running = True
       while running:
           playerX = 370
           playerY = 480
           player_change = 0
    

    Initialize playerX, playerY and player_change before the loop:

    def game_loop(playerX, playerY, player_change, bulletX, bulletY, bulletX_change, bulletY_change, bullet_state, bulletImg):
        running = True
        player_change = 0
        playerX = 370
        playerY = 480
        while running:    
            playerX += player_change
            # [...]
    

    the bullet won't shoot

    If you want to fire a bullet, then you have to set the initial position of the bullet bulletX, bulletY = playerX, playerY and set bullet_state = 'fire':

    def game_loop(playerX, playerY, player_change, bulletX, bulletY, bulletX_change, bulletY_change, bullet_state, bulletImg):
        # [...]    
    
        while running:    
            playerX += player_change
    
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    running = False
    
                # If keystroke is pressed check whether its left or right
                if event.type == pygame.KEYDOWN:
                    # [...]               
    
                    if event.key == pygame.K_SPACE:
                        if bullet_state is 'ready':
                            #bullet_sound = mixer.Sound('laser.wav')
                            #bullet_sound.play()
                            # Get the current x coordinate of the spaceship
                            bulletX, bulletY = playerX, playerY
                            bullet_state = 'fire'
    

    Note, the global variable bullet_state

    def fire_bullet(x, y):
       global bullet_state
       bullet_state = 'fire'
    

    is different to the local variable bullet_state in game_loop, because bullet_state is an argument to game_loop and thus a completely different variable in a different scope, which has casually the same name:

    def game_loop(playerX, playerY, player_change, bulletX, bulletY, 
                  bulletX_change, bulletY_change, 
                  bullet_state, # <--- that is a new variable in local scope
                                #      and not the "global" bullet_state
                  bulletImg):
        # [...]