Loneth B
Loneth B

Reputation: 41

Snake game error code (IndexError: list index out of range)

Im creating a snake Pygame with a menu and am fine tuning the bugs and such when I come across the error

IndexError: list index out of range

the error actually appears after I open the tab itself and move the cursor over it

I have a faint idea of what it actually means but I am quite new to python and coding in general so I would appreciate it if someone could explain and show a solution,

thank you very much and here is the code

import pygame
import sys
import random
import time

pygame.init()

WHITE = (255, 255, 255)
YELLOW = (255, 255, 102)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
DARKRED = (125, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)

screenWidth = 800
screenHeight = 800

screen = pygame.display.set_mode((screenWidth, screenHeight))
pygame.display.set_caption('Snake Game')

clock = pygame.time.Clock()

snakeBlock = 10
snakeSpeed = 15

fontTitle = pygame.font.SysFont("arial",100)
fontStyle = pygame.font.SysFont("ariel", 50)
scoreFont = pygame.font.SysFont("ariel", 35)


def score(score):
    value = scoreFont.render(" Score: " + str(score), True, BLACK)
    screen.blit(value, [50, 50])



def snake(snakeBlock, snake_list):
    for x in snake_list:
        pygame.draw.rect(screen, GREEN, [x[0], x[1], snakeBlock, snakeBlock])


def message(msg, colour):
    msg = fontStyle.render(msg, True, BLACK)
    screen.blit(msg, [screenWidth / 20, screenHeight / 2])


