Python realizes snake game of single player mode

  • 2021-11-29 07:56:33
  • OfStack

Simple with py wrote a snake game, there are single, double mode, relatively simple, suitable for beginners to practice hand. Basically, every important statement has comments, and it is clear at first glance what has been done

Let's introduce the single player mode first

1. Key points of game design

1. Design and reasonable arrangement of game main window (size), canvas (size, position), button (size, position), text (size, color, position), image, background music and related response functions (mainly mouse movement and click response)
2. Attribute design of snake and food class
3. Update the snake position (according to the keyboard input), judge the extra points for eating food, and update the food
4. Design of judging conditions for snake death

2. Main modules

1.pygame
2.sys
3.random

3. Classes Used

1. Snake class, which defines the position of snake head and body elements
2. Food class, which defines the position of food elements and the color of individual elements

4. Main functions

1. new_food (), Function: Generate a food that does not coincide with the snake head position and return the food object


def new_food(head):
    while True:
        #  Loop, instantiate continuously new_food Object until it is generated 1 A food that does not coincide with the snake head 
        new_food = Food(randint(0, 45) * 20, randint(0, 28) * 20, (randint(10, 255), randint(10, 255), randint(10, 255)))
        #  If new_food If it coincides with the snake head, it will not create a key 
        if new_food.x != head.x and new_food.y != head.y:
            break
        else:
            continue
    return new_food

2. draw_snake (), draw_food () function, function: Drawing snake and food images, passing in parameters for color and object:


#  Drawing Snakes in a Form 
#  Formal parameters: 1 One is color and the other is color 1 Is an instantiated object 
def draw_snake(color, object):
    pygame.draw.circle(window, color, (object.x, object.y), 10)
    
#  Drawing food in a form 
#  Formal parameter: instantiate the object 
def draw_food(food):
    pygame.draw.circle(window, food.color, (food.x, food.y), 10)

3. show_end function, function: Displays the scoring interface at the end of single player mode:


#  At the end of the game, the setting of the form for displaying scores in single player mode 
def show_end_single():
    while True:
        window.blit(init_background, (0, 0))
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                exit_end()
        #  Define title 
        pygame.display.set_caption(" Snake Adventure ")
        #  Define prompt text 
        font = pygame.font.SysFont("simHei", 40)
        fontsurf = font.render(' Game over !  Your score is : %s' % score, False, black)
        window.blit(fontsurf, (250, 100))
        button(" Return to the main menu ", 370, 300, 200, 40, blue, brightred, into_game)
        button(" Quit the game ", 370, 470, 200, 40, red, brightred, exit_end)
        pygame.display.update()
        clock.tick(20)

4. exit_end () function, function: Click "×" in the upper right corner of the initial interface and the end of the game to exit the whole game directly:


def exit_end():
    pygame.quit()
    sys.exit()

5. start_game () function, function: realize single person normal mode:


def start_game():
    # 播放音乐
    pygame.mixer.music.play(-1)
    # 定义存分数的全局变量
    global score
    score = 0
    # 定义存放玩家键盘输入运动方向的变量,初始为向右
    run_direction = "right"
    # 定义贪吃蛇运动方向的变量,初始为玩家键入方向
    run = run_direction
    # 实例化贪吃蛇和食物对象
    head = Snake(randint(0, 30) * 20, randint(0, 20) * 20)
    # 实例化蛇身长度为2个单位
    snake_body = [Snake(head.x, head.y + 20), Snake(head.x, head.y + 40)]
    # 实例化食物列表,列表随着其中食物被吃掉应该不断缩短
    food_list = [Food(randint(0, 45) * 20, randint(0, 28) * 20, (randint(10, 255), randint(10, 255), randint(10, 255)))]
    for i in range(1,24):
        food_list.append(Food(randint(0, 45) * 20, randint(0, 28) * 20, (randint(10, 255), randint(10, 255), randint(10, 255))))
    # 实例化单个食物,方便循环内生成单个新食物
    food = Food(randint(0, 45) * 20, randint(0, 28) * 20, (randint(10, 255), randint(10, 255), randint(10, 255)))
    while True:
        window.blit(background, (0,0))
        # 监听玩家键盘输入的运动方向值,并根据输入转为up、down、right或left,方便程序中调用
        # pygame.event.get()返回1个列表,存放本次game执行中程序遇到的1连串事件(按时间顺序依次存放)
        for event in pygame.event.get():
            # pygame.QUIT事件是指用户点击窗口右上角的"×"
            if event.type == pygame.QUIT:
                # 显示结果界面
                show_end()
            # 若事件类型是按下键盘,分↑ ↓ ← →4种情况讨论
            elif event.type == pygame.KEYDOWN:
                # 若事件类型是按下键盘↑
                # key是键值,表示按下去的键值是什么
                if event.key == ord('w'):
                    run_direction = "up"
                # 若事件类型是按下键盘↓
                if event.key == ord('s'):
                    run_direction = "down"
                # 若事件类型是按下键盘←
                if event.key == ord('a'):
                    run_direction = "left"
                # 若事件类型是按下键盘→
                if event.key == ord('d'):
                    run_direction = "right"
        # 绘制初始化的25个食物图像(24+1=25)
        # 随着该列表中的食物被吃掉,列表应该不断pop以清除已经被吃的事物
        for item in food_list:
            draw_food(item)
        # 绘制被贪吃蛇吃掉后新增的食物图像
        draw_food(food)
        # 绘制蛇头图像
        draw_snake(black, head)
        # 绘制蛇身图像
        for item in snake_body:
            draw_snake(blue, item)
        # 判断贪吃蛇原运动方向(run)与玩家键盘输入的运动方向(run_direction)是否违反正常运动情况
        if run == "up" and not run_direction == "down":
            run = run_direction
        elif run == "down" and not run_direction == "up":
            run = run_direction
        elif run == "left" and not run_direction == "right":
            run = run_direction
        elif run == "right" and not run_direction == "left":
            run = run_direction
        # 插入蛇头位置到蛇身列表中
        snake_body.insert(0, Snake(head.x, head.y))
        # 根据玩家键入方向进行蛇头xy的更新
        if run == "up":
            head.y -= 20
        elif run == "down":
            head.y += 20
        elif run == "left":
            head.x -= 20
        elif run == "right":
            head.x += 20
        # 判断是否死亡
        die_flag = False
        # 遍历存放贪吃蛇位姿的列表,从第1个开始,(第0个位蛇头)
        for body in snake_body[1:]:
            # 如果蛇头的xy和蛇身xy相等,则判定相撞,设置flag为ture
            if head.x == body.x and head.y == body.y:
                die_flag = True
        # 若蛇头的xy在显示窗体外,或flag为true,则显示结束界面,并退出游戏
        if die_flag == True or head.x < 0 or head.x > 960 or head.y < 0 or head.y > 600:
            # 停止播放音乐
            pygame.mixer.music.stop()
            show_end()
        # die_snake(head, snake_body)
        # 判断蛇头和食物坐标,若相等,则加分,并生成新的食物
        # 定义标志,表明是否找到和蛇头相等的事物
        global flag
        flag = 0
        # 如果蛇头和食物重合
        for item in food_list:
            if head.x == item.x and head.y == item.y or head.x == food.x and head.y == food.y:
                flag = 1
                score += 1
                # 弹出被吃掉的这个食物
                food_list.pop(food_list.index(item))
                # 再产生1个食物
                food = new_food(head)
                # 把新食物插入food_list,下1次循环中会更新绘制食物全体
                food_list.append(food)
                break
        if flag == 0:
            snake_body.pop()
        font = pygame.font.SysFont("simHei", 25)
        mode_title = font.render('正常模式', False, grey)
        socre_title = font.render('得分: %s' % score, False, grey)
        window.blit(mode_title, (50, 30))
        window.blit(socre_title, (50, 65))
        # 更新蛇头蛇身和食物的数据
        pygame.display.update()
        # 通过帧率设置贪吃蛇速度
        clock.tick(8)

