Python Forum
Too much values to unpack - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: Too much values to unpack (/thread-41576.html)



Too much values to unpack - actualpy - Feb-10-2024

So I'm trying to do a Space Invader-ish game, and I can't figure this out.
Says "Too much values to unpack (expected 3)"

Here's the code:
import pygame
from pygame import mixer
import math

pygame.init()
mixer.init()

mixer.music.load("9mm-pistol-shot-6349.mp3")
mixer.music.set_volume(0.5)

BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
WHITE = (255, 255, 255)

pW = 30
pH = 30

soldier = pygame.Rect(300, 370, pW, pH)

enemy1 = pygame.Rect(300, 0, pW, pH)
enemy2 = pygame.Rect(250, 50, pW, pH)
enemy3 = pygame.Rect(200, 0, pW, pH)
enemy4 = pygame.Rect(150, 50, pW, pH)
enemy5 = pygame.Rect(100, 0, pW, pH)
enemy6 = pygame.Rect(350, 50, pW, pH)
enemy7 = pygame.Rect(400, 0, pW, pH)
enemy8 = pygame.Rect(450, 50, pW, pH)
enemy9 = pygame.Rect(500, 0, pW, pH)
enemy10 = pygame.Rect(50, 50, pW, pH)

enemies = [enemy1, enemy2, enemy3, enemy4, enemy5, enemy6, enemy7, enemy8, enemy9, enemy10]

eB1 = pygame.Rect(0, 0, 5, 5)
eB2 = pygame.Rect(0, 0, 5, 5)
eB3 = pygame.Rect(0, 0, 5, 5)
eB4 = pygame.Rect(0, 0, 5, 5)
eB5 = pygame.Rect(0, 0, 5, 5)
eB6 = pygame.Rect(0, 0, 5, 5)
eB7 = pygame.Rect(0, 0, 5, 5)
eB8 = pygame.Rect(0, 0, 5, 5)
eB9 = pygame.Rect(0, 0, 5, 5)
eB10 = pygame.Rect(0, 0, 5, 5)

bullets = [eB1, eB2, eB3, eB4, eB5, eB6, eB7, eB8, eB9, eB10]
bullet_speed = 1

bullet = pygame.Rect(0, 0, 5, 5)

windowHeight = 400
windowWidth = 600

screen = pygame.display.set_mode((windowWidth, windowHeight))

# Load font
font = pygame.font.Font(None, 36)  # Default system font with size 36

# Initialize score
score = 0

# Constants for soldier shooting
RELOAD_TIME = 2000  # 2 seconds
last_shot_time = 0

key = pygame.key.get_pressed()

enemy_move_delay = 1000
last_enemy_move = pygame.time.get_ticks()

bulletFired = False
enemyBulletFired = False
enemyBulletCooldown = 1000
lastShoot = pygame.time.get_ticks()
whichBullet = 1  # Initialize bullet type

def moveEnemies():
    global last_enemy_move

    current_time = pygame.time.get_ticks()
    if current_time - last_enemy_move >= enemy_move_delay:
        for enemy in enemies:
            enemy.move_ip(0, 2)
        last_enemy_move = current_time

def moveBullet():
    global bulletFired
    global score

    if bulletFired:
        bullet.move_ip(0, -1)

        for enemy in enemies[:]:
            if bullet.colliderect(enemy):
                enemies.remove(enemy)
                score += 1  # Increment score when an enemy is hit

        if bullet.y < 0:
            bulletFired = False

def moveEnemyBullet():
    global enemyBulletFired
    global lastShoot
    global enemyBulletCooldown
    global bullets

    currentTime = pygame.time.get_ticks()

    if currentTime - lastShoot >= enemyBulletCooldown:
        lastShoot = currentTime

        # Iterate over enemies and fire bullets
        for enemy in enemies:
            if enemyBulletFired:
                # Calculate the direction vector from enemy to player
                direction_x = soldier.centerx - enemy.centerx
                direction_y = soldier.centery - enemy.centery

                # Normalize the direction vector
                length = math.sqrt(direction_x ** 2 + direction_y ** 2)
                if length != 0:
                    direction_x /= length
                    direction_y /= length

                # Create a bullet with initial position at the enemy
                bullet = pygame.Rect(enemy.centerx, enemy.centery, 5, 5)
                bullets.append((bullet, direction_x, direction_y))

        # Toggle enemyBulletFired
        enemyBulletFired = not enemyBulletFired

    # Move bullets and remove if they reach the window boundaries
    for bullet in bullets[:]:
        bullet_rect, _, _ = bullet
        bullet_rect.x += direction_x * bullet_speed
        bullet_rect.y += direction_y * bullet_speed

        if bullet_rect.y > windowHeight or bullet_rect.colliderect(soldier):
            bullets.remove(bullet)