def gameLoop():

    gameOver = False
    gameEnd = False
    instructions = False
    game = True
    intro = True
    main = True



    x1 = screenWidth / 2
    y1 = screenHeight / 2

    dx = 0
    dy = 0

    snakeList = []
    snakeLength = 2

    foodx = round(random.randrange(0, screenWidth - snakeBlock) / 10.0) * 10.0
    foody = round(random.randrange(0, screenHeight - snakeBlock) / 10.0) * 10.0

    def menu(titles):
        buttonTitleFont = pygame.font.SysFont("arial", 52)
        selection = []
        rectWidth = 400
        rectHeight = 60
        x = int(screen.get_width()/2 - rectWidth/2)
        y = 450
        length = len(titles)
        num = 0
        hover = False
        # creates the Rects (containers) for the buttons

        for i in range (0,length,1):
            choiceRect = pygame.Rect(x,y,rectWidth,rectHeight)
            selection.append(choiceRect)
            y += 100

            #main loop in menu    
            menu = True
            while menu:    
                for event in pygame.event.get():
                    if event.type == pygame.QUIT:
                        menu = False
                        pygame.quit()
                        sys.exit()
                    if event.type ==pygame.MOUSEMOTION:     # if mouse moved
                        hover = False
                        mx, my = pygame.mouse.get_pos()     # get the mouse position
                        for i in range (length):            
                            if selection[i].collidepoint((mx,my)):  # check if x,y of mouse is in a button
                                num = i
                                hover = True
                    if event.type == pygame.MOUSEBUTTONDOWN and hover == True:  #if mouse is in button
                        menu = False                                              # and has been clicked

                # draw all buttons                                                                
                for choice in selection:
                    pygame.draw.rect(screen,WHITE,choice,0)

                # redraw selected button in another colour
                pygame.draw.rect(screen,GREEN,selection[num],0)

                # draw all the titles on the buttons
                x = int(screen.get_width()/2 - 150)
                y = 450
                for i in range(0,length,1):
                    buttonTitle = buttonTitleFont.render(titles[i],True,BLACK)
                    screen.blit(buttonTitle,(x,y))
                    y += 100

                pygame.display.update()
            return num

    while main:
        for event in pygame.event.get(): # check for any events (i.e key press, mouse click etc.)
            if event.type ==pygame.QUIT: # check to see if it was "x" at top right of screen
                main = False         # set the "main" variable to False to exit while loop

        while intro:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    main = False
                    intro = False

            screen.fill(BLACK)

            menuMain = ["Launch", "Instructions","QUIT"]

            mainMenu = True
            mainInt = True
            while mainInt:
                for event in pygame.event.get():
                    if event.type == pygame.QUIT:
                        main = False
                        intro = False
                        mainInt = False

                screen.fill(BLACK)

                #Centers the rendered tiles
                textTitle = fontTitle.render("Snake", True, GREEN )
                textW = textTitle.get_width()
                textH = textTitle.get_height()
                xTitle = int(screenWidth/2 - textW/2)
                yTitle = int(screenHeight/4 - textH/2)
                screen.blit(textTitle, (xTitle,yTitle))
                pygame.display.update()

                # in the intro, this asks the user where they would like to go
                if mainMenu ==True:
                    choose = menu(menuMain)
                    if choose == 0:
                        menu = False
                        intro = False
                        mainInt = False
                        mainMenu = False
                        game = True
                        screen.fill(BLACK)
                    elif choose ==1:
                        menu = False
                        instructions = True
                        mainMenu = False
                        screen.fill(BLACK)
                        pygame.display.update()
                    else:
                        menu = False
                        main = False
                        intro = False
                        mainInt = False
                        mainMenu = False

        while game: 

            if gameOver == True:
                game = False

            while gameEnd == True:
                screen.fill(DARKRED)
                message("You Lost! Press C to Play Again or Q to Quit", RED)
                score(snakeLength - 1)
                pygame.display.update()

                for event in pygame.event.get():
                    if event.type == pygame.KEYDOWN:
                        if event.key == pygame.K_q:
                            gameOver = True
                            gameEnd = False
                        if event.key == pygame.K_c:
                            gameLoop()

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    gameOver = True
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_LEFT:
                        dx = -snakeBlock
                        dy = 0
                    elif event.key == pygame.K_RIGHT:
                        dx = snakeBlock
                        dy = 0
                    elif event.key == pygame.K_UP:
                        dx = 0
                        dy = -snakeBlock
                    elif event.key == pygame.K_DOWN:
                        dx = 0
                        dy = snakeBlock

            if x1 >= screenWidth or x1 < 0 or y1 >= screenHeight or y1 < 0:
                gameEnd = True

            x1 += dx
            y1 += dy

            screen.fill(WHITE)

            pygame.draw.rect(screen, RED, [foodx, foody, snakeBlock, snakeBlock])
            snakeHead = []
            snakeHead.append(x1)
            snakeHead.append(y1)
            snakeList.append(snakeHead)

            if len(snakeList) > snakeLength:
                del snakeList[0]

            for x in snakeList[:-1]:
                if x == snakeHead:
                    gameEnd = True

            snake(snakeBlock, snakeList)
            score(snakeLength - 1)

            pygame.display.update()

            if x1 == foodx and y1 == foody:
                foodx = round(random.randrange(0, screenWidth - snakeBlock) / 10.0) * 10.0
                foody = round(random.randrange(0, screenHeight - snakeBlock) / 10.0) * 10.0
                snakeLength += 1

            clock.tick(snakeSpeed)

        pygame.quit()
        quit()


gameLoop()


Upvotes: 2

Views: 243

Answers (1)

Lapis Rose
Lapis Rose

Reputation: 644

I see that in your code, you're referencing selection[some_index] multiple times. If you look into what selection actually is, you'll find that it's an array with one rectangle object inside of it:

[<rect(200, 450, 400, 60)>]

This rectangle never changes, so I suggest referencing it directly by calling

selection[0]

For example, here is the snippet of code that's giving you the error.

for i in range (length):   
    if selection[i].collidepoint((mx,my)):  # check if x,y of mouse is in a button
        num = i
        hover = True

Because selection is an array with one element that never changes, you get an Index out of range error after the first iteration of your for loop. Perhaps this looks familiar:

IndexError: list index out of range

What you can do to fix this is get rid of the loop (because it's unnecessary - you shouldn't be looping through indices if there's only one rectangle in the selection list!) and extracting the rectangle at the 0-th index.


if selection[0].collidepoint((mx,my)):  # check if x,y of mouse is in a button
    num = i
    hover = True

This isn't the only bug I ran into in your code, but I believe this will help you on your way!

Upvotes: 3

Related Questions