3

My current code makes any added length from eating apples just stay in a straight line behind the head of a snake. How do I make it so it is a trail like normal snake games? If someone could help me approach the problem rather than pasting could that would be nice.

here is my full code (it uses png files so it might not run if you try it)

import pygame, random, time

pygame.init()

screenWidth = 500
screenHeight = 500
window = pygame.display.set_mode((screenWidth, screenHeight))
pygame.display.set_caption("Snake")
x = random.randint(30, 440)
y = random.randint(30, 44)
snakex = x-30
snakey = y
previousx = snakex
previousy = snakey
run = True
appleNeeded = True
direction = "right"
lengthNeeded = False
length1 = True
lengthAmount = 3
check = True


snake_body = []
#Create images (Snake head, apple, and snake tail)

#class SnakeHead(pygame.sprite.Sprite):

#   def __init__(self, ):
snakeHeadUp = pygame.image.load("snakeHeadUp.png")
snakeHeadUp = pygame.transform.scale(snakeHeadUp, (30, 30))
snakeHeadLeft = pygame.image.load("snakeHeadLeft.png")
snakeHeadLeft = pygame.transform.scale(snakeHeadLeft, (30, 30))
snakeHeadRight = pygame.image.load("snakeHeadRight.png")
snakeHeadRight = pygame.transform.scale(snakeHeadRight, (30, 30))
snakeHeadDown = pygame.image.load("snakeHeadDown.png")
snakeHeadDown = pygame.transform.scale(snakeHeadDown, (30, 30))
apple = pygame.image.load("apple.png")
apple = pygame.transform.scale(apple, (30, 30))
snakeHead = snakeHeadRight

while run:
    if check == True:
        snake_body.append((x, y))
        check = False

    #Create screen with boundaries
    window.fill((0, 0, 255))

    #Create snake head (sprite)

    #Create snake


    #Create apple randomly (either rect or sprite) and if needed
    if appleNeeded == True:
        randomx = random.randint(30, 440)
        randomy = random.randint(30, 440)
        if randomx > 5:
            randomx = randomx - (randomx % 5)
        elif randomx < 5:
            randomx = randomx + (5 % randomx)
        if randomy > 5:
            randomy = randomy - (randomy % 5)
        elif randomy < 5:
            randomy = randomy + (5 % randomy)

        appleNeeded = False
    window.blit(apple, (randomx, randomy))

    #Determine if snake head has touched apple
    if x-15 >= randomx-30 and x-15 < randomx and y-15 >= randomy-30 and y-15 < randomy:
        appleNeeded = True
        lengthAmount += 1
        snake_body.append("1")

    #Check for key updates

    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT]:
        direction = "left"
        snakeHead = snakeHeadLeft
    if keys[pygame.K_RIGHT]:
        direction = "right"
        snakeHead = snakeHeadRight
    if keys[pygame.K_UP]:
        direction = "up"
        snakeHead = snakeHeadUp
    if keys[pygame.K_DOWN]:
        direction = "down"
        snakeHead = snakeHeadDown

    if direction == "left":
        x -= 5
        snakex = x+30
        snakey = y
    elif direction == "right":  
        x += 5
        snakex = x-30
        snakey = y
    elif direction == "up":
        y -= 5
        snakex = x
        snakey = y+30
    elif direction == "down":
        y += 5
        snakex = x
        snakey = y-30


    #Update snake length
    window.blit(snakeHead, (x, y))
    for i in range(lengthAmount):
        if i == 0:
            previousx = snakex - (30 * i)
            previousy = snakey
        if direction == "left":
            previousx = snakex + (30 * i)
            previousy = snakey
        elif direction == "right":  
            previousx = snakex - (30 * i)
            previousy = snakey
        elif direction == "up":
            previousx = snakex 
            previousy = snakey + (30 * i)
        elif direction == "down":
            previousx = snakex  
            previousy = snakey - (30 * i)

        for body in snake_body:
            pygame.draw.rect(window, (0, 175, 0), (previousx, previousy, 30, 30))


    #Don't allow snake to leave the window (game over if True)
    if x >= 470 or x <= 0 or y <= 0 or y >= 470:
        run = False

    #Don't allow snake to eat itself (game over if True)


    pygame.display.update()

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

pygame.quit()
Lore
  • 103
  • 1
  • 6
  • I added some code so it is the same problem but different code. – Lore May 10 '19 at 14:04
  • @Lore, does Rabbid76's answer to your previous question not work? Why are you asking another question that is almost alike to your previous one that was answered already? – marsnebulasoup May 10 '19 at 14:09
  • The logic is the same of what is explained in the duplicate question. You are asking the same thing. Do not expect that we implement the logic in your code. If instead you have a specific problem in your code, rephase the question asking about that specific problem. – Valentino May 10 '19 at 14:20
  • @Valentino I thought so, too. But it turns out, that I was wrong. The answer in the other question assumes, that one step of the shake is equal the size of one part the body (as in most trivial snake games around here). Bit in this case the size of the body is 30 and one step is 5. So the first part of the body has to be draw at the place, where the snakes head was 6 frames before. – Rabbid76 May 10 '19 at 14:41
  • @Rabbid76 I admit I didn't go through the code. If so, you are right, it's not a duplicate. – Valentino May 10 '19 at 15:33
  • See also [How do I chain the movement of a snake's body?](https://stackoverflow.com/questions/62010434/how-do-i-chain-the-movement-of-a-snakes-body/62010435#62010435) – Rabbid76 Oct 05 '20 at 17:44

1 Answers1

4

In your case this is a bit tricky. See How do I chain the movement of a snake's body?.

You have to store all the positions, which have been met by the snake in a list.
The length of a part of the snake is 30 and the size of a step is 5. So each 6th position in the list is the position of one part of the snakes body:

snake_pos = []
while run:

    # [...]
    
    # append position at the head of the list
    snake_pos = [(x, y)] + snake_pos

    # draw the parts of the body at each 6th position of the list 
    for i in range(lengthAmount):
        pi = min((i+1)*6, len(snake_pos)-1)
        pygame.draw.rect(window, (0, 175, 0), (*snake_pos[pi], 30, 30))

    #window.blit(snakeHead, (x, y))
    pygame.draw.rect(window, (175, 50, 0), (x, y, 30, 30))

    # delete all paositons from the list which are not further need
    del snake_pos[lengthAmount*6:]

Rabbid76
  • 202,892
  • 27
  • 131
  • 174