def moveSoldier():
    global bulletFired
    global last_shot_time

    key = pygame.key.get_pressed()

    if key[pygame.K_d]:
        soldier.move_ip(1, 0)
    if key[pygame.K_a]:
        soldier.move_ip(-1, 0)

    # Check for shooting
    if key[pygame.K_SPACE] and pygame.time.get_ticks() - last_shot_time >= RELOAD_TIME:
        bulletFired = True
        last_shot_time = pygame.time.get_ticks()  # Update the last shot time
        bullet.x = soldier.x + soldier.width // 2 - bullet.width // 2  
        bullet.y = soldier.y
        mixer.music.play()

run = True

while run:
    screen.fill(BLACK)


    pygame.draw.rect(screen, GREEN, soldier)
    pygame.draw.rect(screen, WHITE, bullet)

    for enemy in enemies:
        pygame.draw.rect(screen, GREEN, enemy)

    # Draw enemy bullets
    
    for bullet in bullets:
        pygame.draw.rect(screen, GREEN, bullet)



    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    text_surface = font.render(f'Score: {score}', True, WHITE)  # Render score text
    text_rect = text_surface.get_rect()
    text_rect.topleft = (10, 10)  # Position of the text

    text_surface2 = font.render('You Won, GG', True, WHITE)  # Render text
    text_rect2 = text_surface2.get_rect()
    text_rect2.midright = (320, 170)  # Position of the text

    # Blit the text onto the screen
    screen.blit(text_surface, text_rect)

    moveSoldier()
    moveEnemies()
    moveBullet()
    moveEnemyBullet()

    if score == 10:
        screen.fill(BLACK)
        screen.blit(text_surface2, text_rect2)
    

    pygame.display.update()

pygame.quit()
Here's the error: ValueError: too many values to unpack (expected 3) (on line 132)
Thanks in advance.


RE: Too much values to unpack - deanhystad - Feb-10-2024

You need to be consistent. Initially you define bullets to be a list of rectangles.
eB1 = pygame.Rect(0, 0, 5, 5)
eB2 = pygame.Rect(0, 0, 5, 5)
eB3 = pygame.Rect(0, 0, 5, 5)
eB4 = pygame.Rect(0, 0, 5, 5)
eB5 = pygame.Rect(0, 0, 5, 5)
eB6 = pygame.Rect(0, 0, 5, 5)
eB7 = pygame.Rect(0, 0, 5, 5)
eB8 = pygame.Rect(0, 0, 5, 5)
eB9 = pygame.Rect(0, 0, 5, 5)
eB10 = pygame.Rect(0, 0, 5, 5)
 
bullets = [eB1, eB2, eB3, eB4, eB5, eB6, eB7, eB8, eB9, eB10]
Later on you add tuples to bullets:
                bullets.append((bullet, direction_x, direction_y))
This causes a problem when unpacking because somethmes bullets[x] will be just a rectangle, and other times it will be a rectangle and a direction (direction_x, direction_y).

You have a lot of problems in your code that are associated with bullets.

You only need to declare a variable as global when doing an assignment. You don't have to use global for accessing the variable. In this function:
def moveEnemyBullet():
    global enemyBulletFired
    global lastShoot
    global enemyBulletCooldown
    global bullets
You only need to declare enemyBulletFired and lastShoot using global. The other variables are not assigned in the function.
def moveEnemyBullet():
    global enemyBulletFired, lastShoot



RE: Too much values to unpack - actualpy - Feb-11-2024

Thanks! I'll add it on.


RE: Too much values to unpack - deanhystad - Feb-11-2024

You should read about sprites. They make programming in pygame much easier..

Here's a fairly extensive tutorial for making a space invaders pygame.