-2

Im having troubles with my snake code and keep getting the IndexError: list index out of range error message

I think the problem is at line 114

 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)

If there are any other problems in the code such as bugs or inconsistencies please tell me

But if you find the solution to the index problem please explain it because I am new to python Also a solution would be helpful

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 by Loneth')

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)
instructionsTitle = pygame.font.SysFont("arial", 48)


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



def snake(snakeBlock, snakeList):
    for x in snakeList:
        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):
        mx, my = 0, 0

        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

                    if selection[0].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()
                    elif choose == 2:
                        menu = False
                        main = False
                        intro = False
                        mainInt = False
                        mainMenu = False


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

            screen.fill(BLACK)

            # main instructions title
            insTitle = fontTitle.render("Instructions!", True, RED)
            insW = insTitle.get_width()
            insx = int(screenWidth/2 - insW/2)
            insy = 10
            screen.blit(insTitle, (insx,insy))

            # first line of instructions
            playerInsTitle = instructionsTitle.render("Hey youre a snake and that sucks.", True, RED)
            playW = playerInsTitle.get_width()
            playx = int(screenWidth/2 - playW/2)
            playy = 200
            screen.blit(playerInsTitle, (playx,playy))

            # second line of instructions
            playerInsTitle2 = instructionsTitle.render("as a snake you have to eat food and stay alive long enough to be crowned king of snakes", True, RED)
            play2W = playerInsTitle2.get_width()
            play2x = int(screenWidth/2 - play2W/2)
            play2y = 300
            screen.blit(playerInsTitle2, (play2x,play2y))

            #third line of instructions
            playerInsTitle3 = instructionsTitle.render("Avoid hitting your self or the walls or else you'll die", True, RED)
            play3W = playerInsTitle3.get_width()
            play3x = int(screenWidth/2 - play3W/2)
            play3y = 400
            screen.blit(playerInsTitle3, (play3x,play3y))

            # fourth line of instructions
            playerInsTitle4 = instructionsTitle.render("Now you know how to play the game!", True, RED)
            play4W = playerInsTitle4.get_width()
            play4x = int(screenWidth/2 - play4W/2)
            play4y = 500
            screen.blit(playerInsTitle4, (play4x,play4y))


            # Detects if Q is pressed and starts the game
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_q:
                    game = True
                    instructions = False


            pygame.display.update()


        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()
2
  • If selection[num] is throwing that error then clearly num is outside the range of the selection array. As an example, suppose you have an array with 10 elements and you try to get the 11th element from it, that's what that error means. Commented Jan 22, 2020 at 15:24
  • Does this answer your question? Index Error: list index out of range (Python) Commented Jan 22, 2020 at 15:24

1 Answer 1

0

It seems you have some indentation in def menu(): wrong and you don't check mouse position against all buttons.

To draw other buttons and prevent Index Error you can do this (I put comments starting with #!!! to the code):

def menu(titles):
    mx, my = 0, 0

    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

    #!!! Here was indentation wrong, move the whole `while` block to the left

    #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

            #!!! Here I put for-loop to check mouse position against every button:

            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

This will show:

enter image description here

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.