Python 贪吃蛇

文章目录

  • 效果图:
  • 项目目录结构
    • main.py
    • game/apple.py
    • game/base.py
    • game/snake.py
    • constant.py

效果图:

请添加图片描述

项目目录结构

在这里插入图片描述

main.py

from snake.game.apple import Apple  # 导入苹果类
from snake.game.base import *  # 导入游戏基类
from snake.game.snake import Snake  # 导入蛇类class SnakeGame(GameBase):"""贪吃蛇游戏"""def __init__(self):"""初始化游戏"""super(SnakeGame, self).__init__(game_name=GAME_NAME, icon=ICON,  # 调用基类的初始化方法screen_size=SCREEN_SIZE,display_mode=DISPLAY_MODE,loop_speed=LOOP_SPEED,font_size=FONT_SIZE,background=WHITE,font_name=None)# 绘制背景self.prepare_background()# 创建游戏对象self.apple_count = 0  # 苹果计数器self.high_score = 0  # 记录最高分self.snake = Snake(self)  # 创建蛇对象self.apple = Apple(self)  # 创建苹果对象# 绑定按键事件self.add_key_binding(KEY_UP, self.snake.turn, direction=UP)  # 绑定上方向键self.add_key_binding(KEY_DOWN, self.snake.turn, direction=DOWN)  # 绑定下方向键self.add_key_binding(KEY_LEFT, self.snake.turn, direction=LEFT)  # 绑定左方向键self.add_key_binding(KEY_RIGHT, self.snake.turn, direction=RIGHT)  # 绑定右方向键self.add_key_binding(KEY_RESTART, self.restart)  # 绑定R键(重启游戏)self.add_key_binding(KEY_PAUSE, self.pause)  # 绑定R键(重启游戏)self.add_key_binding(KEY_EXIT, self.quit)  # 绑定退出键# 添加绘图函数self.add_draw_action(self.draw_score)  # 添加绘制分数的函数def prepare_background(self):"""准备背景"""self.background.fill(BACKGROUND_COLOR)  # 用背景颜色填充背景for _ in range(CELL_SIZE, SCREEN_WIDTH, CELL_SIZE):  # 绘制垂直网格线self.draw.line(self.background, GRID_COLOR, (_, 0), (_, SCREEN_HEIGHT))for _ in range(CELL_SIZE, SCREEN_HEIGHT, CELL_SIZE):  # 绘制水平网格线self.draw.line(self.background, GRID_COLOR, (0, _), (SCREEN_WIDTH, _))def restart(self):"""重启游戏"""if not self.snake.is_alive:  # 如果蛇已经死亡self.apple_count = 0  # 重置苹果计数器self.apple.drop()  # 重新放置苹果self.snake.restart_pawn()  # 重生蛇self.running = True  # 继续游戏循环def draw_score(self):"""绘制分数"""text = f"Apple: {self.apple_count}"  # 准备要绘制的文本self.high_score = max(self.high_score, self.apple_count)  # 更新最高分self.draw_text(text, (0, 0), (255, 255, 33))  # 绘制文本if not self.snake.is_alive:  # 如果蛇已经死亡self.draw_text(" 游戏结束 ", (SCREEN_WIDTH / 2 - 54, SCREEN_HEIGHT / 2 - 10),  # 绘制游戏结束文本(255, 33, 33), WHITE)self.draw_text(" 按R键重启 ", (SCREEN_WIDTH / 2 - 85, SCREEN_HEIGHT / 2 + 20),  # 绘制重启提示文本GREY, DARK_GREY)self.draw_text(f"当前最高分: {self.high_score}", (SCREEN_WIDTH / 2 - 114, SCREEN_HEIGHT / 2 + 50),  # 绘制最高分文本(255, 33, 33), WHITE)  # 展示最高分if not self.running and self.snake.is_alive:  # 如果游戏暂停且蛇还活着self.draw_text("游戏暂停 ", (SCREEN_WIDTH / 2 - 55, SCREEN_HEIGHT / 2 - 10),  # 绘制游戏暂停文本LIGHT_GREY, DARK_GREY)if __name__ == '__main__':SnakeGame().run()  # 运行游戏

