欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Python:游戏:贪吃蛇(附源码)

程序员文章站 2022-04-14 21:57:37
贪吃蛇是个非常简单的游戏,适合练手。 首先分析一下这个游戏 1、蛇怎么画? 蛇是由一个个小方块组成的,那么我们可以用一个 list 记录每一个小方块的坐标,显示的时候将所有小方块画出来即可。 2、蛇怎么移动? 第一反应就是想蚯蚓蠕动一样,每一个方块向前移动一格,但这样做很麻烦,仔细想下,其实除了头尾 ......

贪吃蛇是个非常简单的游戏,适合练手。

首先分析一下这个游戏

1、蛇怎么画?

蛇是由一个个小方块组成的,那么我们可以用一个 list 记录每一个小方块的坐标,显示的时候将所有小方块画出来即可。

2、蛇怎么移动?

第一反应就是想蚯蚓蠕动一样,每一个方块向前移动一格,但这样做很麻烦,仔细想下,其实除了头尾,蛇的其他部分根本就没有动过,那就简单了,将下一格的坐标添加到 list 开头,并移除 list 的最后一个元素,就相当于蛇向前移动了一格。

3、如何判定游戏结束?

蛇移动超出了游戏区的范围或者碰到了自己就算输了,超出范围很容易判断,碰到自己也容易,只要判断下一格的坐标是否已经包含在蛇的 list 中就可以了。

 

理清了这些问题,我们就可以开始编码了。

先看一下我的游戏截图

Python:游戏:贪吃蛇(附源码)

 

本例中,回车键:开始游戏,空格键:暂停 / 继续,方向键 或 wsad 键:控制移动方向。

每吃一个食物加10分,每增加100分速度加快一级,没有设置关卡,我玩到1100分,速度太快了,然后就 game over 了

"""贪吃蛇"""

import random
import sys
import time
import pygame
from pygame.locals import *
from collections import deque

screen_width = 600
screen_height = 480
size = 20


def print_text(screen, font, x, y, text, fcolor=(255, 255, 255)):
    imgtext = font.render(text, true, fcolor)
    screen.blit(imgtext, (x, y))


def main():
    pygame.init()
    screen = pygame.display.set_mode((screen_width, screen_height))
    pygame.display.set_caption('贪吃蛇')

    light = (100, 100, 100)  # 蛇的颜色
    dark = (200, 200, 200)   # 食物颜色

    font1 = pygame.font.sysfont('simhei', 24)  # 得分的字体
    font2 = pygame.font.font(none, 72)  # game over 的字体
    red = (200, 30, 30)                 # game over 的字体颜色
    fwidth, fheight = font2.size('game over')
    line_width = 1                      # 网格线宽度
    black = (0, 0, 0)                   # 网格线颜色
    bgcolor = (40, 40, 60)              # 背景色

    # 方向,起始向右
    pos_x = 1
    pos_y = 0
    # 如果蛇正在向右移动,那么快速点击向下向左,由于程序刷新没那么快,向下事件会被向左覆盖掉,导致蛇后退,直接game over
    # b 变量就是用于防止这种情况的发生
    b = true
    # 范围
    scope_x = (0, screen_width // size - 1)
    scope_y = (2, screen_height // size - 1)
    # 蛇
    snake = deque()
    # 食物
    food_x = 0
    food_y = 0

    # 初始化蛇
    def _init_snake():
        nonlocal snake
        snake.clear()
        snake.append((2, scope_y[0]))
        snake.append((1, scope_y[0]))
        snake.append((0, scope_y[0]))

    # 食物
    def _create_food():
        nonlocal food_x, food_y
        food_x = random.randint(scope_x[0], scope_x[1])
        food_y = random.randint(scope_y[0], scope_y[1])
        while (food_x, food_y) in snake:
            # 为了防止食物出到蛇身上
            food_x = random.randint(scope_x[0], scope_x[1])
            food_y = random.randint(scope_y[0], scope_y[1])

    _init_snake()
    _create_food()

    game_over = true
    start = false       # 是否开始,当start = true,game_over = true 时,才显示 game over
    score = 0           # 得分
    orispeed = 0.5      # 原始速度
    speed = orispeed
    last_move_time = none
    pause = false       # 暂停

    while true:
        for event in pygame.event.get():
            if event.type == quit:
                sys.exit()
            elif event.type == keydown:
                if event.key == k_return:
                    if game_over:
                        start = true
                        game_over = false
                        b = true
                        _init_snake()
                        _create_food()
                        pos_x = 1
                        pos_y = 0
                        # 得分
                        score = 0
                        last_move_time = time.time()
                elif event.key == k_space:
                    if not game_over:
                        pause = not pause
                elif event.key in (k_w, k_up):
                    # 这个判断是为了防止蛇向上移时按了向下键,导致直接 game over
                    if b and not pos_y:
                        pos_x = 0
                        pos_y = -1
                        b = false
                elif event.key in (k_s, k_down):
                    if b and not pos_y:
                        pos_x = 0
                        pos_y = 1
                        b = false
                elif event.key in (k_a, k_left):
                    if b and not pos_x:
                        pos_x = -1
                        pos_y = 0
                        b = false
                elif event.key in (k_d, k_right):
                    if b and not pos_x:
                        pos_x = 1
                        pos_y = 0
                        b = false

        # 填充背景色
        screen.fill(bgcolor)
        # 画网格线 竖线
        for x in range(size, screen_width, size):
            pygame.draw.line(screen, black, (x, scope_y[0] * size), (x, screen_height), line_width)
        # 画网格线 横线
        for y in range(scope_y[0] * size, screen_height, size):
            pygame.draw.line(screen, black, (0, y), (screen_width, y), line_width)

        if game_over:
            if start:
                print_text(screen, font2, (screen_width - fwidth)//2, (screen_height - fheight)//2, 'game over', red)
        else:
            curtime = time.time()
            if curtime - last_move_time > speed:
                if not pause:
                    b = true
                    last_move_time = curtime
                    next_s = (snake[0][0] + pos_x, snake[0][1] + pos_y)
                    if next_s[0] == food_x and next_s[1] == food_y:
                        # 吃到了食物
                        _create_food()
                        snake.appendleft(next_s)
                        score += 10
                        speed = orispeed - 0.03 * (score // 100)
                    else:
                        if scope_x[0] <= next_s[0] <= scope_x[1] and scope_y[0] <= next_s[1] <= scope_y[1] \
                                and next_s not in snake:
                            snake.appendleft(next_s)
                            snake.pop()
                        else:
                            game_over = true

        # 画食物
        if not game_over:
            # 避免 game over 的时候把 game over 的字给遮住了
            pygame.draw.rect(screen, light, (food_x * size, food_y * size, size, size), 0)

        # 画蛇
        for s in snake:
            pygame.draw.rect(screen, dark, (s[0] * size + line_width, s[1] * size + line_width,
                                            size - line_width * 2, size - line_width * 2), 0)

        print_text(screen, font1, 30, 7, f'速度: {score//100}')
        print_text(screen, font1, 450, 7, f'得分: {score}')

        pygame.display.update()


if __name__ == '__main__':
    main()