6. start_kgame () function, function: Implement single person through wall mode:


def start_kgame_single():
    #  Play music 
    pygame.mixer.music.play(-1)
    global score
    score = 0
    #  Defines the variable for storing the movement direction of the player's keyboard input, initially to the right 
    run_direction = "right"
    #  A variable that defines the direction of the snake's movement, initially typing the direction for the player 
    run = run_direction
    #  Instantiate snake head, snake body and food object 
    head = Snake(160, 160)
    #  Instantiate snake body 
    snake_body = [Snake(head.x, head.y + 20), Snake(head.x, head.y + 40), Snake(head.x, head.y + 60)]
    #  Instantiate the food list, which should be shortened as the food in it is eaten 
    food_list = [Food(randint(0, 45) * 20, randint(0, 28) * 20, (randint(10, 255), randint(10, 255), randint(10, 255)))]
    for i in range(1,24):
        food_list.append(Food(randint(0, 45) * 20, randint(0, 28) * 20, (randint(10, 255), randint(10, 255), randint(10, 255))))
    #  Instantiate a single food to facilitate the generation of a single new food in the cycle 
    food = Food(randint(0, 45) * 20, randint(0, 28) * 20, (randint(10, 255), randint(10, 255), randint(10, 255)))
    #  Infinite loop, listening for keyboard key values 
    while True:
        window.blit(background, (0, 0))
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                show_end_single()
            elif event.type == pygame.KEYDOWN:
                #  If the event type is keyboard press w
                # key Is a key value, indicating what key value is pressed 
                if event.key == ord('w'):
                    run_direction = "up"
                #  If the event type is keyboard press s
                if event.key == ord('s'):
                    run_direction = "down"
                #  If the event type is keyboard press a
                if event.key == ord('a'):
                    run_direction = "left"
                #  If the event type is keyboard press d
                if event.key == ord('d'):
                    run_direction = "right"
        #  Draws the initialized 25 Food images (24+1=25)
        #  As the food in the list is eaten, the list should continue pop To remove what has been eaten 
        for item in food_list:
            draw_food(item)
        #  Draw an image of food added after being eaten by a gluttonous snake 
        draw_food(food)
        #  Draw snake head image 
        draw_snake(black, head)
        #  Draw a snake image 
        for item in snake_body:
            draw_snake(blue, item)
        #  Judging whether the original movement direction of the snake and the movement direction input by the player's keyboard violate the normal movement situation 
        if run == "up" and not run_direction == "down":  #  If the movement direction is upward and the player inputs the movement direction downward, it violates the normal movement of the gluttonous snake 
            run = run_direction
        elif run == "down" and not run_direction == "up":
            run = run_direction
        elif run == "left" and not run_direction == "right":
            run = run_direction
        elif run == "right" and not run_direction == "left":
            run = run_direction
        #  Insert snake head position into snake body list 
        snake_body.insert(0, Snake(head.x, head.y))
        #  Snake head according to the direction typed by the player xy Update of 
        if run == "up":
            head.y -= 20
        elif run == "down":
            head.y += 20
        elif run == "left":
            head.x -= 20
        elif run == "right":
            head.x += 20
        #  Through-wall implementation 
        #  Define flag bit 
        die_flag = False
        #  Traversing, when the snake head touches the snake body, flag For true Quit the game 
        for body in snake_body[1:]:
            if head.x == body.x and head.y == body.y:
                die_flag = True
        if die_flag:
            pygame.mixer.music.stop()
            show_end()
        else: 
            #  When the snake head goes out of the form, there is 4 In this case, discuss separately 
            if head.x < 0:
                head.x = 960
            if head.x > 960:
                head.x = 0
            if head.y < 0:
                head.y = 600
            if head.y > 600:
                head.y = 0
        #  Judge the coordinates of snake head and food, and if they are equal, add points and generate new food 
        #  Defining a sign to indicate whether something equal to the snake's head has been found 
        global flag
        flag = 0
        #  If the snake head coincides with the food 
        for item in food_list:
            if head.x == item.x and head.y == item.y or head.x == food.x and head.y == food.y:
                flag = 1
                score += 1
                #  Pop up the food that was eaten 
                food_list.pop(food_list.index(item))
                #  Regeneration 1 A food 
                food = new_food(head)
                #  Insert new food food_list , under 1 The whole food will be updated in the sub-loop 
                food_list.append(food)
                break
        #  If you don't eat food, start from the snake body pop1 Elements to update the snake position 
        if flag == 0:
            snake_body.pop()
        font = pygame.font.SysFont("simHei", 25)
        mode_title = font.render(' Wall-through mode ', False, grey)
        socre_title = font.render(' Score : %s' % score, False, grey)
        window.blit(mode_title, (50, 30))
        window.blit(socre_title, (50, 65))
        #  Drawing updates 
        pygame.display.update()
        #  Setting Snake Speed by Frame Rate 
        clock.tick(8)

