Reputation: 13
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
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:
pygame.K_UP
the direction doesn't change and key is omitted)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