picture

writing |  doug

source :Python technology 「ID: pythonall」

 picture

I believe you all played the game of snake when you were young , Anyway, I loved playing when I was a kid , No other reason , Because there is only one game on the mobile phone at home that can kill time . Later, with the popularity of mobile Internet , Smartphones are gradually replacing Nokia , But the game is a classic .

We'll use it today pygame Come and write a snake by yourself , Revisit the classic .

Come and see us first The final effect .


install

Use pygame It needs to be installed before , Use it directly pip Can be installed .

pip install pygame

Before using, we need to introduce the corresponding module into our program .

import pygame, sysfrom pygame.locals import *

Hello World

Generally, the first program you write when you learn a new programming language is basically Hello World, So our introduction today demo Just use pygame Output... On the screen Hello World.

In the use of pygame It needs to be initialized before , Then create a new game window , For interacting with users .

#  initialization pygame.init()#  New window screen = pygame.display.set_mode((640, 480))

Next, I need to set the font to output .

#  Set the window title pygame.display.set_caption("Hello World")#  Set the font font = pygame.font.Font(None, 30)text = font.render('Hello World', True, pygame.Color("#FFFFFF"))

After the font is set , Output the font directly to the canvas , Remember , Don't forget to refresh the canvas after you've finished working on it , Otherwise, there won't be anything to show .

#  Fill the font into the canvas screen.blit(text, (100, 100))#  Refresh the canvas pygame.display.update()

among screen.blit() The input parameters of the function are font , And the output position of the font .

When it comes to location , You need to say pygame The coordinate system in , The coordinate system takes the upper left corner of the game window as the origin (0,0),x Axial right increment ,y It's going down the axis .

After running the above program, you will find that , The window flashed by , So we need to put the operation in a dead loop .

while 1:    for event in pygame.event.get():        if event.type == pygame.QUIT:            pygame.quit()            sys.exit()
   screen.blit(text, (100, 100))    pygame.display.update()

 picture

In this cycle , We monitor whether the user clicks the close button in the window , If you click on us, you can exit the program directly .

It needs to be said here pygame The event monitoring mechanism of , stay pygame in , All events are passed to a queue in turn , We can go through pygame.event.get() Get all the events in the queue , Then do different operations according to the event type . Such as monitoring keyboard click events or mouse events .

snake

 picture

Let's take a look at the layout of the game first , Upper left corner 「0/0」 Express 「 The current score / The highest score in history 」. The little red squares are food , The rectangle made up of five small squares is a snake , Snake head right , The initial direction of motion is also to the right , The combat area of the game is in a large rectangle . When the snake's head touches a wall or its own body, the game ends .

For the convenience of programming , Let's define some default parameters first . Like all kinds of colors 、 A unit of length 、 The default position and orientation of the snake 、 Up, down, left and right 、 And scores, etc .

color setting

#  Color configuration snake_color = pygame.Color("#8B7D1C")food_color = pygame.Color("#8B0000")background_color = pygame.Color("#BACB03")text_color = pygame.Color("#EFEFEF")

Coordinate settings

Coordinate calculation in the game is particularly critical . Because snake and food are made of small squares , So we set the cube to occupy 15 A square in pixels , In the game, the coordinates are calculated by taking the side length of a small square as the length unit . The side length of a small square is a unit of length .

On this basis , We set the width and height of the game window as 44 Two units of length and 36 Unit of length , The distance between the combat area of the game and the top border of the window 、 Under the frame 、 The distance between the left border and the right border is four units of length 、 Two units of length 、 Two units of length 、 Two units of length .

therefore , The width and height of the game window and the four vertex coordinates of the game combat area are set as follows :

# A unit of length pixel = 15line = 44row = 36window_width = pixel * linewindow_high = pixel * row
point_left_up = [pixel * 2, pixel * 4]point_left_down = [pixel * 2, pixel * (row - 2)]point_right_up = [pixel * (line - 2), pixel * 4]point_right_down = [pixel * (line - 2), pixel * (row - 2)]

The position coordinates of the snake are as follows :

#  Snake head position snake_head = [pixel * 8, pixel * 8]#  The snake   The default is five squares snake_body = [[snake_head[0] - x * pixel, snake_head[1]] for x in range(5)]

Direction setting

In this game , We are divided by 0、90、180、270 For right 、 On 、 Left 、 Next . Many programs like to use strings to represent directions , The reason we use numbers here is that numbers are easier to deal with the turning of snakes , Just calculate whether the angle between them is 90 Degree is enough . That is, the absolute value of the difference between the two is 90 perhaps 270 It's turning .

#  Direction direction_right = 0direction_up = 90direction_left = 180direction_down = 270

Score settings

Last , Because you want to record the player's highest score in history , For simplicity, write the highest score directly to the file , When the game is initialized, just load it .

# Score settings score = 5filename = 'db.txt'
def write_score(content):    with open(filename, 'w+') as f:        f.write(str(content))

def read_score():    with open(filename, 'w+') as f:        result = f.readline()        return 0 if result.strip() == '' else int(result)

