python实现一个简单的贪吃蛇游戏附代码


Posted in Python onJune 28, 2022

前言:

不知道有多少同学跟我一样,最初接触编程的动机就是为了自己做个游戏玩?

今天要给大家分享的是一个 pygame 写的“贪吃蛇”小游戏:

python实现一个简单的贪吃蛇游戏附代码

“贪吃蛇”这个小游戏在编程学习中的常客,因为:

简单,最基本的游戏元素只需要蛇和食物两个就可以进行了。(打飞机还需要三个元素呢,想想分别是什么?)方向的话只要上下左右4个固定方向就可以了。有基本的数据结构和面向对象的思想在其中。游戏开发本身就会用到很多面向对象的概念,而蛇的身体又是一个天然的“链表”结构,太适合用来练习数据结构了。另外比较有趣的一点是,Python 这个单词在英语里就是蟒蛇的意思,贪吃蛇可以算是“同名游戏”了。很多学校里程序开发课程的作业都会有贪吃蛇的选题,也经常会有同学问到我们相关的代码。(诺基亚手机对这款游戏也是情有独钟。)之前我做过一个《贪吃蛇大作战》的 Python 版本,基于 cocos2d-python 开发。但那个对于初学者来说有些复杂了。
这里我们做个简要介绍:
此代码基于 pygame 开发,所以运行前请确保你的 Python 里已成功安装 pygame。然后直接运行代码中的 game2.py 即可开始游戏。除了最终的代码外,我们还特意分解了几个过程中的 py 文件,供想要自己开发的同学参考。
我们先来分析一下,要写出这个游戏来需要注意哪些点。

1、蛇怎么表示?

我们可以将整个游戏区域划分成一个个的小格子,由一组连在一起的小格子组成“蛇”,我们可以用不同的颜色来表示,如上图中,我以深色表示背景,浅色表示“蛇”。
我们可以用坐标来表示每一个小方格,X 轴和 Y 轴的范围都是可以设定好的。用一个列表来存放“蛇身”的坐标,那么一条“蛇”就出来了,最后只要显示的时候以不同的颜色表示即可。

2、蛇怎么移动?

第一反应就是像蚯蚓蠕动一样,每一个小方块向前移动一格,但这样实现起来很麻烦。一开始就是被这里卡住了。
想象一下我们玩过的贪吃蛇,每次“蛇”的移动感觉上是整体往前移动了一格,排除掉脑子中“蛇”的“动作”,细想移动前和移动后“蛇”的位置变化,其实除了头尾,其他部分根本就没有变。那就简单了,将下一格的坐标添加到列表开头,并移除列表的最后一个元素,就相当于蛇向前移动了一格。

3、如何判定游戏结束?

“蛇”移动超出了游戏区的范围或者碰到了自己就算输了,轴坐标的范围是事先定好的,超出范围很容易判断。那么如何判断碰到自己呢?
如果脑子里想的是“蛇”动的画面,那真的比较难了,但是放到代码中,我们的“蛇”是一个列表,那么只要判断下一格的坐标是否已经包含在“蛇”的列表中岂不就可以了?
理清了这些问题,我们就可以开始编码了。

定义游戏元素及界面:

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()

全部代码:

"""
贪吃蛇小游戏
"""
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()

tips:这个贪吃蛇的游戏还是很简单的,大家可以尝试运行哦。

到此这篇关于python实现一个简单的贪吃蛇游戏附代码的文章就介绍到这了,更多相关python贪吃蛇游戏内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!


Tags in this post...

Python 相关文章推荐
Windows系统配置python脚本开机启动的3种方法分享
Mar 10 Python
用Python写王者荣耀刷金币脚本
Dec 21 Python
python: line=f.readlines()消除line中\n的方法
Mar 19 Python
Python实现的凯撒密码算法示例
Apr 12 Python
详解Python下Flask-ApScheduler快速指南
Nov 04 Python
解决Python下imread,imwrite不支持中文的问题
Dec 05 Python
Python Matplotlib实现三维数据的散点图绘制
Mar 19 Python
Django文件存储 自己定制存储系统解析
Aug 02 Python
Python 爬虫实现增加播客访问量的方法实现
Oct 31 Python
Python各种扩展名区别点整理
Feb 27 Python
通过cmd进入python的步骤
Jun 16 Python
matplotlib实现数据实时刷新的示例代码
Jan 05 Python
python数字图像处理之对比度与亮度调整示例
Jun 28 #Python
python数字图像处理实现图像的形变与缩放
在python中读取和写入CSV文件详情
Jun 28 #Python
python数字图像处理之图像的批量处理
如何利用python实现Simhash算法
Jun 28 #Python
python数字图像处理:图像的绘制
python数字图像处理数据类型及颜色空间转换
You might like
第八节--访问方式
2006/11/16 PHP
PHP基础之运算符的使用方法
2013/04/28 PHP
微信扫描二维码登录网站代码示例
2013/12/30 PHP
PHP安装threads多线程扩展基础教程
2015/11/17 PHP
yum命令安装php7和相关扩展
2016/07/04 PHP
php版微信公众平台之微信网页登陆授权示例
2016/09/23 PHP
js 数组操作代码集锦
2009/04/28 Javascript
js 与 php 通过json数据进行通讯示例
2014/03/26 Javascript
玩转方法:call和apply
2014/05/08 Javascript
使用JavaScript 编写简单计算器
2014/11/24 Javascript
IE浏览器下PNG相关功能
2015/07/05 Javascript
使用JQuery实现Ctrl+Enter提交表单的方法
2015/10/22 Javascript
JS获取月份最后天数、最大天数与某日周数的方法
2015/12/08 Javascript
JavaScript使用forEach()与jQuery使用each遍历数组时return false 的区别
2016/08/26 Javascript
探究react-native 源码的图片缓存问题
2017/08/24 Javascript
javascript获取指定区间范围随机数的方法
2017/09/08 Javascript
使用vue与jquery实时监听用户输入状态的操作代码
2017/09/19 jQuery
highcharts 在angular中的使用示例代码
2017/09/20 Javascript
AngularJS中的作用域实例分析
2018/05/16 Javascript
小程序点击图片实现自动播放视频
2020/05/29 Javascript
Vue项目中使用better-scroll实现一个轮播图自动播放功能
2018/12/03 Javascript
VScode格式化ESlint方法(最全最好用方法)
2019/09/10 Javascript
python中for语句简单遍历数据的方法
2015/05/07 Python
python 处理string到hex脚本的方法
2018/10/26 Python
Python3内置模块pprint让打印比print更美观详解
2019/06/02 Python
django表单的Widgets使用详解
2019/07/22 Python
Django时区详解
2019/07/24 Python
python3 pathlib库Path类方法总结
2019/12/26 Python
Oroton中国官网:澳洲知名奢侈配饰品牌
2017/03/26 全球购物
Linux开机引导的步骤是什么
2014/02/26 面试题
创业者是否需要商业计划书?
2014/02/07 职场文书
男人帮观后感
2015/06/18 职场文书
《所见》教学反思
2016/02/23 职场文书
使用Springboot实现健身房管理系统
2021/07/01 Java/Android
JavaScript 数组去重详解
2021/09/15 Javascript
详解在SQLPlus中实现上下键翻查历史命令的功能
2022/03/18 SQL Server