【童年经典小游戏】使用Python实现经典贪吃蛇游戏

文章目录

使用Python实现经典贪吃蛇游戏

贪吃蛇(Snake)作为一个经典的小游戏,从早期的手机游戏到网页小游戏,一直深受玩家的喜爱。本文将详细介绍如何使用Python来实现一个简化版的贪吃蛇游戏,包括所需库的选择、游戏逻辑的设计、关键代码的剖析,以及如何对代码进行拓展和优化。

简介

贪吃蛇的游戏规则相对简单:玩家通过控制蛇的移动方向,让蛇吃掉场景中的食物,每吃到一个食物,蛇身会增长一节,同时得分增加。当蛇撞到墙壁或自身时,游戏结束。虽然逻辑简单,但是实现起来需要兼顾用户交互、动画刷新和碰撞检测等多个层面的问题。

实现思路与准备

游戏框架与库选择

实现贪吃蛇有多种途径,这里我们将使用Python的Pygame库来完成,它是一个基于SDL的简单易用的游戏开发框架。Pygame的优势在于:

  • 易于安装与使用
  • 提供处理图形、输入事件、声音等的API
  • 社区资源丰富

游戏基本逻辑

  1. 初始化游戏场景:定义窗口大小、背景颜色、刷新率等基本参数。
  2. 表示贪吃蛇:可以使用列表来表示蛇的身体,每个元素代表一个"块"的坐标(如网格坐标)。蛇头位于列表末尾,列表头部为蛇尾。
  3. 控制方向:通过键盘事件获取上下左右方向键的输入,更改蛇移动的方向。
  4. 移动与增长:每帧更新蛇头位置。如果吃到食物,不移除蛇尾(长度增加),否则移除蛇尾,保持长度。
  5. 食物生成:在随机位置生成食物,确保不与蛇身重叠。
  6. 碰撞检测:检测蛇头是否碰到边界或自身身体块,如是则游戏结束。
  7. 得分与显示:在窗口中显示当前得分、游戏状态等信息。

代码实现

完整代码

下面是一个简单版本的贪吃蛇代码示例。请确保本机已安装pygame库,可通过pip install pygame命令安装。

python 复制代码
import pygame
import random
import sys

# 初始化Pygame
pygame.init()

# 定义颜色
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (200, 0, 0)
GREEN = (0, 200, 0)

# 游戏窗口尺寸与标题
WIDTH, HEIGHT = 600, 400
BLOCK_SIZE = 20  # 蛇与食物的大小
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("贪吃蛇游戏")

clock = pygame.time.Clock()

# 字体设置
font = pygame.font.SysFont(None, 30)

def draw_text(msg, color, x, y):
    text = font.render(msg, True, color)
    screen.blit(text, [x, y])

def create_food(snake_list):
    while True:
        x = random.randint(0, (WIDTH // BLOCK_SIZE) - 1) * BLOCK_SIZE
        y = random.randint(0, (HEIGHT // BLOCK_SIZE) - 1) * BLOCK_SIZE
        if [x, y] not in snake_list:
            return [x, y]

def game_loop():
    # 初始参数
    game_over = False
    game_close = False

    # 初始蛇位置与移动方向
    x = WIDTH // 2
    y = HEIGHT // 2
    x_change = 0
    y_change = 0

    snake_list = []
    snake_length = 1

    food = create_food(snake_list)
    score = 0

    while not game_over:
        while game_close:
            screen.fill(BLACK)
            draw_text("游戏结束,按 Q 退出 或 C 重来", RED, WIDTH//4, HEIGHT//3)
            draw_text(f"得分: {score}", WHITE, WIDTH//4, HEIGHT//3 + 40)
            pygame.display.update()

            for event in pygame.event.get():
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_q:
                        game_over = True
                        game_close = False
                    if event.key == pygame.K_c:
                        return  # 重新开始

        # 方向控制
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT and x_change == 0:
                    x_change = -BLOCK_SIZE
                    y_change = 0
                elif event.key == pygame.K_RIGHT and x_change == 0:
                    x_change = BLOCK_SIZE
                    y_change = 0
                elif event.key == pygame.K_UP and y_change == 0:
                    y_change = -BLOCK_SIZE
                    x_change = 0
                elif event.key == pygame.K_DOWN and y_change == 0:
                    y_change = BLOCK_SIZE
                    x_change = 0

        # 更新蛇头位置
        x += x_change
        y += y_change

        # 边界检测
        if x < 0 or x >= WIDTH or y < 0 or y >= HEIGHT:
            game_close = True

        screen.fill(BLACK)
        # 绘制食物
        pygame.draw.rect(screen, GREEN, [food[0], food[1], BLOCK_SIZE, BLOCK_SIZE])

        # 更新蛇身体列表
        snake_head = [x, y]
        snake_list.append(snake_head)
        if len(snake_list) > snake_length:
            del snake_list[0]

        # 蛇头碰到身体检测
        for segment in snake_list[:-1]:
            if segment == snake_head:
                game_close = True

        # 绘制蛇
        for segment in snake_list:
            pygame.draw.rect(screen, WHITE, [segment[0], segment[1], BLOCK_SIZE, BLOCK_SIZE])

        draw_text(f"得分: {score}", WHITE, 10, 10)
        pygame.display.update()

        # 判断是否吃到食物
        if x == food[0] and y == food[1]:
            food = create_food(snake_list)
            snake_length += 1
            score += 10

        clock.tick(10)  # 控制游戏帧率

def main():
    while True:
        game_loop()

if __name__ == "__main__":
    main()

代码关键点解析

初始化与游戏窗口

python 复制代码
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("贪吃蛇游戏")
  • pygame.init()初始化Pygame。
  • set_mode创建游戏窗口,set_caption为窗口标题。
  • clock = pygame.time.Clock()用于控制游戏的刷新帧率。

贪吃蛇的表示与移动

python 复制代码
snake_list = []
snake_length = 1
  • snake_list列表用于存储蛇每个节的坐标,如[ [x1, y1], [x2, y2], ... ],末尾为蛇头。
  • 每次移动时将新的头部坐标加入snake_list末尾,如果没有吃到食物,则移除首元素(蛇尾),达到移动效果。

食物的生成

python 复制代码
def create_food(snake_list):
    while True:
        x = random.randint(0, (WIDTH // BLOCK_SIZE) - 1) * BLOCK_SIZE
        y = random.randint(0, (HEIGHT // BLOCK_SIZE) - 1) * BLOCK_SIZE
        if [x, y] not in snake_list:
            return [x, y]
  • 随机生成网格点作为食物位置,保证不与蛇身重叠。
  • 每次吃到食物后重新调用此函数获得新位置。

碰撞检测与游戏结束

python 复制代码
if x < 0 or x >= WIDTH or y < 0 or y >= HEIGHT:
    game_close = True
  • 检测蛇头坐标是否超出游戏区域,如是则表示撞墙,游戏结束。
python 复制代码
for segment in snake_list[:-1]:
    if segment == snake_head:
        game_close = True
  • 检查蛇头是否与身体其它部分重叠,若是则游戏结束。

运行代码

首先在桌面创建一个文本文件,将代码复制进去,然后重命名为.py文件

之后我们打开终端(win+r)输入cmd

然后右键文件属性,找到路径

在cmd中输入 cd 文件路径,就可以进入到相应的路径中去,之后输入

python 复制代码
Python 文件名

上方向键:向上移动

下方向键:向下移动

左方向键:向左移动

右方向键:向右移动

游戏目标是让蛇吃掉出现的绿色方块(食物)。每当蛇吃到食物:

蛇身长度会增加一格。

得分会增加10分。

需要注意的要点:

切勿让蛇头碰到游戏窗口的边界,否则游戏结束。

不要让蛇头碰到自己身体的其他部分,否则游戏结束。

当游戏结束时,屏幕上会显示相应提示,可按 C 键重新开始,或按 Q 键退出游戏。

中文不显示问题解决

下面的链接作者会教你如何下载字体

https://gitcode.com/open-source-toolkit/c55ef/overview?utm_source=tools_gitcode\&index=top\&type=card\&\&null

python 复制代码
# -*- coding: utf-8 -*-
import pygame
import random
import sys

# 初始化Pygame
pygame.init()

# 定义颜色
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (200, 0, 0)
GREEN = (0, 200, 0)

# 游戏窗口尺寸与标题
WIDTH, HEIGHT = 600, 400
BLOCK_SIZE = 20  # 蛇与食物的大小
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("贪吃蛇游戏")

clock = pygame.time.Clock()

# 使用支持中文的字体(需准备支持中文的字体文件,如simhei.ttf放在同目录下)
font = pygame.font.Font("simhei.ttf", 30)

def draw_text(msg, color, x, y):
    text = font.render(msg, True, color)
    screen.blit(text, [x, y])

def create_food(snake_list):
    while True:
        x = random.randint(0, (WIDTH // BLOCK_SIZE) - 1) * BLOCK_SIZE
        y = random.randint(0, (HEIGHT // BLOCK_SIZE) - 1) * BLOCK_SIZE
        if [x, y] not in snake_list:
            return [x, y]

def game_loop():
    # 初始参数
    game_over = False
    game_close = False

    # 初始蛇位置与移动方向
    x = WIDTH // 2
    y = HEIGHT // 2
    x_change = 0
    y_change = 0

    snake_list = []
    snake_length = 1

    food = create_food(snake_list)
    score = 0

    while not game_over:
        while game_close:
            screen.fill(BLACK)
            draw_text("游戏结束,按 Q 退出 或 C 重来", RED, WIDTH//4, HEIGHT//3)
            draw_text(f"得分: {score}", WHITE, WIDTH//4, HEIGHT//3 + 40)
            pygame.display.update()

            for event in pygame.event.get():
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_q:
                        game_over = True
                        game_close = False
                    elif event.key == pygame.K_c:
                        return  # 重新开始
                elif event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()

        # 方向控制
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                # 避免180度掉头:当向左移动时不允许直接向右,向上时不允许直接向下,反之亦然
                if event.key == pygame.K_LEFT and x_change == 0:
                    x_change = -BLOCK_SIZE
                    y_change = 0
                elif event.key == pygame.K_RIGHT and x_change == 0:
                    x_change = BLOCK_SIZE
                    y_change = 0
                elif event.key == pygame.K_UP and y_change == 0:
                    y_change = -BLOCK_SIZE
                    x_change = 0
                elif event.key == pygame.K_DOWN and y_change == 0:
                    y_change = BLOCK_SIZE
                    x_change = 0

        # 如果蛇还未开始移动,则不更新位置(防止游戏开始后立即结束)
        if x_change == 0 and y_change == 0:
            # 等待用户进行第一次方向输入
            pygame.display.update()
            clock.tick(10)
            continue

        # 更新蛇头位置
        x += x_change
        y += y_change

        # 边界检测
        if x < 0 or x >= WIDTH or y < 0 or y >= HEIGHT:
            game_close = True

        screen.fill(BLACK)
        # 绘制食物
        pygame.draw.rect(screen, GREEN, [food[0], food[1], BLOCK_SIZE, BLOCK_SIZE])

        # 更新蛇身体列表
        snake_head = [x, y]
        snake_list.append(snake_head)
        if len(snake_list) > snake_length:
            del snake_list[0]

        # 蛇头碰到身体检测
        for segment in snake_list[:-1]:
            if segment == snake_head:
                game_close = True

        # 绘制蛇
        for segment in snake_list:
            pygame.draw.rect(screen, WHITE, [segment[0], segment[1], BLOCK_SIZE, BLOCK_SIZE])

        draw_text(f"得分: {score}", WHITE, 10, 10)
        pygame.display.update()

        # 判断是否吃到食物
        if x == food[0] and y == food[1]:
            food = create_food(snake_list)
            snake_length += 1
            score += 10

        clock.tick(10)  # 控制游戏帧率

def main():
    while True:
        game_loop()

if __name__ == "__main__":
    main()

拓展与优化建议

添加音效:在吃食物或游戏结束时播放音效。

难度调节:增加游戏关卡或根据得分提升蛇的移动速度。

UI美化:换成更精美的图片作为蛇身和食物贴图。

排行榜功能:记录每次游戏的分数,并在游戏结束时显示历史最高分。

总结

通过本篇博客的学习,我们了解了如何借助Python与Pygame实现一个简单的贪吃蛇游戏。从基础的游戏循环、蛇与食物的数据结构设计,到碰撞检测与绘制画面,都有了一个清晰的实现范例。未来,您可以在这个基础上添加更多特性,打造一款更丰富、更有趣的游戏体验,当然这仅仅是一个小案例,若想要完整的实现,可以看看建议,或者结合其他游戏开发工具,unity,虚幻等

相关推荐
Alfred king2 小时前
面试150 生命游戏
leetcode·游戏·面试·数组
思则变3 小时前
[Pytest] [Part 2]增加 log功能
开发语言·python·pytest
漫谈网络3 小时前
WebSocket 在前后端的完整使用流程
javascript·python·websocket
try2find5 小时前
安装llama-cpp-python踩坑记
开发语言·python·llama
博观而约取6 小时前
Django ORM 1. 创建模型(Model)
数据库·python·django
精灵vector7 小时前
构建专家级SQL Agent交互
python·aigc·ai编程
Zonda要好好学习7 小时前
Python入门Day2
开发语言·python
Vertira7 小时前
pdf 合并 python实现(已解决)
前端·python·pdf
太凉7 小时前
Python之 sorted() 函数的基本语法
python
项目題供诗8 小时前
黑马python(二十四)
开发语言·python