game/apple.py

from random import randint
from snake.constant import *class Apple:"""苹果类:表示游戏中的苹果,蛇吃到苹果会增长身体长度。"""def __init__(self, game):"""初始化苹果对象。:param game: 游戏对象。"""self.game = gameself.x = self.y = 0  # 苹果的初始位置self.game.add_draw_action(self.draw)  # 将 draw 方法添加到游戏的绘制动作列表中self.drop()  # 生成一个新的苹果def drop(self):"""生成一个新的苹果,确保苹果不在蛇的身体上。"""snake = self.game.snake.body + [self.game.snake.head]  # 获取蛇的身体和头部的所有位置while True:(x, y) = randint(0, COLUMNS - 1), randint(0, ROWS - 1)  # 随机生成一个位置if (x, y) not in snake:  # 如果这个位置不在蛇的身体上self.x, self.y = x, y  # 将苹果的位置设置为这个位置break  # 退出循环def draw(self):"""绘制苹果。"""self.game.draw_cell((self.x, self.y),  # 苹果的位置CELL_SIZE,  # 每个单元格的大小APPLE_COLOR_SKIN,  # 苹果的外框颜色APPLE_COLOR_BODY  # 苹果的主体颜色)

game/base.py

import os
import sys
import time
from snake.constant import *# 使窗口居中
os.environ["SDL_VIDEO_CENTERED"] = "1"# MyGame 默认值
GAME_NAME = "贪吃蛇 By stormsha"
SCREEN_SIZE = 640, 480
DISPLAY_MODE = pygame.HWSURFACE | pygame.DOUBLEBUF
LOOP_SPEED = 60
# noinspection SpellCheckingInspection
FONT_NAME = "resources/MONACO.ttf"
FONT_SIZE = 16
KEY_PAUSE = pygame.K_PAUSEclass GameBase(object):"""pygame模板类"""def __init__(self, **kwargs):"""初始化可选参数:game_name       游戏名称icon            图标文件名screen_size     画面大小display_mode    显示模式loop_speed      主循环速度font_name       字体文件名font_size       字体大小"""pygame.init()pygame.mixer.init()self.game_name = kwargs.get("game_name") or GAME_NAMEpygame.display.set_caption(self.game_name)self.screen_size = kwargs.get("screen_size") or SCREEN_SIZEself.screen_width, self.screen_height = self.screen_sizeself.display_mode = kwargs.get("display_mode") or DISPLAY_MODEself.images = {}self.sounds = {}self.musics = {}self.icon = kwargs.get("icon") or Noneself.icon and pygame.display.set_icon(pygame.image.load(self.icon))self.screen = pygame.display.set_mode(self.screen_size,self.display_mode)self.loop_speed = kwargs.get("loop_speed") or LOOP_SPEEDself.font_size = kwargs.get("font_size") or FONT_SIZEself.background = None# noinspection SpellCheckingInspection''' 支持中文的字体新细明体:PMingLiU细明体:MingLiU标楷体:DFKai - SB黑体:SimHei宋体:SimSun新宋体:NSimSun仿宋:FangSong楷体:KaiTi仿宋_GB2312:FangSong_GB2312楷体_GB2312:KaiTi_GB2312微软正黑体:Microsoft JhengHei微软雅黑体:Microsoft YaHei'''self.font_name = kwargs.get("font_name") or pygame.font.match_font('SimHei')  # 获取系统字体self.font = pygame.font.Font(self.font_name, self.font_size)self.clock = pygame.time.Clock()self.now = 0self.background_color = kwargs.get("background") or BLACKself.set_background()self.key_bindings = {}  # 按键与函数绑定字典self.add_key_binding(KEY_PAUSE, self.pause)self.game_actions = {}  # 游戏数据更新动作self.draw_actions = [self.draw_background]  # 画面更新动作列表self.running = Trueself.draw = pygame.drawdef run(self):"""主循环"""while True:self.now = pygame.time.get_ticks()self.process_events()if self.running:self.update_game_data()self.update_display()self.clock.tick(self.loop_speed)def pause(self):"""暂停游戏"""self.running = not self.runningif self.running:for action in self.game_actions.values():if action["next_time"]:action["next_time"] = self.now + action["interval"]def process_events(self):"""事件处理"""for event in pygame.event.get():if event.type == pygame.QUIT:self.quit()elif event.type == pygame.KEYDOWN:action, kwargs = self.key_bindings.get(event.key, (None, None))# noinspection allaction(**kwargs) if kwargs else action() if action else Nonedef update_game_data(self):"""更新游戏数据"""for action in self.game_actions.values():if not action["next_time"]:action["run"]()elif self.now >= action["next_time"]:action["next_time"] += action["interval"]action["run"]()def update_display(self):"""更新画面显示"""for action in self.draw_actions:action()pygame.display.flip()def draw_background(self):"""绘制背景"""self.screen.blit(self.background, (0, 0))def add_key_binding(self, key, action, **kwargs):"""增加按键绑定"""self.key_bindings[key] = action, kwargs# TODO: 更新动作若有次序要求,则用字典保存不合适def add_game_action(self, name, action, interval=0):"""添加游戏数据更新动作"""next_time = self.now + interval if interval else Noneself.game_actions[name] = dict(run=action,interval=interval,next_time=next_time)def add_draw_action(self, action):"""添加画面更新动作"""self.draw_actions.append(action)def draw_text(self, text, loc, color, bgcolor=None):if bgcolor:surface = self.font.render(text, True, color, bgcolor)else:surface = self.font.render(text, True, color)self.screen.blit(surface, loc)def draw_cell(self, xy, size, color1, color2=None):x, y = xyrect = pygame.Rect(x * size, y * size, size, size)self.screen.fill(color1, rect)if color2:self.screen.fill(color2, rect.inflate(-4, -4))@staticmethoddef quit():"""退出游戏"""pygame.quit()sys.exit(0)@staticmethoddef load_music(filename):pygame.mixer.music.load(filename)@staticmethoddef play_music():pygame.mixer.music.play(-1)@staticmethoddef pause_music():pygame.mixer.music.pause()@staticmethoddef resume_music():pygame.mixer.music.unpause()@staticmethoddef stop_music():pygame.mixer.music.stop()def save_screenshots(self):filename = time.strftime('screenshots/%Y%m%d%H%M%S.png')pygame.image.save(self.screen, filename)def load_images(self, filename, sub_img=None):sub_img = sub_img or {}image = pygame.image.load(filename).convert_alpha()  # 文件打开失败for name, rect in sub_img.items():x, y, w, h = rectself.images[name] = image.subsurface(pygame.Rect((x, y), (w, h)))def set_background(self, background=None):if isinstance(background, str):self.background = pygame.image.load(background)else:self.background = pygame.Surface(self.screen_size)self.background_color = background \if isinstance(background, tuple) else (0, 0, 0)self.background.fill(self.background_color)def load_sounds(self, **sounds):"""@summary: 加载音乐:param sounds::return:"""for name, filename in sounds.items():self.sounds[name] = pygame.mixer.Sound(filename)def play_sound(self, name):self.sounds[name].play()if __name__ == '__main__':GameBase().run()

game/snake.py

import pygamefrom snake import constantclass Snake:"""贪吃蛇"""def __init__(self, game):self.game = gameself.sound_hit = pygame.mixer.Sound("resources/hit.wav")self.sound_eat = pygame.mixer.Sound("resources/eat.wav")self.game.add_draw_action(self.draw)# 初始化数据self.head = (constant.SNAKE_X, constant.SNAKE_Y)  # 蛇头当前位置self.body = [(-1, -1)] * constant.SNAKE_BODY_LENGTH  # 蛇身长度self.direction = constant.SNAKE_DIRECTION  # 当前方向self.new_direction = constant.SNAKE_DIRECTION  # 移动方向self.speed = constant.SNAKE_SPEED  # 移动速度self.is_alive = True  # 是否存活def set_speed(self, speed):"""@summary: 设置蛇的移动速度:param speed: 移动速度:return:"""self._speed = speedself.game.add_game_action("snake.move", self.move, 1000 // speed)def get_speed(self):"""@summary: 获取当前蛇的移动速度:return:"""return self._speed@propertydef speed(self):return self._speed@speed.setterdef speed(self, speed):self._speed = speedself.game.add_game_action("snake.move", self.move, 1000 // speed)def draw(self):"""@summary: 绘制小蛇:return: """skin_color = constant.SNAKE_COLOR_SKIN if self.is_alive else constant.SNAKE_COLOR_SKIN_DEADbody_color = constant.SNAKE_COLOR_BODY if self.is_alive else constant.SNAKE_COLOR_BODY_DEADhead_color = constant.SNAKE_COLOR_HEAD if self.is_alive else constant.SNAKE_COLOR_HEAD_DEADfor cell in self.body:self.game.draw_cell(cell, constant.CELL_SIZE, skin_color, body_color)self.game.draw_cell(self.head, constant.CELL_SIZE, skin_color, head_color)def turn(self, direction):"""@summary: 改变小蛇方向:param direction: :return: """if (self.direction in (constant.LEFT, constant.RIGHT) and direction in (constant.UP, constant.DOWN) orself.direction in (constant.UP, constant.DOWN) and direction in (constant.LEFT, constant.RIGHT)):self.new_direction = directiondef move(self):"""@summary: 移动小蛇:return: """if not self.is_alive:return# 设定方向self.direction = self.new_direction# 检测前方x, y = meeting = (self.head[0] + self.direction[0],self.head[1] + self.direction[1])# 死亡判断if meeting in self.body or x not in range(constant.COLUMNS) or y not in range(constant.ROWS):self.die()return# 判断是否吃了苹果if meeting == (self.game.apple.x, self.game.apple.y):self.sound_eat.play()self.game.apple.drop()self.game.apple_count += 1else:self.body.pop()# 蛇头变成脖子self.body = [self.head] + self.body# 蛇头移动到新位置self.head = meetingdef restart_pawn(self):"""重生"""self.head = (constant.SNAKE_X, constant.SNAKE_Y)self.body = [(-1, -1)] * constant.SNAKE_BODY_LENGTHself.direction = constant.SNAKE_DIRECTIONself.new_direction = constant.SNAKE_DIRECTIONself.speed = constant.SNAKE_SPEEDself.is_alive = Truedef die(self):self.sound_hit.play()self.is_alive = False

constant.py

import pygame# 颜色设定
BLACK = 0, 0, 0
WHITE = 255, 255, 255
DARK_GREY = 33, 33, 33
GREY = 127, 127, 127
LIGHT_GREY = 192, 192, 192
BACKGROUND_COLOR = BLACK
GRID_COLOR = DARK_GREY
APPLE_COLOR_SKIN = 255, 127, 127
APPLE_COLOR_BODY = 255, 66, 66
SNAKE_COLOR_SKIN = 33, 255, 33
SNAKE_COLOR_BODY = 33, 192, 33
SNAKE_COLOR_HEAD = 192, 192, 33
SNAKE_COLOR_SKIN_DEAD = LIGHT_GREY
SNAKE_COLOR_BODY_DEAD = GREY
SNAKE_COLOR_HEAD_DEAD = DARK_GREY# 一般设定
GAME_NAME = "SnakeGame"
SCREEN_SIZE = SCREEN_WIDTH, SCREEN_HEIGHT = 640, 480
CELL_SIZE = 20
COLUMNS, ROWS = SCREEN_WIDTH // CELL_SIZE, SCREEN_HEIGHT // CELL_SIZE
DISPLAY_MODE = pygame.HWSURFACE | pygame.DOUBLEBUF
LOOP_SPEED = 60
# noinspection SpellCheckingInspection
FONT_NAME = "resources/MONACO.TTF"
FONT_SIZE = 16
# noinspection SpellCheckingInspection
ICON = "resources/snake.png"
UP, DOWN, LEFT, RIGHT = (0, -1), (0, 1), (-1, 0), (1, 0)# 按键设定
KEY_EXIT = pygame.K_ESCAPE
KEY_UP = pygame.K_UP
KEY_DOWN = pygame.K_DOWN
KEY_LEFT = pygame.K_LEFT
KEY_RIGHT = pygame.K_RIGHT
KEY_RESTART = pygame.K_r
K_PAUSE = pygame.K_PAUSE# 蛇的默认值
SNAKE_X = 0
SNAKE_Y = 0
SNAKE_BODY_LENGTH = 5
SNAKE_DIRECTION = RIGHT
SNAKE_SPEED = 10

源码地址:https://gitcode.com/stormsha1/games/overview

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/320916.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小米手机短信删除了怎么恢复?这里教你快速解决!

手机已经成为我们生活中不可或缺的一部分,比如小米手机。我们通过手机进行通讯、娱乐、学习等各种活动,其中,短信是我们日常生活中的重要信息来源之一。然而,我们可能会不小心删除了一些重要的短信,这时候我们就会想知…

【 Qt 的“前世”与“今生”】Qt 的起源 | Qt 的发展历程 | 为什么选择 Qt | Qt 的授权模式 | Qt 版本选择 | Qt Widgets和QML | Qt 程序发布

目录 1、什么是 Qt ? 2、Qt 可以用来做什么? 3、Qt 的由来与发展 3.1、Qt 的起源与发展 3.2、Qt 发展经历的三家公司 4、为什么选择 Qt ? 5、Qt 支持的平台 6、Qt 的授权模式 7、Qt 版本的选择 8、选择 QML 还是 Qt Widgets? 8.1…

RLC防孤岛负载测试的案例和实际应用经验有哪些?

RLC防孤岛负载测试是用于检测并防止电力系统出现孤岛现象的测试方法,孤岛现象是指当电网因故障或停电而与主电网断开连接时,一部分电网仍然与主电网保持连接,形成一个孤立的电网。这种情况下,如果电力系统不能及时检测到孤岛并采取…

2019年CSP-J入门级第一轮初赛真题

一.单项选择题(共 15 题,每题 2 分,共计 30 分;每题有且仅有一个正确选项) 中国的国家顶级域名是( ) A. .cnB. .chC. .chnD. .china 二进制数 11 1011 1001 0111 和 01 0110 1110 1011 进行逻辑与运算的结果…

linux——主从同步

1. 保证主节点开始二进制日志,从节点配置中继日志 2. 从节点的开启一个 I/O 线程读取主节点二进制日志的内容 3. 从节点读取主节点的二进制日志之后,会将去读的内容写入从节点的中继日志 4. 从节点开启 SQL 线程,读取中继日志的内容&a…

当AI遇见现实:数智化时代的人类社会新图景

文章目录 一、数智化时代的机遇二、数智化时代的挑战三、如何适应数智化时代《图解数据智能》内容简介作者简介精彩书评目录精彩书摘强化学习什么是强化学习强化学习与监督学习的区别强化学习与无监督学习的区别 前言/序言 随着科技的日新月异,我们步入了一个前所未…

运维自动化之 ansible

目录 一 常见的自动化运维工具 (一)有哪些常见的 自动化运维工具 (二)为什么后面都变成用 ansible 二 ansible 基本介绍 1, ansible 是什么 2,ansible能干什么 3,ansible 工作原…

无人机+三维建模:倾斜摄影技术详解

无人机倾斜摄影测量技术是一项高新技术,近年来在国际摄影测量领域得到了快速发展。这种技术通过从一个垂直和四个倾斜的五个不同视角同步采集影像,从而获取到丰富的建筑物顶面及侧视的高分辨率纹理。这种技术不仅能够真实地反映地物情况,还能…

(双指针) 有效三角形的个数 和为s的两个数字 三数之和 四数之和

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 文章目录 前言 一、有效三角形的个数(medium) 1.1、题目 1.2、讲解算法原理 1.3、编写代码 二、和为s的两个数字 2.1、题目 2.2、讲解算…

笔记1--Llama 3 超级课堂 | Llama3概述与演进历程

1、Llama 3概述 https://github.com/SmartFlowAI/Llama3-Tutorial.git 【Llama 3 五一超级课堂 | Llama3概述与演进历程】 2、Llama 3 改进点 【最新【大模型微调】大模型llama3技术全面解析 大模型应用部署 据说llama3不满足scaling law?】…

【C++】深入剖析C++11中右值引用和左值引用

目录 一、左值引用 && 右值引用 二、左值引用于右值引用的比较 三、 右值引用使用场景和意义 1、函数返回值 ①移动赋值 ②移动构造 2、STL容器插入接口 ​3、完美转发 一、左值引用 && 右值引用 传统的C语法中就有引用的语法,而C11中新增了…

pygame鼠标绘制

pygame鼠标绘制 Pygame鼠标绘制效果代码 Pygame Pygame是一个开源的Python库,专为电子游戏开发而设计。它建立在SDL(Simple DirectMedia Layer)的基础上,允许开发者使用Python这种高级语言来实时开发电子游戏,而无需被…

淘宝霸屏必备!了解淘宝商品评论电商API接口

淘宝商品评论电商API接口是指用于获取淘宝商品评论信息的一种接口,通过该接口可以获取淘宝网上商品的评价内容、评价等级、评价数量等信息。通过了解并使用该接口,联讯数据能够帮助电商了解消费者对商品的评价情况,做好商品的推广和销售工作。…

力扣刷题:四数相加Ⅱ

题目详情: 解法一:暴力枚举 对于这道题,我们的第一思路就是暴力枚举,我们可以写一个四层的for循环进行暴力匹配,只要相加的结果等于0就进行统计。但是我们会发现,我们的事件复杂度为O(N^4)事件复杂度非常大…

【Word】写论文,参考文献涉及的上标、尾注、脚注 怎么用

一、功能位置 二、脚注和尾注区别 1.首先脚注是一个汉语词汇,论文脚注就是附在论文页面的最底端,对某些内容加以说明,印在书页下端的注文。脚注和尾注是对文本的补充说明。 2.其次脚注一般位于页面的底部,可以作为文档某处内容的…

机器人系统ros2内部接口介绍

内部 ROS 接口是公共 C API ,供创建客户端库或添加新的底层中间件的开发人员使用,但不适合典型 ROS 用户使用。 ROS客户端库提供大多数 ROS 用户熟悉的面向用户的API,并且可能采用多种编程语言。 内部API架构概述 内部接口主要有两个&#x…

tcping的安装,ping和tcping的区别

ping和tcping的区别 功能不同: Ping:Ping是一种基于ICMP协议的网络工具,用于测试主机之间的连通性。它发送ICMP回显请求(Echo Request)到目标主机,并等待目标主机返回ICMP回显应答(Echo Reply…

架构师:搭建Spring Security、OAuth2和JWT 的安全认证框架

1、简述 Spring Security 是 Spring 生态系统中的一个强大的安全框架,用于实现身份验证和授权。结合 OAuth2 和 JWT 技术,可以构建一个安全可靠的认证体系,本文将介绍如何在 Spring Boot 中配置并使用这三种技术实现安全认证,并分析它们的优点。 2、Spring Security Spri…

Java 笔记 13:Java 数组内容,数组的声明、创建、初始化、赋值等,以及内存分析

一、前言 记录时间 [2024-05-03] 系列文章简摘: Java 笔记 01:Java 概述,MarkDown 常用语法整理 Java 笔记 02:Java 开发环境的搭建,IDEA / Notepad / JDK 安装及环境配置,编写第一个 Java 程序 Java 笔记 …

会声会影电影片头怎么做 会声会影电影质感调色技巧 会声会影视频制作教程 会声会影下载免费中文版

片头通常通过一系列的图像、音乐和文字等元素来引入电影的主题和氛围。通过视觉和音频的呈现方式,给观众留下深刻的第一印象,为电影的故事铺设基础。这篇文章来学习一下会声会影电影片头怎么做,会声会影电影质感调色技巧。 一、会声会影电影…