Home » maths » manifolds » Snakes on a Manifold: Part 2

Snakes on a Manifold: Part 2

Welcome back. Last time we implemented the main components of the game. This time we will implement the main game loop. The job of the loop is to: get keyboard input, update the game state, update the display.

We will now be using pygame, so you might want to check out a tutorial before proceeding, but I think the best way to learn is just to dive right in. You will however need to install pygame before running the code. If you haven’t already, you should download the code from last time too. Finally if you want to skip to playing with the code yourself, here it is.

The Code
Ok here it is.

import pygame
import snake as sk
from pygame.locals import *

class Game(object):
    def __init__(self, size, topology, speed=6):
        pygame.init()
        #Resolution in pixels.
        self.screen_resolution =600
        self.topology=topology
        self.speed = speed #Controls how fast the snake moves.
        self.screen = pygame.display.set_mode((self.screen_resolution,
                                               self.screen_resolution))
        pygame.display.set_caption('SNAKES ON A MANIFOLD!')

        self.board = sk.Board(size, topology)
        #Put the snake in the center.
        self.snake = sk.Snake([size/2, size/2], self.board.opposite_direction,
                         self.board.get_next_coord)
        #Number of grid cells.
        self.size=size
        #Width in pixels of a grid cell.
        self.square_size=int(self.screen_resolution/self.size)
        #Now we name some colors in RGB for ease of use.
        self.black = (0,0,0)
        self.red = (255,0,0)
        self.green = (0,255,0)
        self.blue=(0,0,255)
        self.darkgrey=(40,40,40)

        self.background_colour=self.black
        self.boundary_colour=self.blue
        self.snake_colour = self.green
        self.apple_colour=self.red

        #Initialises screen to background color.
        self.screen.fill(self.background_colour)

        #Then we draw the boundary cells.
        self.draw_boundary()

        #This command updates the changes we have made to the screen.
        pygame.display.update()

        #Main game loop.
        self.main()

    def main(self):
        score=0
        Quit=False
        first=True
        while True: # main game loop
            #Displays score in window caption.
            pygame.display.set_caption('Topology: '+self.board.topology+'  |  Score: '+ str(score))
            #Gets keyboard input
            direction=None
            for event in pygame.event.get():
                if event.type == QUIT:
                    #User has closed window.
                    Quit=True
                    break
                if event.type==pygame.KEYDOWN:
                    #User has pressed key.
                    if event.key==K_q:
                        Quit=True
                        break
                    if event.key==K_UP:
                        direction='UP'
                    if event.key==K_DOWN:
                        direction='DOWN'
                    if event.key==K_LEFT:
                        direction='LEFT'
                    if event.key==K_RIGHT:
                        direction='RIGHT'
            if Quit:
                break
            #To see if anything has happened, we check where the head is.
            head_loc = self.snake.head_position
            #Now we find out what, apart from the head, is in the grid cell.
            head_on = self.board.grid[head_loc[0], head_loc[1]]

            if (head_on == 1) or (head_on==2):
                #The snake has hit the boundary or part of itself.
                Quit=True
                break
            if head_on==3:
                #The snake has found an apple.
                self.snake.grow()
                x,y=self.board.generate_apple()
                self.draw_apple(x,y)
                score+=1

            self.update_board()
            if first:
                #When the game starts, the snake stands still waiting
                #for user input to start the game.
                x,y=self.board.generate_apple()
                first=False
                self.draw_apple(x,y)
                self.draw_snake()
                pygame.display.update()
                while True:
                    got_direction=False
                    for event in pygame.event.get():
                        if event.type == QUIT:
                            Quit=True
                            break
                        if event.type==pygame.KEYDOWN:
                            if event.key==K_q:
                                Quit=True
                                break
                            if event.key==K_UP:
                                direction='UP'
                                got_direction=True
                                break
                            if event.key==K_DOWN:
                                direction='DOWN'
                                got_direction=True
                                break
                            if event.key==K_LEFT:
                                direction='LEFT'
                                got_direction=True
                                break
                            if event.key==K_RIGHT:
                                direction='RIGHT'
                                got_direction=True
                                break
                    if Quit:
                        break
                    elif got_direction:
                        break
                if Quit:
                    break

            self.snake.move(direction)
            self.draw_snake()
            pygame.display.update()
            #This pauses the game to slow it down, adjust to make faster/slower.
            pygame.time.Clock().tick(self.speed)
        #Waiting to quit after died.
        Quit=False
        restart=False
        while True: # main game loop
        #Gets keyboard input

            for event in pygame.event.get():
                if event.type == QUIT:
                    Quit=True
                    break
                if event.type==pygame.KEYDOWN:
                    if event.key==K_q:
                        Quit=True
                        break
                    if event.key==K_r:
                        restart=True
                        break
            if Quit:
                break
            if restart:
                break
        if restart:
            G=Game(self.size, self.topology)
        pygame.quit()

    def draw_boundary(self):
        #Draws any boundary grid cells.
        for row in range(self.size):
            for col in range(self.size):
                if self.board.grid[row, col]==1:
                    y=row*self.square_size
                    x=col*self.square_size
                    rect=pygame.Rect(x,y, self.square_size, self.square_size)
                    pygame.draw.rect(self.screen,self.boundary_colour, rect)

    def draw_snake(self):
        #We add a snake colored square where the head has moved,
        #and add a background colored square where the tail was.
        old_tail_position=self.snake.segments[0].previous_position
        new_head_position=self.snake.head_position

        top=old_tail_position[0]*self.square_size
        left=old_tail_position[1]*self.square_size
        background_rect=pygame.Rect(left,top, self.square_size, self.square_size)
        pygame.draw.rect(self.screen, self.background_colour,background_rect)

        top=new_head_position[0]*self.square_size
        left=new_head_position[1]*self.square_size
        snake_rect=pygame.Rect(left,top, self.square_size, self.square_size)
        pygame.draw.rect(self.screen, self.snake_colour,snake_rect)

    def draw_apple(self, x, y):
        apple_rect=pygame.Rect(y*self.square_size,x*self.square_size,
                               self.square_size, self.square_size)
        pygame.draw.rect(self.screen, self.apple_colour, apple_rect)

    def update_board(self):
        #Updates the numpy array of the board.
        old_tail_position = self.snake.segments[0].previous_position
        new_head_position=self.snake.head_position
        self.board.grid[old_tail_position[0], old_tail_position[1]]=0
        self.board.grid[new_head_position[0], new_head_position[1]]=2

And we’re done! Now you can play a game by typing something like this.

G=Game(20, 'Mobius Strip')

Please let me know what you think. The code is here. If anyone is feeling ambitious, you could add a menu screen where you could select a speed and topology.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: