Python游戏编程:用Python打造经典贪吃蛇小游戏

news/2024/9/17 1:51:47/ 标签: python, 游戏, pygame

贪吃蛇作为一款极其经典且广受欢迎的小游戏,是早期 Windows 电脑和功能手机(特别是诺基亚手机)流行度极高的小游戏,是当时功能手机时代最具代表性的游戏之一。
在这里插入图片描述

贪吃蛇游戏分析

控制蛇的移动:通过上下左右键,控制一条蛇在游戏区域中移动,最初蛇很短,通常由 1 个方块组成。

吃到食物增长:游戏区域中会随机出现食物(例如一个方块),当蛇头触碰到食物时,代表蛇吃到了食物,蛇身体会增长一节,同时得 1 分。

避免越界或碰撞:游戏中需要避免蛇头撞到游戏区域的边界,或者蛇头碰到自己的身体。

策略性移动:随着游戏的进行蛇身增长,需要巧妙地操控蛇的路径,既要吃到食物,又要避免越界碰撞,这变得越来越具挑战性和趣味性。

游戏分数和结束:游戏过程中,需要记录当前得分(即:蛇吃到食物的数量),游戏结束,展示总得分和重新开始游戏或者退出。

在这里插入图片描述

游戏进行中界面

pygame__20">准备:安装 pygame 工具包

贪吃蛇游戏依赖pygame这个强大的 Python 游戏工具包:

pip install pygame   

代码:设置基础参数

基础参数包括屏幕大小、中文字体、背景颜色、字体颜色、蛇的颜色、食物的颜色、蛇的大小和蛇游动速度等。中文simsun.ttf字体文件在源代码目录,请一起下载到本地:

import random   import pygame      # 初始化   pygame.init()      # 设置窗口和初始化   SCREEN_WIDTH = 640   SCREEN_HEIGHT = 480   SCREEN = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))      # 设置窗口标题   pygame.display.set_caption('老牛同学:贪吃蛇')      # 游戏屏幕字体   SCORE_FONT = pygame.font.Font('./fonts/simsun.ttf', 25)   RESULT_FONT = pygame.font.Font('./fonts/simsun.ttf', 25)      # 颜色设置   BLACK = (0, 0, 0)  # 黑色(屏幕的颜色)   WHITE = (255, 255, 255)  # 白色(分数的颜色)   GREEN = (0, 255, 0)  # 绿色(蛇的颜色)   RED = (255, 0, 0)  # 红色(食物的颜色,游戏结束字体的颜色)      # 蛇区块大小(正方形)和游动速度   SNAKE_BLOCK = 10   SNAKE_SPEED = 8   

代码:绘制游戏进行中的得分

游戏进行中,得分默认在窗口左上角展示:

def draw_score(score):       """绘制当前分数"""       score_text = SCORE_FONT.render("总分数:" + str(score), True, WHITE)       #SCREEN.blit(score_text, [20, 20])  # 左上角   

也可以设置为顶部居中展示,如下代码:

def draw_score(score):       """绘制当前分数"""       score_text = SCORE_FONT.render("总分数:" + str(score), True, WHITE)       score_rect = score_text.get_rect(center=(SCREEN_WIDTH // 2, 20))       SCREEN.blit(score_text, score_rect)   

代码:绘制游戏进行中蛇的身体

游戏进行中,蛇的身体其实就是一些方块的位置,蛇的数据结构为一个 list 列表,列表的元素是 x 和 y 坐标 list 列表,即[[x1,y1],[x2,y2],[x3,y3]...]数据存储形式,蛇尾是第 1 个元素,蛇头是在最后 1 个元素。

def draw_snake(snake_list):       """绘制蛇的身体,由于都是方块,所以绘制过程无需区分蛇头和蛇身等"""       for x in snake_list:           pygame.draw.rect(SCREEN, GREEN, [x[0], x[1], SNAKE_BLOCK, SNAKE_BLOCK])   

问题:蛇尾在第 1 个元素,而蛇头在最后 1 个元素,为什么要这么设计?

答案:从后面代码可以看出,蛇在游动的过程中,蛇新的坐标是用的append到列表,然后删除列表的第 1 个元素。当然完全可以通过insert的方式反过来设计。

代码:计算食物的随机坐标

我们使用random函数随机计算食物的坐标,同时需要注意,避免食物越界:

def food_position():       """随机计算食物坐标"""       x_food = round(random.randrange(0, SCREEN_WIDTH - SNAKE_BLOCK, SNAKE_BLOCK))       y_food = round(random.randrange(0, SCREEN_HEIGHT - SNAKE_BLOCK, SNAKE_BLOCK))       return x_food, y_food   

代码:绘制游戏结束分数和提示

我们在屏幕正中央分别展示 3 行提示文本:游戏结束、总得分和继续游戏提示。文本正中央展示和总得分类似:

def draw_result(snake_length):  """绘制游戏结果"""  # 在屏幕中央显示文本  game_over_text = RESULT_FONT.render('游戏结束', True, RED)  game_over_rect = game_over_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2 - 50))  SCREEN.blit(game_over_text, game_over_rect)  # 显示最终得分文本  final_score_text = RESULT_FONT.render(f'总得分: {snake_length - 1}', True, RED)  final_score_rect = final_score_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2))  SCREEN.blit(final_score_text, final_score_rect)  # 显示重新开始游戏的提示文本  restart_text = RESULT_FONT.render('按`Q`退出游戏,按`C`重新开始游戏', True, RED)  restart_rect = restart_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2 + 50))  SCREEN.blit(restart_text, restart_rect)  

代码:游戏主循环设置

主循环游戏把以上功能函数缝合起来,同时包括控制代码:

  1. game_close参数控制单局游戏是否结束,game_over参数控制整个游戏是否结束

  2. 上下左右按键:上下按键控制蛇Y轴(上减少、下增加),左右按键控制蛇X轴(左减少、右增加)

  3. 蛇触墙检测:蛇头坐标x1,y1是否在整个屏幕之内

  4. 蛇触蛇身检测:蛇头坐标是否在蛇身体的任意坐标相同

  5. 蛇吃到食物检测:蛇头坐标是否和食物坐标相同,如果相同则重新设置食物位置,同时蛇身长加 1 个方块

def game_loop():  """游戏主循环函数"""  game_over = False  # 退出游戏  game_close = False  # 单次游戏结束  # 初始化蛇的坐标和坐标增量  x1 = SCREEN_WIDTH / 2  y1 = SCREEN_HEIGHT / 2  x1_change = 0  y1_change = 0  # 蛇的身体列表,初始长度为1  snake_list = []  snake_length = 1  # 随机生成食物的位置  x_food, y_food = food_position()  while not game_over:  # 如果游戏结束但未选择退出或重玩,则进入此循环  while game_close:  # 清空屏幕,准备下一轮绘制  SCREEN.fill(BLACK)  draw_result(snake_length)  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:  game_loop()  # 重新开始游戏  # 处理键盘事件,改变蛇的移动方向  for event in pygame.event.get():  if event.type == pygame.QUIT:  game_over = True  # 退出游戏  if event.type == pygame.KEYDOWN:  if event.key == pygame.K_LEFT:  # 左:X坐标减少1个区块,Y坐标不变  x1_change = -1  y1_change = 0  elif event.key == pygame.K_RIGHT:  # 右:X坐标增加1个区块,Y坐标不变  x1_change = 1  y1_change = 0  elif event.key == pygame.K_UP:  # 上:X坐标不变,Y坐标减少1个区块  x1_change = 0  y1_change = -1  elif event.key == pygame.K_DOWN:  # 下:X坐标不变,Y坐标增加1个区块  x1_change = 0  y1_change = 1  # 退出游戏  if game_over:  break  # 检测蛇是否触墙  if x1 >= SCREEN_WIDTH or x1 < 0 or y1 >= SCREEN_HEIGHT or y1 < 0:  game_close = True  # 更新蛇的位置  x1 += x1_change * SNAKE_BLOCK  y1 += y1_change * SNAKE_BLOCK  # 清空屏幕,准备下一轮绘制  SCREEN.fill(BLACK)  # 画食物  pygame.draw.rect(SCREEN, RED, [x_food, y_food, SNAKE_BLOCK, SNAKE_BLOCK])  # 新的蛇头位置,同时删除最后蛇尾区块,以保持蛇的总长度不变  snake_head = [x1, y1]  snake_list.append(snake_head)  if len(snake_list) > snake_length:  del snake_list[0]  # 删除蛇尾  # 检查蛇头是否碰到蛇的身体  for x in snake_list[:-1]:  if x == snake_head:  game_close = True  # 绘制蛇  draw_snake(snake_list)  # 绘制得分  draw_score(snake_length - 1)  # 刷新屏幕  pygame.display.update()  # 检查蛇头是否碰到食物,若碰到则增加长度并重新生成食物  if x1 == x_food and y1 == y_food:  x_food, y_food = food_position()  snake_length += 1  # 控制游戏帧率  clock = pygame.time.Clock()  clock.tick(SNAKE_SPEED)  # 游戏结束时清理pygame环境  pygame.quit()  quit()  

最后:启动游戏主循环

启动游戏,进入主循环,通过上下左右按键控制蛇身游动:

# 开始游戏  
if __name__ == '__main__':  game_loop()  

最后,我们游戏界面大概像这样:

在这里插入图片描述

游戏进行中界面

单局游戏结束的界面:

在这里插入图片描述

游戏结束界面

禅定: 我们可以继续进一步优化这个程序:

  1. 每次吃到食物、单局游戏结束增加音效

  2. 增加难度:长按上下左右按键,加速蛇游动的速度

  3. 记住每轮游戏分数,进行分数排名(本地记录,或者联网)


关于Python技术储备

学好 Python 不论是就业还是做副业赚钱都不错,但要学会 Python 还是要有一个学习规划。最后大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!

在这里插入图片描述

👉Python学习路线汇总👈

Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。

在这里插入图片描述

👉Python必备开发工具👈

在这里插入图片描述

👉Python学习视频合集👈

观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。

在这里插入图片描述

👉实战案例👈

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

在这里插入图片描述

👉Python副业兼职路线&方法👈

学好 Python 不论是就业还是做副业赚钱都不错,但要学会兼职接单还是要有一个学习规划。

在这里插入图片描述

👉 这份完整版的Python全套学习资料已经上传,朋友们如果需要可以扫描下方二维码免费领取

在这里插入图片描述


http://www.ppmy.cn/news/1522216.html

相关文章

目标检测-YOLOv5

YOLOv5介绍 YOLOv5 是 YOLO 系列的第五个版本&#xff0c;由 Ultralytics 团队发布。虽然 YOLOv5 并非 Joseph Redmon 原团队发布&#xff0c;但它在 YOLOv4 的基础上进行了重要的优化和改进&#xff0c;成为了深度学习目标检测领域中的热门模型之一。YOLOv5 的优势不仅体现在…

TLC SSD强行关闭SLC缓存会怎样?

如今的SSD不管是TLC闪存还是QLC闪存&#xff0c;都有SLC模拟缓存技术&#xff0c;在缓存内读写可以获得极高的速度。 但你有没有想过&#xff0c;如果把这个功能关闭&#xff0c;会有什么变化&#xff1f; TechPowerUp SSD数据库维护者、资深内容编辑Gabriel Ferraz就做了一次试…

Go语言基础语法 20240904更新

代码开源地址 https://github.com/zhangdapeng520/zdpgo_basic 快速入门 示例代码&#xff1a; package mainimport "fmt"func main() {fmt.Println("Hello World") }第一行代码 package 用来声明包名。main包时整个程序的入口包&#xff0c;在一个Go语…

基于微信小程序在线订餐系统

微信小程序在线订餐系统 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了微信小程序在线订餐系统的开发全过程。通过分析微信小程序在线订餐系统管理的不足&#xff0c;创建了一个计算机管理微信小程序在线订…

大话C++:第6篇 命名空间namespace作用域

1 命名空间概述 在一个大型的软件项目中&#xff0c;可能会有许多不同的代码文件&#xff0c;这些文件可能由不同的开发者编写&#xff0c;或者来自不同的库和模块。如果这些代码文件中存在同名的变量、函数、类或其他标识符&#xff0c;那么在编译或运行时就可能发生命名冲突…

javascript中数组遍历的所有方法

作为后端程序员平常js用得少&#xff0c;但是数组遍历又是常用功能&#xff0c;遍历方法又有很多。在此记录一下&#xff0c;所有用得上的数组遍历方法。 1.for循环 最基本的数组遍历 特点: 通常配合数组的 .length 属性使用。索引从0开始&#xff0c;需要注意边界问题。 …

3674B/C/D/E/F/G矢量网络分析仪

3674B/C/D/E/F/G矢量网络分析仪 <<<3674系列矢量网络分析仪>>> Ceyear 3674系列矢量网络分析仪是技术创新的巅峰之作&#xff0c;可以轻松应对半导体芯片测试、材料测试、天线测试、高速线缆测试、微波部组件测试等带来的严峻挑战。出色的射频特性、灵活的硬…

深度学习助力病理切片虚拟组织染色|文献精析·24-09-03

小罗碎碎念 这篇文章综述了深度学习技术在生物样本虚拟组织染色领域的最新研究进展&#xff0c;探讨了其在提高病理诊断效率和降低成本方面的潜力。 作者角色作者姓名单位名称&#xff08;英文&#xff09;单位名称&#xff08;中文&#xff09;第一作者Bijie BaiElectrical an…

使用Docker快速启动Nacos集群

Nacos 是一个易于使用的平台&#xff0c;用于动态服务发现、配置管理和服务管理。它帮助您在云环境中快速构建云原生应用程序&#xff0c;支持服务的注册与发现、动态配置更新等功能。在本文中&#xff0c;我们将介绍如何使用 Docker 快速启动 Nacos 集群。 为什么使用 Docker…

结构型设计模式-外观(facade)模式 - python实现

设计模式汇总&#xff1a;查看 通俗示例 想象一下你去餐厅吃饭&#xff0c;当你坐下后&#xff0c;服务员会为你提供菜单&#xff0c;并负责帮你点菜&#xff0c;通知厨房烹饪&#xff0c;最后将食物端给你。在整个过程中&#xff0c;你不需要直接和厨师、洗碗工或其他餐厅工作…

c#获取当天零点时间戳

以下毫秒为单位 之前获取当天零点的代码如下: public static long GetCurDayZeroTime(long timeStampMS){var timeStampStart new DateTime(1970, 1, 1, 8, 0, 0);var now timeStampStart.AddMilliseconds(timeStampMS);var nowZero new DateTime(now.Year, now.Month, now.…

[论文笔记] t-SNE数据可视化

pip install matplotlib scikit-learn sentence-transformers数据分类别可视化 t-SNE算法将高维数据映射到2D空间后的坐标。 t-SNE是一种用于数据降维和可视化的技术,它的作用是将原本在高维空间中的复杂数据压缩到低维空间,同时尽可能保留数据点之间的距离关系。 举例: h…

基于 RocketMQ 的云原生 MQTT 消息引擎设计

作者&#xff1a;沁君 概述 随着智能家居、工业互联网和车联网的迅猛发展&#xff0c;面向 IoT&#xff08;物联网&#xff09;设备类的消息通讯需求正在经历前所未有的增长。在这样的背景下&#xff0c;高效和可靠的消息传输标准成为了枢纽。MQTT 协议作为新一代物联网场景中…

【佳学基因检测】网站加密证书失效后,如何移除并为新的证书安装准备环境?

【佳学基因检测】网站加密证书失效后&#xff0c;如何移除并为新的证书安装准备环境&#xff1f; 当WoTrus DV Server CA证书失效后&#xff0c;你需要确保你的Nginx配置中不再引用该证书&#xff0c;并且移除或替换相关的证书文件。以下是具体步骤&#xff1a; 1. 确认Nginx…

个性化阅读体验:Spring Boot驱动的图书推荐系统

1 绪论 1.1研究背景 随着网络不断的普及发展&#xff0c;图书个性化推荐系统依靠网络技术的支持得到了快速的发展&#xff0c;首先要从学生的实际需求出发&#xff0c;通过了解学生的需求开发出具有针对性的首页、图书信息、好书推荐、留言反馈、个人中心、后台管理功能&#x…

【C++】手动实现队列的封装(C++)

目录 源代码&#xff1a; 输出结果如下&#xff1a; 实现以下封装 源代码&#xff1a; #include <iostream>using namespace std;class Queue { private:int* arr; // 队列的动态数组int front; // 队列头部元素的索引int rear; // 队列尾部元素的索引in…

数据的表示-(反码,原码,补码,移码)

原码&#xff1a;最高位是符号位&#xff0c;其余低位表示数值的绝对值。 反码&#xff1a;整数的反码与原码相同&#xff0c;负数的反码是其绝对值按位取反&#xff0c;符号位不变 补码&#xff1a;整数的补码与原码相同&#xff0c;负数的补码是其反码末位加1. 移码&#xff…

c语言——用一维数组输出杨辉三角形

一.代码 #include <stdio.h> int Num[100]; int Hang; int Lie; int a; int Flag; int main() {Lie 1;Hang 1;a 0;while (1) {//列1为1if (Lie 1) {Num[1] 1;Lie;}//数据存到数组里面while (Hang > Lie && Hang ! 2) { if (Hang!Lie) {Flag Num[Lie] …

每日一题,力扣leetcode Hot100之238.除自身以外数组的乘积

乍一看这个题很简单&#xff0c;但是不能用除法&#xff0c;并且在O(N)时间复杂度完成或许有点难度。 考虑到不能用除法&#xff0c;如果我们要计算输出结果位置i的值&#xff0c;我们就要获取这个位置左边的乘积和右边的乘积&#xff0c;那么我新设立两个数组L和R。 对于L来…

c#如何实现触发另外一个文本框的回车事件

一.需求 我需要实现listview中的一行双击后&#xff0c;将其中的一个值传给一个文本框&#xff0c;传完后&#xff0c;给文本框一个回车指令。 我的方法&#xff1a;后面加上 \rthis.txt_ID.Text this.listView1.SelectedItems[0].Text"\r" 结果无效。 二.问通义…