前言
开始
献上代码
from tkinter.messagebox import showinfo as msg
from random import randint as rand
from pygame.locals import *
import tkinter as tk
import pygame
import time
win = tk.Tk()
win.withdraw()
pygame.init()
def render(surf,blocks):
for x,y in blocks.keys():
renderingf = (x * 40,y * 40)
color = blocks[(x,y)]
pygame.draw.rect(surf,color,Rect(renderingf,(40,40)))
def render_snake(surf,pos):
def unique(pos):
for i in pos:
if(pos.count(i) > 1):
return False
return True
if(not unique(pos)):
return False
d = {
}
for i in pos:
d[tuple(i)] = (255,255,255)
d[pos[-1]] = (0,0,255)
render(surf,d)
return True
def main(size):
scr = pygame.display.set_mode((40 * size[0],40 * size[1]))
stop = False
l = 3
pos = [(0,0),(1,0),(2,0)]
last = 'd'
dir = {
'w':(0,-1),'s':(0,1),'a':(-1,0),'d':(1,0)}
oppsite = {
'w':'s','s':'w','a':'d','d':'a'}
food = (rand(0,size[0] - 1),rand(0,size[1] - 1))
n = 1
speed = 30
while(1):
if((food in pos) and (not stop)):
l += 1
food = (rand(0,size[0] - 1),rand(0,size[1] - 1))
if(l == size[0] * size[1]):
return l
if(pos[-1][0] < 0 or pos[-1][1] < 0 or pos[-1][0] >= size[0] or pos[-1][1] >= size[1]):
return l
pygame.display.update()
speed = 30 - int(l / (1 - 3 / (size[0] * size[1])))
n += 1
n %= speed
pos = pos[-l:]
if((not n) and (not stop)):
t = (pos[-1][0] + dir[last][0],pos[-1][1] + dir[last][1])
pos.append(t)
scr.fill((0,0,0))
for ev in pygame.event.get():
if(ev.type == QUIT):
exit()
elif(ev.type == KEYDOWN and ev.unicode in 'aAwWsSdD' and ev.unicode):
if(ev.unicode == oppsite[last]):
return l
t = (pos[-1][0] + dir[ev.unicode.lower()][0],
pos[-1][1] + dir[ev.unicode.lower()][1])
pos.append(t)
last = str(ev.unicode.lower())
elif(ev.type == MOUSEBUTTONDOWN):
stop = not stop
elif(ev.type == KEYDOWN and ev.key == K_ESCAPE and stop):
return l
if(stop):
img = pygame.image.load('pause.jpg')
img = pygame.transform.scale(img,(40 * size[0],40 * size[1]))
scr.blit(img,(0,0))
else:
render(scr,{
food:(0,255,0)})
if(not render_snake(scr,pos)):
return l
if(__name__ == '__main__'):
size = [15,15]
while(1):
l = main(size)
msg("GAMEOVER!","GAMEOVER! score:%s"%l)
代码剖析
from tkinter.messagebox import showinfo as msg
from random import randint as rand
from pygame.locals import *
import tkinter as tk
import pygame
import time
win = tk.Tk()
win.withdraw()
pygame.init()
导入库并初始化
注意⚠️:tkinter一定要在pygame之前初始化
def render(surf,blocks):
for x,y in blocks.keys():
renderingf = (x * 40,y * 40)
color = blocks[(x,y)]
pygame.draw.rect(surf,color,Rect(renderingf,(40,40)))
渲染格子,surf
是要渲染的Surface
对象,blocks
是要渲染的位置和颜色
def render_snake(surf,pos):
def unique(pos):
for i in pos:
if(pos.count(i) > 1):
return False
return True
if(not unique(pos)):
return False
d = {
}
for i in pos:
d[tuple(i)] = (255,255,255)
d[pos[-1]] = (0,0,255)
render(surf,d)
return True
渲染蛇,即为render
(点击跳转)的包装。surf
为要渲染的Surface
对象,pos
是蛇身子的每个格子的坐标列表。其中unique
为蛇是否碰到自己的检测,其思路是,如果pos
中有重复的,蛇就否碰到自己,所以,unique
就是检测数组中是否有重复数据的
def main(size):
scr = pygame.display.set_mode((40 * size[0],40 * size[1]))
stop = False
l = 3
pos = [(0,0),(1,0),(2,0)]
last = 'd'
dir = {
'w':(0,-1),'s':(0,1),'a':(-1,0),'d':(1,0)}
oppsite = {
'w':'s','s':'w','a':'d','d':'a'}
food = (rand(0,size[0] - 1),rand(0,size[1] - 1))
n = 1
speed = 30
while(1):
if((food in pos) and (not stop)):
l += 1
food = (rand(0,size[0] - 1),rand(0,size[1] - 1))
if(l == size[0] * size[1]):
return l
if(pos[-1][0] < 0 or pos[-1][1] < 0 or pos[-1][0] >= size[0] or pos[-1][1] >= size[1]):
return l
pygame.display.update()
speed = 30 - int(l / (1 - 3 / (size[0] * size[1])))
n += 1
n %= speed
pos = pos[-l:]
if((not n) and (not stop)):
t = (pos[-1][0] + dir[last][0],pos[-1][1] + dir[last][1])
pos.append(t)
scr.fill((0,0,0))
for ev in pygame.event.get():
if(ev.type == QUIT):
exit()
elif(ev.type == KEYDOWN and ev.unicode in 'aAwWsSdD' and ev.unicode):
if(ev.unicode == oppsite[last]):
return l
t = (pos[-1][0] + dir[ev.unicode.lower()][0],
pos[-1][1] + dir[ev.unicode.lower()][1])
pos.append(t)
last = str(ev.unicode.lower())
elif(ev.type == MOUSEBUTTONDOWN):
stop = not stop
elif(ev.type == KEYDOWN and ev.key == K_ESCAPE and stop):
return l
if(stop):
img = pygame.image.load('pause.jpg')
img = pygame.transform.scale(img,(40 * size[0],40 * size[1]))
scr.blit(img,(0,0))
else:
render(scr,{
food:(0,255,0)})
if(not render_snake(scr,pos)):
return l
这里分开分析
def main(size):
scr = pygame.display.set_mode((40 * size[0],40 * size[1]))
stop = False
l = 3
pos = [(0,0),(1,0),(2,0)]
last = 'd'
dir = {
'w':(0,-1),'s':(0,1),'a':(-1,0),'d':(1,0)}
oppsite = {
'w':'s','s':'w','a':'d','d':'a'}
food = (rand(0,size[0] - 1),rand(0,size[1] - 1))
n = 1
speed = 30
创建窗口,初始化是否暂停,蛇长,身体个块坐标,最后一个操作,方向与偏移量的关系字典,相反动作字典,食物位置,轮回数,速度(住:这里speed
越大,速度越慢,请记住这件事情,后面会用到)
while(1):
if((food in pos) and (not stop)):
l += 1
food = (rand(0,size[0] - 1),rand(0,size[1] - 1))
if(l == size[0] * size[1]):
return l
if(pos[-1][0] < 0 or pos[-1][1] < 0 or pos[-1][0] >= size[0] or pos[-1][1] >= size[1]):
return l
进入游戏循环,处理吃到食物,蛇占满格子的问题
pygame.display.update()
speed = 30 - int(l / (1 - 3 / (size[0] * size[1])))
n += 1
n %= speed
pos = pos[-l:]
if((not n) and (not stop)):
t = (pos[-1][0] + dir[last][0],pos[-1][1] + dir[last][1])
pos.append(t)
scr.fill((0,0,0))
刷新窗口,清屏,这里中间的代码的作用向 ↓ \downarrow ↓看
speed = 30 - int(l / (1 - 3 / (size[0] * size[1]))) n += 1 n %= speed pos = pos[-l:] if((not n) and (not stop)): t = (pos[-1][0] + dir[last][0],pos[-1][1] + dir[last][1]) pos.append(t) scr.fill((0,0,0))
第一行更新速度,这里公式是由 速 度 = 蛇 长 ÷ [ ( 最 长 长 度 − 初 始 长 度 ) ÷ 最 长 长 度 ] 速度=蛇长 \div [(最长长度 - 初始长度) \div 最长长度] 速度=蛇长÷[(最长长度−初始长度)÷最长长度],将 ( 最 长 长 度 − 初 始 长 度 ) ÷ 最 长 长 度 (最长长度 - 初始长度) \div 最长长度 (最长长度−初始长度)÷最长长度改成 最 长 长 度 ÷ 最 长 长 度 − 初 始 长 度 ÷ 最 长 长 度 最长长度 \div 最长长度 - 初始长度 \div 最长长度 最长长度÷最长长度−初始长度÷最长长度也就是 1 − 3 / ( s i z e [ 0 ] ∗ s i z e [ 1 ] ) 1 - 3 / (size[0] * size[1]) 1−3/(size[0]∗size[1]),整理一下,变成 s p e e d = l ÷ [ 1 − 3 / ( s i z e [ 0 ] ∗ s i z e [ 1 ] ) ] speed=l \div [1 - 3 / (size[0] * size[1])] speed=l÷[1−3/(size[0]∗size[1])],由于速度是整数,所以去一下整。
再往后就要解释一下为什么speed
越大,速度越快了,因为speed
指的就是经过speed
个轮回之后蛇就自动挪一下,那么换句话说,speed
越大,不挪的轮回数就越多,挪动的时间间隔就越长
所以每次 n = n + 1 n = n + 1 n=n+1就指的是又轮回了一次(因为 n n n这的就是轮回数),如果 n = s p e e d n = speed n=speed了,那么 n % s p e e d n~\%~speed n % speed就等于0,于是每次经过 n = ( n + 1 ) % s p e e d n = (n + 1)~\%~speed n=(n+1) % speed之后如果 n = 0 n = 0 n=0,就代表改挪一下了。
for ev in pygame.event.get():
if(ev.type == QUIT):
exit()
elif(ev.type == KEYDOWN and ev.unicode in 'aAwWsSdD' and ev.unicode):
if(ev.unicode == oppsite[last]):
return l
t = (pos[-1][0] + dir[ev.unicode.lower()][0],
pos[-1][1] + dir[ev.unicode.lower()][1])
pos.append(t)
last = str(ev.unicode.lower())
elif(ev.type == MOUSEBUTTONDOWN):
stop = not stop
elif(ev.type == KEYDOWN and ev.key == K_ESCAPE and stop):
return l
处理事件
- 点
x
就退出 - 点
awsd
就按照方向移动 - 点击鼠标暂停或继续
- 暂停时点
ESC
就再来一局
if(stop):
img = pygame.image.load('pause.jpg')
img = pygame.transform.scale(img,(40 * size[0],40 * size[1]))
scr.blit(img,(0,0))
else:
render(scr,{
food:(0,255,0)})
if(not render_snake(scr,pos)):
return l
如果是没有在玩(暂停),那么将图片与窗口调成同样大小后显示,显示的图片向 ↓ \downarrow ↓看
不难看出就是暂停继续的图案
如果在玩(没暂停),那么调用render_snake
(点击跳转)渲染蛇,如果返回False
,也就是撞自己上了,游戏结束。
if(__name__ == '__main__'):
size = [15,15]
while(1):
l = main(size)
msg("GAMEOVER!","GAMEOVER! score:%s"%l)
运行游戏,size
中的两个值表明区域大小,可自行更改(推荐 ≤ 15 \le15 ≤15)。
项目github
作者
hit-road
拜拜,下课!
回到顶部