[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [pygame] Odd behaviour of sprites in a list - newbie help please?



Yes, also Snake.append(Snake[0]) surely doesn't do what you want.

On 6/24/2019 12:26 PM, dejohnso wrote:
Hi,

Each segment of your snake is a reference to the same pygame rect. So when you move one, they all appear to move. The line

Snake[tail] = Snake[tail-1]

Is not making new rect. If you print out the id of each segment, you should see that they are the same object. 

Use Rect.copy() to make the ones in the list be disconnected to the original. Or append a new Rect where the head has moved (you don’t really need to copy everything yourself, you can insert a new one at the front and remove it from the back).

Thanks,
David


On Jun 24, 2019, at 11:28 AM, DR0ID <dr0id@xxxxxxxxxx> wrote:

On 24.06.2019 17:19, Adam Coombes wrote:
I've created a list of sprites to try and make a basic 'snake' game. The idea is to shuffle each sprite to the position of the next, starting at the end of the tail, and then move the head. As I append new tail pieces, they should 'snake' along. However, when I move the head sprite ( Snake[0] in my list 'Snake'), they all seem to move to the same position. Even when I omit the line that moves them along by commenting out 'Snake[tail] = Snake[tail-1]' in my for loop, it still moves every sprite in the list Snake[] to the same place as Snake[0], which is inexplicable to me as I'm not even moving them then. Can anyone point out my mistake please? This is just a learner project, but it's driving me nuts.

import pygame, sys
from pygame.locals import*
import random
#colours========================================================
BLACK = (0,0,0)
WHITE = (255,255,255)
RED = (255,0,0)
GREEN = (0,255,0)
BLUE = (0,0,255)
PURPLE = (128,0,128)
GREY = (128,128,128)
YELLOW = (255,255,0)
pygame.init()
Height = 1920
Width = 1080
score = 0
basicfont = pygame.font.SysFont(None, 50)
Score = basicfont.render("Score: " + str(score), True, WHITE, GREEN)
ScoreRect = Score.get_rect()
ScoreRect.left =560
ScoreRect.bottom = 130
moveLeft = False
moveRight = False
moveUp = False
moveDown = False
PlayerSpeed = 40
def GameBoard():
    pygame.display.set_caption("Snake_Game")
    Window.fill(GREEN)
    pygame.draw.line(Window, BLACK,(560,140),(1360,140),4)
    pygame.draw.line(Window, BLACK,(560,140),(560,940),4)
    pygame.draw.line(Window, BLACK,(1360,140),(1360,940),4)
    pygame.draw.line(Window, BLACK,(560,940),(1360,940),4)
#GAME===========================================================
mainClock = pygame.time.Clock()
Window = pygame.display.set_mode((Height,Width), 0, 32)
#PLayer=========================================================                    
Snake =[]
Snake.append (pygame.Rect(940,500,40,40))
playerImage = pygame.image.load("Snake.GIF")
Window.blit(playerImage,Snake[0])
#Apple==========================================================
def PlotApple():
    global AppleX
    global AppleY
    global Apple
    AppleX = random.randint(560,1320)
    AppleY = random.randint(140,900)
    Apple = pygame.Rect(AppleX,AppleY,40,40)
PlotApple()
AppleImage = pygame.image.load("Apple.GIF") 
Window.blit(AppleImage,Apple)
pygame.display.update()
#================================================================
while True:
    for event in pygame.event.get():
        if event.type == KEYDOWN:
            if event.key == K_ESCAPE:
                pygame.quit()
        #===================================================
        if event.type == KEYDOWN:
            #===============================================
            if event.key == K_LEFT:
                moveRight = False
                moveLeft = True
                moveDown = False
                moveUp = False
            #===============================================
            if event.key == K_RIGHT:
                moveLeft = False
                moveRight = True
                moveDown = False
                moveUp = False
            #===============================================
            if event.key == K_UP:
                moveDown = False
                moveUp = True
                moveLeft = False
                moveRight = False
            #===============================================
            if event.key ==K_DOWN:
                moveUp = False
                moveDown = True
                moveLeft = False
                moveRight = False
            #KEYUP===============================================
            if event.type == KEYUP:
            #===================================================
                if event.key == K_ESCAPE:
                    pygame.quit()
                    sys.exit()
    #MovePlayer===================================================
    mainClock.tick(10)
    GameBoard()
    for tail in range (len(Snake)-1,0,-1):
        print(Snake,tail)
        Snake[tail] = Snake[tail-1]
        Window.blit(playerImage,Snake[tail])
        print(Snake,tail)
    if moveDown:
        Snake[0].top += PlayerSpeed
    if moveUp:
        Snake[0].top -= PlayerSpeed
    if moveLeft:
        Snake[0].left -= PlayerSpeed
    if moveRight:
        Snake[0].right += PlayerSpeed
    if Snake[0].bottom >=940 or Snake[0].top<+140 or Snake[0].left<=560 or Snake[0].right>=1360:
        pygame.quit()
    Score = basicfont.render("Score:" + str(score), True, WHITE, GREEN)
    Window.blit(playerImage,Snake[0])
    Window.blit(AppleImage,Apple)
    Window.blit(Score,ScoreRect)
    if Snake[0].colliderect(Apple):
        score = score +50
        Snake.append (Snake[0])
        PlotApple()
    pygame.display.update()


Hi

flying over your code (without executing it) I think these loop is setup wrongly:


    for tail in range (len(Snake)-1,0,-1):
        print(Snake,tail)
        Snake[tail] = Snake[tail-1]

Because the for loop will generate 'tail' sequence as: 9, 8, 7, 6, 5, 4, 3, 2, 1
But then you do: Snake[tail] = Snake[tail-1]   which is using concrete indices: Snake[9] = Snake[9-1]
...

So this means that if you had a Snake like this ['a', 'b', 'c', 'd'] this loop will transform it to:
['a', 'a', 'b', 'c']
and so on until its all 'a': ['a', 'a', 'a', 'a']
which is what you see (all seem to be at index 0 because only this sprite exists in the list).

...

I wondered and run the code. It seems there are some other issues.

1. I would suggest to draw all elements of the snake not only the head (so you see where they are actually placed and the snake should be growing with each apple eaten).
2. I would think about object references. If a rect1 is put into a list at index 0 and then Snake[1] = Snake[0] is executed the same object is now at index 0 and 1. This means that if Snake[0].x is changed its also changed for Snake[1] (because both are actually the same object). So adding a tail part or moving the last to the front should be carefully done. I would think about moving the last part to the front (don't forget to update the coordinates accordingly because next lines in the code move the head relative to the old position).

I hope I gave you some pointers where to look.

~DR0ID