✅作者简介:CSDN内容合伙人、信息安全专业在校大学生🏆
🔥系列专栏 :信息安全本科生实验-Python
📃新人博主 :欢迎点赞收藏关注,会回访!
💬舞台再大,你不上台,永远是个观众。平台再好,你不参与,永远是局外人。能力再大,你不行动,只能看别人成功!没有人会关心你付出过多少努力,撑得累不累,摔得痛不痛,他们只会看你最后站在什么位置,然后羡慕或鄙夷。
(一)需求和规格说明
**问题描述:**贪吃蛇小游戏
编程任务:
- 图形化蛇
- 图形化食物
- 图形化地图
- 设计食物,速度,方格大小
(二)设计
1. 设计思想
本体主要采用库“pygame”,用列表表示食物的分值和颜色,用元组表示游戏区域坐标的范围,用Print_text(); 在界面相应的位置打印信息Init_snake(); 初始化蛇; Crate_food()随机创造食物 ;Get_food_style() 为食物赋值相应的分数和颜色Set_mode() 显示相应大小的界面;用第三方库pygame,设置GUI界面,openpyxl设置excel表格
2. 设计表示
- 用到的库:
import random
import sys
import time
import pygame
from pygame.locals import *
from collections import deque
import openpyxl
import time
-
数据:
| 数据类型 | 数据名称 | 描述 |
| — | — | — |
| 元组 |SCOPE_X/Y
| 游戏区域坐标范围 |
| 列表 |FOOD_STYLE_LIST
| 食物的分值和颜色 | -
函数:
| 函数名称 | 描述 |
| — | — |
|Print_text()
| 在界面相应的位置打印信息 |
|Init_snake()
| 初始化蛇 |
|Crate_food()
| 随机创造食物 |
|Get_food_style()
| 为食物赋值相应的分数和颜色 |
|Set_mode()
| 显示相应大小的界面 |
|Get_desktop()
| 获取桌面地址 |
|Save()
| 保存时间速度得分到excel表格 |
|Time.time()
| 获取当前时间戳 |
3. 核心算法
该程序的核心算法主要放在main()函数中。
开始游戏第一步是创造一个自定义好的地图和蛇,先用随机函数random.int()获取一个随机数i,然后crate_food()获取食物地位置,然后用get_food_style()获取食物的分数和颜色。
控制蛇的移动可以采用键盘读入的方式,蛇采用列表抽象表示,每次都要入队,出队,每次吃到食物时,就采用列表.append()入队,而不出队,从而增加蛇的长度方法表示。为了避免蛇在向右运动过程中,玩家按了左键,导致蛇直接致死,采用额外增加一个变量,按下按键时判断该变量的值和运动方向和键盘读入的方向,以此控制蛇的正常运行。每次吃到食物时,采用算法speed = orispeed – 0.03 * (score // 100)来显示新的速度。用第三方库openpyxl设置保存excel表格,
(三)用户手册
首先,在桌面任意位置创建一个excel表格,命名为“贪吃蛇”,然后打开该应用程序出现初始画面,然后按下键盘回车键运行该程序。通过“wasd”或者小键盘“上下左右”控制蛇的移动。通过控制蛇的移动来获取食物,获取食物后分数会增加,速度会增加,长度也会增加,从而增加了游戏难度。游戏过程中,不要让蛇的头部触碰到游戏外围的墙壁,这样子会导致蛇死亡,游戏结束。
(四)调试及测试
1、自定义游戏范围大小:
2、自定义游戏内食物颜色,蛇的颜色等:
3、游戏初始界面:
4、游戏过程画面:
5、游戏结束画面:
6、游戏记录的保存
(五) 感想
这道题并不难,但是算是首次完成一个综合题。我做这道题时是先把程序的功能拆分开来,比如创造食物,创造蛇,颜色,功能等,一个功能写一个小程序,最后组合起来。分开做时都比较顺利的,但是合起来就出现了很多小问题,比如参数传递出错,变量命名不统一等等。最开始写的时候也没有考虑时间复杂度和空间复杂度,只要能实现就好,写完之后才发现有些地方可以优化,原先我写的就很麻烦,而后经过算法优化才有些改进。我觉得解决这些问题都会对我以后的程序设计有帮助,所以应当多多实践做题。这也让我明白以后要尽量在写程序之前先考虑好用户会怎么使用这个程序,从使用者的角度出发。
附录:
源码:
import random
import sys
import time
import pygame
from pygame.locals import *
from collections import deque
import openpyxl
import time
SCREEN_WIDTH = 600 # 屏幕宽度
SCREEN_HEIGHT = 480 # 屏幕高度
SIZE = 20 # 小方格大小
LINE_WIDTH = 1 # 网格线宽度
# 游戏区域的坐标范围
SCOPE_X = (0, SCREEN_WIDTH // SIZE - 1)
SCOPE_Y = (2, SCREEN_HEIGHT // SIZE - 1)
# 食物的分值及颜色
FOOD_STYLE_LIST = [(10, (255, 100, 100)), (20, (100, 255, 100)), (30, (100, 100, 255))]
LIGHT = (100, 100, 100)
DARK = (200, 0, 0) # 蛇的颜色
BLACK = (0, 0, 0) # 网格线颜色
RED = (200, 30, 30) # 红色,GAME OVER 的字体颜色
BGCOLOR = (50, 50, 60) # 背景色
def get_desktop():
import winreg
#
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER,
r'Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders',)
return winreg.QueryValueEx(key, "Desktop")[0]
def print_text(screen, font, x, y, text, fcolor=(255, 255, 255)):
imgText = font.render(text, True, fcolor)
screen.blit(imgText, (x, y))
# 初始化蛇
def init_snake():
snake = deque()
snake.append((2, SCOPE_Y[0]))
snake.append((1, SCOPE_Y[0]))
snake.append((0, SCOPE_Y[0]))
return snake
def create_food(snake):
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])
return food_x, food_y
def get_food_style():
return FOOD_STYLE_LIST[random.randint(0, 2)]
def save(v,score):
print("save......")
path1=get_desktop()+"\贪吃蛇.xlsx"
workbook =openpyxl.load_workbook(path1)
table1 = workbook.worksheets[0]
table1.column_dimensions['A'].width = 18 #统一设置第一列宽度为
table1.cell(row=1,column=1).value = "时间"
table1.cell(row=1,column=2).value = "速度"
table1.cell(row=1,column=3).value = "得分"
rows=table1.max_row #读取行数
localtime = time.strftime('%Y-%m-%d',time.localtime(time.time()))
table1.cell(row=rows+1,column=1).value = localtime
table1.cell(row=rows+1,column=2).value = v
table1.cell(row=rows+1,column=3).value = score
workbook.save(path1) #保存文件
workbook.close()
def main():
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption('贪吃蛇')
font1 = pygame.font.SysFont('SimHei', 24) # 得分的字体
font2 = pygame.font.Font(None, 72) # GAME OVER 的字体
fwidth, fheight = font2.size('GAME OVER')
# 如果蛇正在向右移动,那么快速点击向下向左,由于程序刷新没那么快,向下事件会被向左覆盖掉,导致蛇后退,直接GAME OVER
# b 变量就是用于防止这种情况的发生
b = True
#以免多次保存出错
c = True
# 蛇
snake = init_snake()
# 食物
food = create_food(snake)
food_style = get_food_style()
# 方向
pos = (1, 0)
game_over = True
start = False # 是否开始,当start = True,game_over = True 时,才显示 GAME OVER
score = 0 # 得分
orispeed = 0.1 # 原始速度
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
snake = init_snake()
food = create_food(snake)
food_style = get_food_style()
pos = (1, 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[1]:
pos = (0, -1)
b = False
elif event.key in (K_s, K_DOWN):
if b and not pos[1]:
pos = (0, 1)
b = False
elif event.key in (K_a, K_LEFT):
if b and not pos[0]:
pos = (-1, 0)
b = False
elif event.key in (K_d, K_RIGHT):
if b and not pos[0]:
pos = (1, 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 not game_over:
curTime = time.time()
if curTime - last_move_time > speed:
if not pause:
b = True
last_move_time = curTime
next_s = (snake[0][0] + pos[0], snake[0][1] + pos[1])
if next_s == food:
# 吃到了食物
snake.appendleft(next_s)
score += food_style[0]
speed = orispeed - 0.03 * (score // 100)
food = create_food(snake)
food_style = get_food_style()
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, food_style[1], (food[0] * SIZE, food[1] * 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//10}')
print_text(screen, font1, 450, 7, f'得分: {score}')
if game_over:
if start:
print_text(screen, font2, (SCREEN_WIDTH - fwidth) // 2, (SCREEN_HEIGHT - fheight) // 2, 'GAME OVER', RED)
if c:
save(score//10,score)
c=False
pygame.display.update()
if __name__ == '__main__':
main()
文章出处登录后可见!