Draw a snake

Let's draw the score and the border first .

# According to the text def display_message(text, color, size, postion):    font = pygame.font.Font(None, size)    text = font.render(text, True, color)    screen.blit(text, postion)    pygame.display.update()
# Draw a line def draw_box():    for point in [[point_left_up, point_right_up], [point_right_up, point_right_down],                  [point_right_down, point_left_down], [point_left_down, point_left_up]]:        pygame.draw.line(screen, snake_color, point[0], point[1], 1)
       

 picture

Mm-hmm , It looks good , Then we'll draw the snake and the food together .

# Randomly produce food def create_food():    while True:        x = random.randint(point_left_up[0] / pixel, point_right_down[0] / pixel - 1) * pixel        y = random.randint(point_left_up[1] / pixel, point_right_down[1] / pixel - 1) * pixel        if [x, y] not in snake_body:            break    return [x, y]
def draw_snake(food_position):    # Draw a snake    for point in snake_body:        pygame.draw.rect(screen, snake_color, Rect(point[0], point[1], pixel, pixel))    # Painting food    pygame.draw.rect(screen, food_color, Rect(food_position[0], food_position[1], pixel, pixel))

 picture

To draw snakes and food is to draw rectangles , Given the color , coordinate , Length and width are enough .

You need to pay attention to the food here , Draw in the combat area of the game , And get rid of the position that the snake itself occupies .

Let the snake move

Everything is all set. , So how to make the snake move .

It's simple , In the game, snakes are made up of small squares , And the coordinates of the small squares are stored in the list snake_body Medium , When we draw snakes, we render small squares one by one , So it must be in snake_body I did an article on .

Every move to the right , amount to x Add a unit of length to the coordinates , On the contrary, one unit of length is reduced , Up and down movement is the same , It's just that y Axis coordinates . therefore , We just need to listen for keyboard events , And then change in different directions x Axis or y The coordinates of the axis are just .

Of course, if you want to traverse every unit of length snake_body, That's a bit too much trouble . Think about it , We just need to get rid of the snake tail , Then insert a new snake head .

 picture

So when we're going to move in different directions ,x Axis and y The unit of length the axis needs to move into move In this dictionary , Easy to calculate .

move = {direction_right: [pixel, 0], direction_left: [-pixel, 0], direction_up: [0, -pixel], direction_down: [0, pixel]}#  Move snake_head[0] += move[origin_direction][0]snake_head[1] += move[origin_direction][1]snake_body.insert(0, list(snake_head))#  Remove the tail snake_body.pop()

How to deal with the problem of eating food . In fact, it's not very different from dealing with sports , The only difference is that you don't need to remove the tail after eating .

Then how to judge if you have eaten food , Of course, the snakehead coordinates are the same as the food coordinates .

Last , We encapsulate all operations into an entry function run In the to .

# Entry function def run():    food_position = create_food()    max_score = read_score()    current_score = 0    is_dead = False    origin_direction = direction_right    target_direction = origin_direction    while True:        # Monitor keyboard buttons sign out OR Change direction         for event in pygame.event.get():            if event.type == pygame.QUIT:                game_over(max_score, current_score)            if event.type == KEYDOWN:                # arrow OR asdw Control direction                 if event.key == K_RIGHT or event.key == K_d:                    target_direction = direction_right                if event.key == K_LEFT or event.key == K_a:                    target_direction = direction_left                if event.key == K_UP or event.key == K_w:                    target_direction = direction_up                if event.key == K_DOWN or event.key == K_s:                    target_direction = direction_down                # esc sign out                 if event.key == K_ESCAPE:                    game_over(max_score, current_score)            # The included angle is 90 or 270 You can change direction             angle = abs(origin_direction - target_direction)            if angle == 90 or angle == 270:                origin_direction = target_direction
       if not is_dead:            snake_head[0] += move[origin_direction][0]            snake_head[1] += move[origin_direction][1]
       if not is_dead and is_alive():            # Press origin_direction Directional motion            snake_body.insert(0, list(snake_head))            # Eat food and regenerate            if snake_head == food_position:                food_position = create_food()                current_score += score            else:                # Remove the last space                snake_body.pop()        else:            is_dead = True
       # Painting background        screen.fill(background_color)        # Picture frame        draw_box()        # Draw a snake        draw_snake(food_position)        # Refresh screen        pygame.display.update()        # Update score        display_message(f"{current_score}/{max_score}", text_color, 30, (pixel * 2, pixel * 2))        if is_dead:            display_message("Game Over", text_color, 50, (pixel * 16, pixel * 15))        # Control game speed        time_clock.tick(speed)

if __name__ == '__main__':    run(

summary

Today we use  pygame Wrote a small game of their own snake , The number of lines of code does not exceed 150   That's ok . It's not hard to write this game , You just need to build a coordinate system in your mind , Then draw different patterns on different coordinate points at different times . When there are many pictures and the switching speed is very fast , People's eyes can't tell if it's a picture , This is what makes animation .

You can also try to use pygame Write a little game you like to play .