sathvikchilakala
sathvikchilakala

Reputation: 13

My Snake is running straight through itself and it is passing through the boundaries

I just started learning python and tried the snake game and I ran into an issue. When I run the program and make the snake is moving to the left, I can move it right and it crashes into itself. Same thing with up and down. I want to make it so the snake cannot run into itself backward. Also, when I make the snake go outside the boundary, it doesn't die, it simply passes out the other wall. For example, if my snake goes out of the right wall, it will come through the left on the other side.

import pygame
import math
import random
import tkinter as tk
from tkinter import messagebox
from pygame.locals import *
import time



pygame.display.set_caption('SNAKE GAME!!! HAVE FUN PLAYING')

class cube(object):
    rows = 30
    w = 750

    def __init__(self,start,dirnx=1,dirny=0,color=(30,144,255)):
        self.pos = start
        self.dirnx = 1
        self.dirny = 0
        self.color = color

    def move(self,dirnx,dirny):
        self.dirnx = dirnx
        self.dirny = dirny
        self.pos = (self.pos[0] + self.dirnx, self.pos[1] + self.dirny)

    def draw(self,surface,eyes=False):
        dis = self.w //self.rows
        i = self.pos[0]
        j = self.pos[1]

        pygame.draw.rect(surface,self.color, (i*dis+1, j*dis+1, dis-2, dis-2))

        if eyes:
            centre = dis//2
            radius = 3
            circleMiddle = (i*dis+centre-radius,j*dis+8)
            circleMiddle2 = (i*dis+dis-radius*2, j*dis+8)
            pygame.draw.circle(surface, (0,128,0), circleMiddle, radius)
            pygame.draw.circle(surface, (0,128,0), circleMiddle2, radius)


class snake(object):
    body= []
    turns = {}

    def __init__(self,color,pos):
        self.color = color
        self.head = cube(pos)
        self.body.append(self.head)
        self.dirnx = 0
        self.dirny = 1

    def move(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()

            keys = pygame.key.get_pressed()

            for key in keys:
                if keys[pygame.K_LEFT]:
                    self.dirnx = -1
                    self.dirny = 0
                    self.turns[self.head.pos[:]] = [self.dirnx, self.dirny]

                elif keys[pygame.K_RIGHT]:
                    self.dirnx = 1
                    self.dirny = 0
                    self.turns[self.head.pos[:]] = [self.dirnx, self.dirny]

                elif keys[pygame.K_UP]:
                    self.dirnx = 0
                    self.dirny = -1
                    self.turns[self.head.pos[:]] = [self.dirnx, self.dirny]

                elif keys[pygame.K_DOWN]:
                    self.dirnx = 0
                    self.dirny = 1
                    self.turns[self.head.pos[:]] = [self.dirnx, self.dirny]

        for i, c in enumerate(self.body):
            p = c.pos[:]
            if p in self.turns:
                turn = self.turns[p]
                c.move(turn[0], turn[1])
                if i == len(self.body) - 1:
                    self.turns.pop(p)
            else:
                if c.dirnx == -1 and c.pos[0] <= 0:
                    c.pos = (c.rows - 1, c.pos[1])
                elif c.dirnx == 1 and c.pos[0] >= c.rows - 1:
                    c.pos = (0, c.pos[1])
                elif c.dirny == 1 and c.pos[1] >= c.rows - 1:
                    c.pos = (c.pos[0], 0)
                elif c.dirny == -1 and c.pos[1] <= 0:
                    c.pos = (c.pos[0], c.rows - 1)
                else:
                    c.move(c.dirnx, c.dirny)

    def reset(self,pos):
        self.head = cube(pos)
        self.body = []
        self.body.append(self.head)
        self.turns = {}
        self.dirnx = 0
        self.dirny = 1

    def addCube(self):
        tail = self.body[-1]
        dx,dy = tail.dirnx, tail.dirny

        if dx == 1 and dy == 0:
            self.body.append(cube((tail.pos[0]-1,tail.pos[1])))
        elif dx == -1 and dy == 0:
            self.body.append(cube((tail.pos[0]+1, tail.pos[1])))
        elif dx == 0 and dy == 1:
            self.body.append(cube((tail.pos[0], tail.pos[1]-1)))
        elif dx == 0 and dy == -1:
            self.body.append(cube((tail.pos[0], tail.pos[1]+1)))

        self.body[-1].dirnx = dx
        self.body[-1].dirny = dy



    def draw(self,surface):
        for i,c in enumerate(self.body):
            if i == 0:
                c.draw(surface, True)
            else:
                c.draw(surface)


def drawGrid(w,rows,surface):
    sizeBtwn = w // rows
    x = 0
    y = 0
    for l in range(rows):
        x = x + sizeBtwn
        y = y + sizeBtwn
        pygame.draw.line(surface,(255,255,255),(x,0),(x,w))
        pygame.draw.line(surface,(255,255,255),(0,y),(w,y))


def redrawWindow(surface):
    global rows,width,s,snack
    surface.fill((154,205,50))
    s.draw(surface)
    snack.draw(surface)
    drawGrid(width,rows,surface)
    pygame.display.update()

def randomSnack(rows,item):
    positions = item.body

    while True:
        x = random.randrange(rows)
        y = random.randrange(rows)
        if len(list(filter(lambda z:z.pos == (x,y), positions)))>0:
            continue
        else:
            break
    return (x,y)


def message_box(subject,content):
    root = tk.Tk()
    root.attributes("-topmost", True)
    root.withdraw()
    messagebox.showinfo(subject,content)
    try:
        root.destroy()
    except:
        pass

def main():
    global width,rows,s,snack
    width = 750
    height = 500
    rows = 30
    win = pygame.display.set_mode((width,width))
    s = snake((30,144,255),(10,10))
    snack = cube(randomSnack(rows,s), color=(255,0,0))
    flag = True
    clock = pygame.time.Clock()
    while flag:
        pygame.time.delay(1)
        clock.tick(10)
        s.move()
        if s.body[0].pos == snack.pos:
            s.addCube()
            snack = cube(randomSnack(rows,s), color=(255,0,0))

        for x in range(len(s.body)):
            if s.body[x].pos in list(map(lambda z: z.pos, s.body[x + 1:])):
                print('Score: ', len(s.body))
                score = str(len(s.body))
                s.reset((10, 15))
                pygame.display.set_caption("Score:", score)

        redrawWindow(win)
        pass

main()

Please Help!

Upvotes: 1

Views: 601

Answers (1)

Benjamin
Benjamin

Reputation: 3448

Firstly - it's much easier to read the pygame code when there are Sprites instead of simple object classes. Secondly - your example is much larger than it should be - please keep it simple and limit it to the real problem.

In order to stop snake from killing itself when it goes the opposite way I see 2 solutions:

  1. When snake is going in any direction (e.g. self.dirny=1) you might forbid the change direction to the opposite way (so when user presses pygame.K_UP the direction doesn't change and key is omitted)
  2. Harder solution - check in which direction is a tail and change direction according to this (this will include the moving head and exchanging it with tail in that case).

In order to kill a snake when it hits the boundary - in a snake move() method you should check whether the cube hits the boundary and when it does - kill the snake instead of moving the cube's position to the other side of the board.

Upvotes: 3

Related Questions