0

I made a basic eating apples snake game. After the snake "eats" the apple it gains one more segment in its length and the position of the apple resets to a new random location on the screen.

My problem is that it is possible that the new random coordinates of the apple can be the same as one's of the snake's segments, therefore the snake gains one more segment in it's length without actually "eating" the apple.

How can it make it so that the new apple location does not coincide with one of the snake's segments ? I do not necessary need the code that will make it work, but the logic behind it. Can anyone help ?

Please note that the game is very basic. It does not have boundaries and the snake can eat the apple even thought the apple does not always "fit" its mouth (it only has to touch it).

import pygame,random

# --- Globals ---
# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255,0,0)

# Set the width and height of each snake segment
segment_width = 15
segment_height = 15
# Margin between each segment
segment_margin = 3

# Set initial speed
x_change = segment_width + segment_margin
y_change = 0


class Segment(pygame.sprite.Sprite):
    """ Class to represent one segment of the snake. """

    # -- Methods
    # Constructor function
    def __init__(self, x, y):
        # Call the parent's constructor
        super().__init__()

        # Set height, width
        self.image = pygame.Surface([segment_width, segment_height])
        self.image.fill(WHITE)

        # Make our top-left corner the passed-in location.
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y

class Apple(pygame.sprite.Sprite):

    def __init__(self,x,y):

        super().__init__()

        self.image = pygame.Surface([segment_width,segment_height])
        self.image.fill(RED)

        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y

    def update(self):
        self.rect.x = random.randrange(800)
        self.rect.y = random.randrange(600)


# Call this function so the Pygame library can initialize itself
pygame.init()

# Create an 800x600 sized screen
screen = pygame.display.set_mode([800, 600])

# Set the title of the window
pygame.display.set_caption('Snake Example')

apple_list = pygame.sprite.Group()

snake_group = pygame.sprite.Group()

allspriteslist = pygame.sprite.Group()

# Create an initial snake
snake_segments = []
for i in range(15):
    x = 250 - (segment_width + segment_margin) * i
    y = 30
    segment = Segment(x, y)
    snake_segments.append(segment)
    snake_group.add(segment)
    allspriteslist.add(segment)

m = random.randrange(0,800,15)
n = random.randrange(0,600,15)


apple = Apple(m, n)

apple_list.add(apple)
allspriteslist.add(apple)

clock = pygame.time.Clock()
done = False
score = 0

while not done:

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True

        # Set the speed based on the key pressed
        # We want the speed to be enough that we move a full
        # segment, plus the margin.
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                x_change = (segment_width + segment_margin) * -1
                y_change = 0
            if event.key == pygame.K_RIGHT:
                x_change = (segment_width + segment_margin)
                y_change = 0
            if event.key == pygame.K_UP:
                x_change = 0
                y_change = (segment_height + segment_margin) * -1
            if event.key == pygame.K_DOWN:
                x_change = 0
                y_change = (segment_height + segment_margin)

    # Get rid of last segment of the snake
    # .pop() command removes last item in list
    old_segment = snake_segments.pop()
    snake_group.remove(old_segment)

    # Figure out where new segment will be
    x = snake_segments[0].rect.x + x_change
    y = snake_segments[0].rect.y + y_change
    segment = Segment(x, y)

    # Insert new segment into the list
    snake_segments.insert(0, segment)
    snake_group.add(segment)

    apple_collide = pygame.sprite.spritecollide(apple,snake_group,False)

    for element in  apple_collide:
        apple_list.remove(element)
        score += 1
        print(score)
        apple.update()
        a = snake_segments[len(snake_segments)-1].rect.x
        b = snake_segments[len(snake_segments)-1].rect.y
        new_segment = Segment(a,b)
        snake_group.add(new_segment)
        snake_segments.append(new_segment)




    # -- Draw everything
    # Clear screen
    screen.fill(BLACK)

    apple_list.draw(screen)
    snake_group.draw(screen)

    # Flip screen
    pygame.display.flip()

    # Pause
    clock.tick(5)

pygame.quit()
ROBlackSnail
  • 111
  • 1
  • 3
  • 14
  • 1
    Can't you just check the random location against the snake sections prior to placing the apple, then just "re-roll" if it's on the snake? This may cause problems when the snake takes up almost the entire screen, but it's a start to try. – Carcigenicate Dec 20 '16 at 14:47
  • @Carcigenicate I don't think it will work that way because i can check if the x , y coordonates of the apple coincide with one of snake's segments, and although it would not be dirrectly on the snake, it could be one pixel higher, therefore the collision still happens and the snake gains length – ROBlackSnail Dec 20 '16 at 14:52
  • compare apple position with snake segments position before you put apple on screen. – furas Dec 20 '16 at 14:52
  • @ROBlackSnail Then check around the snake sections. This is entirely possible; I did it when I made a snake game. – Carcigenicate Dec 20 '16 at 14:54
  • 2
    or use your `pygame.sprite.spritecollide(apple,snake_group,False)` before you put apple - if it collides then get new random position and check `spritecollide` again. – furas Dec 20 '16 at 14:55
  • @furas If PyGame has collision detection, then definitely use that. Manual collision detection is slow and a pain to write. I'm not familiar with PyGame. – Carcigenicate Dec 20 '16 at 14:59
  • @furas I have introduce this part of code after I first call the apple.update() method : `apple.update() if len(pygame.sprite.spritecollide(apple, snake_group, False))> 0 : apple.update()` Seems to be working... Not sure thought. – ROBlackSnail Dec 20 '16 at 15:09
  • @Carcigenicate I didn't check code first, and I expected that OP uses grid with cells and he has to only compare cell numbers :) – furas Dec 20 '16 at 15:26

0 Answers0