7. button () function, function: realize button style design and respond to mouse operation:


def button(msg, x, y, w, h, ic, ac, action=None):
    #  Get the mouse position 
    mouse = pygame.mouse.get_pos()
    #  Get mouse clicks 
    click = pygame.mouse.get_pressed()
    if x + w > mouse[0] > x and y + h > mouse[1] > y:
        pygame.draw.rect(window, ac, (x, y, w, h))
        if click[0] == 1 and action != None:
            action()
    else:
        pygame.draw.rect(window, ic, (x, y, w, h))
    #  Set text style and center alignment in buttons 
    font = pygame.font.SysFont('simHei', 20)
    smallfont = font.render(msg, True, white)
    smallrect = smallfont.get_rect()
    smallrect.center = ((x + (w / 2)), (y + (h / 2)))
    window.blit(smallfont, smallrect)

8. into_game () function, function: realize the initial interface of the game, select the mode:


def into_game():
    while True:
        window.blit(init_background, (0, 0))
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                exit_end()
        #  Set fonts 
        font = pygame.font.SysFont("simHei", 50)
        #  Initial interface displays text 
        fontsurf = font.render(' Welcome to the Snake Adventure !', True, black)  #  Text 
        fontrect = fontsurf.get_rect()
        fontrect.center = ((480), 200)
        window.blit(fontsurf, fontrect)
        button(" Normal mode ", 370, 370, 200, 40, blue, brightred, start_game)
        button(" Penetrable mode ", 370, 420, 200, 40, violte, brightred, start_kgame)
        button(" Quit the game ", 370, 470, 200, 40, red, brightred, exit_end)
        pygame.display.update()
        clock.tick(20)

9. Main function, function: initialize parameter setting and enter the game:


if __name__ == '__main__':
    #  Define the colors that need to be used 
    white = (255, 255, 255)
    red = (200, 0, 0)
    green = (0, 128, 0)
    blue = (0, 202, 254)
    violte = (194, 8, 234)
    brightred = (255, 0, 0)
    brightgreen = (0, 255, 0)
    black = (0, 0, 0)
    grey = (129, 131, 129)
    #  Design window 
    window = pygame.display.set_mode((960, 600))
    #  Define title 
    pygame.display.set_caption(" Snake Adventure ")
    #  Define Background Picture 
    init_background = pygame.image.load("image/init_bgimg.jpg")
    background = pygame.image.load("image/bgimg.jpg")
    #  Background music 
    pygame.mixer.init()
    pygame.mixer.music.load("background.mp3")
    #  Create a clock 
    clock = pygame.time.Clock()
    #  Initialize and self-check whether all modules are complete 
    pygame.init()
    #  Initial interface 
    into_game()

Note: Among the pictures, background music needs to find their own appropriate (size to adapt to the window size), can also refer to the resources I uploaded: Snake Single Edition Source Code + Background + Music

Attachment: Blog: Detailed explanation of two-person mode


Related articles: