Noahp
Noahp

Reputation: 59

Snake game in pygame borders

so I am totally new to Python, PyGame and any kind of programming. I have followed a tutorial on making a snake game in PyGame. Now its done but to give myself a challenge I am trying to change the game a bit. First I would like to add borders but I am really lost. I have tried watching other tutorials but they do it with an image which seems to be different. Here is my code (since I didn't know what would help you to help me I sent it all.):

class cube (object):
    rows = 20
    w = 500
    def __init__(self,start,dirnx=1,dirny=0,color = (255,0,0)):
        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,0,0), circleMiddle, radius)
            pygame.draw.circle(surface, (0,0,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):
    rows_space = w // rows

    x = 0
    y = 0

    for l in range(rows):
        x += rows_space
        y += rows_space
        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, display_width, s, snack
    surface.fill((0,0,0))
    s.draw(surface)
    snack.draw(surface)
    drawGrid(display_width, rows, surface)
    pygame.display.update()

def randomSnack(rows,items):
    positions = items.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 rows, display_width, s, snack
    display_width = 500
    rows = 20
    win = pygame.display.set_mode((display_width, display_width))
    s = snake((255,0,0), (10,10))
    snack = cube(randomSnack(rows, s), color=(0,255,0))
    alive = True

    clock = pygame.time.Clock()

    while alive:
        pygame.time.delay(50)
        clock.tick(7)
        s.move()
        if s.body[0].pos == snack.pos:
            s.addCube()
            snack = cube(randomSnack(rows, s), color=(0,255,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))
                message_box('You Lost!', 'Play again!')
                s.reset((10,10))
                break

        redrawWindow(win)

main()

Basically, I want the the same thing to happen when my snake hits a border as when it hits himself. Thank you so much if you could help me!

Upvotes: 1

Views: 1417

Answers (1)

The Big Kahuna
The Big Kahuna

Reputation: 2110

well lets just make the window bigger, lets make it one cube size bigger

win = pygame.display.set_mode((display_width + (500//20), display_width + (500//20)))

now we have more space, lets just move everything over so there is a even border around the whole thing

In drawGrid() draw from one cube size over

pygame.draw.line(surface, (255,255,255), (x,rows_space), (x,w))
pygame.draw.line(surface, (255,255,255), (rows_space,y), (w,y))

Now if you want it coloured, you can draw a rectangle around it the colour your want

pygame.draw.rect(surface,(0,0,200),(0,0,w,rows_space)) #top
pygame.draw.rect(surface,(0,0,200),(0,0,rows_space,w)) #left
pygame.draw.rect(surface,(0,0,200),(0,w,w + rows_space,rows_space)) #bottom
pygame.draw.rect(surface,(0,0,200),(w,0,rows_space,w + rows_space)) #right

enter image description here

If you want a challenge, do the same thing (you can use the method) but instead of increasing the window, decrease the grid size to make a border.

Also, now that you have made snake, try and make it using as little lines as possible, i would look at others first, but its a good thing to do. because personally i think you have over complicated it using a class for each cube of the body.

To end the game when the snake hits an edge is, do the same thing you did for the snake hitting its body, but when the snake is on the border, you have code that checks if the snake goes off the screen and loops it around to the other side, so you can do it there

        else:
            #if snake off edge
            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) 

it did not copy and paste well

but now we can change this code from moving the snake to ending the game

        outside = False
            if c.pos[0] <= 1: outside = True
            elif c.pos[0] >= c.rows-1: outside = True
            elif c.pos[1] >= c.rows-1: outside = True
            elif c.pos[1] <= 1: outside = True
            else: c.move(c.dirnx,c.dirny) 
            if outside:
                print('Score: ', len(s.body))
                message_box('You Lost!', 'Play again!')
                s.reset((10,10))     

to fix the snake going onto the border, change the above code to >= 1 instead of 0, this is partly my fault, it is not the best way to do a border, but it is a works, and I'm sure when you go to make snake again, you will make it better

Upvotes: 1

Related Questions