首页 > 分享 > 【py】python

【py】python

python-经典贪吃蛇(pygame)

幽泉流霜关注

0.1942018.12.02 13:01:02字数 1,656阅读 1,375

自从开始学习编程后 ,就一直想着能够写一个自己的游戏,这大概是每一个男孩子的梦想吧!
这次我们使用python语言 ,调用pygame库 来写一个简单的小游戏
就拿最经典的游戏 贪吃蛇 作为我的第一个游戏!
看一下最终效果为

tanchishe.gif

我们先分一下步骤!

创建背景--写入蛇头食物--蛇的移动以及控制--蛇体算法--碰撞检测--食物随机生成--死亡判定--细节完善--源码

着急的小伙伴可以直接拉到最后看源码

先导入要用的库吧

import pygame

import random

from pygame.locals import *

第一个当然是必须要用到的pygame
随机生成食物点的时候要用到随机库
最后一个是导入pygame的上下左右键盘输入

一 、创建背景
这个是pygame的一个基本用法
我们先拿一个简单的例子来说

pygame.init()

window = pygame.display.set_mode((640,480),0,32)

pygame.display.set_caption("标题")

pygame.init()用语pygame的初始化
set_mode函数会返回一个Surface对象,代表了在桌面上出现的那个窗口,三个参数第一个为元祖,代表分 辨率(必须);第二个是一个标志位,具体意思见下表,如果不用什么特性,就指定0;第三个为色深。
set_caption顾名思义是用来设置标题的
这时候我们运行程序就会出现一个一闪而过的黑框
它就是我们的游戏窗体啦

那么如果要让黑框一直存在怎么办呢
肯定要用到一个while 循环

while True:

pygame.draw.rect(window,bk_color,(0,0,w,h))

pygame.display.update()

这样子我们的黑框就会一直存在
draw.rect是pygame带的一个画矩形的函数它一共有四个参数
第一个是对象 就是你要画的位置
第二个是颜色 矩形的色彩
第三个 是一个tuple 代表矩形的位置和大小
tuple里面一共四个参数 前面两个代表矩形的左上角坐标,后两个分别是宽和高

但是现在问题又来我们会发现 无法关闭掉这个窗口 或者说卡主

我们可以先定义一个

quit = True

while quit:

for event in pygame.event.get():

if event.type == pygame.QUIT:

quit = False

这里我们引入了pygame的事件概念
pygame.event.gey()可以获取目前的所有事件

import pygame

from pygame.locals import *

from sys import exit

pygame.init()

SCREEN_SIZE = (640, 480)

screen = pygame.display.set_mode(SCREEN_SIZE, 0, 32)

font = pygame.font.SysFont("arial", 16);

font_height = font.get_linesize()

event_text = []

while True:

event = pygame.event.wait()

event_text.append(str(event))

#获得时间的名称

event_text = event_text[-SCREEN_SIZE[1]//font_height:]

#这个切片操作保证了event_text里面只保留一个屏幕的文字

if event.type == QUIT:

exit()

screen.fill((255, 255, 255))

y = SCREEN_SIZE[1]-font_height

#找一个合适的起笔位置,最下面开始但是要留一行的空

for text in reversed(event_text):

screen.blit( font.render(text, True, (0, 0, 0)), (0, y) )

#以后会讲

y-=font_height

#把笔提一行

pygame.display.update()

运行以上代码 就可以看到我们的所有事件了
通过上面的说明我们已经可以让一个黑框完整的出现了!

为了方便
我们可以把贪吃蛇的背景看成一个表格
我们先定义了一个600*800的一个分辨率
然后分别设置行数和列数
代码如下

w = 800

h = 600

ROW = 30

COL = 40

size = (w, h)

direct = "left" #我们下面会讲

window = pygame.display.set_mode(size)

pygame.display.set_caption("贪吃蛇")

二、写入蛇头、食物
为了方便坐标的表示
我们写一个简单的坐标类

class Point:

row = 0

col = 0

def __init__(self,row,col):

self.row = row

self.col = col

我们要画一个蛇头 当然要用到draw.rect的函数
于是需要一个蛇头的颜色和坐标
食物也同样如此

head = Point(ROW / 2,COL / 2)

food = Point(10,10)

head_color = (0, 128, 128)

food_color = (255, 255, 0)

然后再在循环中用rect函数把我们的蛇头和食物画上
运行后效果如图所示

Snipaste_2018-12-01_19-17-04.png

三、蛇的移动以及控制
如何让蛇自动前进
这里我们先引入一个时间的概念

clock =pygame.time.Clock()

clock.tick(20)

当我们把这个clock.tick(20)加入到游戏的主循环后
就代表的画面每秒刷新20次 也就是20帧的意思
我们通过这个刷新次数来控制蛇的移动速度
当然 这是一个比较low的控制方法..
因为他并不稳定 和你的电脑配置是有关系的

那么如何让蛇来自动移动呢
方法很简单
那就是每次刷新的时候
如果方向向左那么让它的列数-1
同理其他方向

if direct == "left":

head.col -= 1

if direct == "down":

head.row += 1

if direct == "up":

head.row -= 1

if direct == "right":

head.col += 1

那改变蛇头方向怎么做呢
当我们按下键盘的时候 pygame会检测到这个事件
用if来判断不同的事件 同时控制direct的方向

if event.type == pygame.KEYDOWN:

print(event)

if event.key == K_LEFT:

direct = "left"

elif event.key == K_RIGHT:

direct = "right"

elif event.key == K_UP:

direct = "up"

elif event.key == K_DOWN:

direct = "down"

四、蛇体算法
我们先假设蛇头和蛇身体的坐标为:
head=(14,7)
l=[
(14,8)
(14,9)
(15,9)
(15,10)
(15,11)
(15,12)
(16,12)
(17,12)
]

移动:
1.把原来的头插到前面
2.把原来的尾删掉

head'=(14,6)
l'=[
(14,7) <-原来的头

(14,8)

(14,9)

(15,9)

(15,10)

(15,11)

(15,12)

(16,12)

del (17,12) <-原来的尾

]
所以本质上说一共就两步
1 把蛇头插入到身体的第一个位置
2 删除尾巴

还有一个问题 因为我们需要保存原先的蛇头位置
因为需要再在类中定义一个 copy

class Point:

row = 0

col = 0

def __init__(self,row,col):

self.row = row

self.col = col

def copy(self):

return Point(self.row, self.col)

snakes =[Point(head.row,head.col+1),

Point(head.row, head.col+2),

Point(head.row, head.col+3)]

#在循环上方定义一个身体 snake

snakes.insert(0,head.copy()) #插入旧蛇头

snakes.pop() #删除蛇尾

到这一步我们就可以简单的控制小蛇移动啦

五、碰撞检测
嘛。。听起来很高级的一个名词
但是我们这里并不需要很复杂的算法
只要检测蛇头的位置和食物的位置是否一样
如果一样
小蛇身体变长且食物新生成
所以还是很简单的

eat =(head.row == food.row and head.col == food.col)

snakes.insert(0,head.copy())

if eat:

food = food_exist() #食物生成

else:

snakes.pop()

六、食物随机生成
这一步肯定要用到random库拉

food = Point(random.randint(0,ROW-1),random.randint(0, COL-1))

这一句话就搞定了

七、死亡判定
死亡时无非是两种情况
1吃到墙了
2吃到自己
那么我们只要判断蛇头的位置死亡位置就好了

dead = False

if (head.row < 0 or head.col< 0 or head.row>ROW or head.col >COL):

print("你死了")

dead = True

for snake in snakes:

if(head.row == snake.row and head.col == snake.col):

print("你死了")

dead = True

if dead ==True:

break

在主循环中加入这段代码即可
先给予dead ==False 假设它一直不死
一旦玩家触发死亡 dead变为True 并且输出了一个 你死了
退出循环

到这里我们的贪吃蛇已经初步完成了 但是还有一些小小的细节需要优化

八、细节优化
1.我们的贪吃蛇是可以直接由左边转向右边 由上面转向下面 ,这显然是非常不科学的。
2.食物随机生成位置可能出现在蛇的身体或者头部上
先对第一点解决
为了避免这个问题 我们可以在转向前进行判定 只有在上下方向感才可以进行左右转
左右转的时候同理

if event.key == K_LEFT:

if (direct == "up" or direct == "down"):

direct = "left"

elif event.key == K_RIGHT:

if (direct == "up" or direct == "down"):

direct = "right"

elif event.key == K_UP:

if (direct == "right" or direct == "left"):

direct = "up"

elif event.key == K_DOWN:

if (direct == "right" or direct == "left"):

direct = "down"

第二点
也就是需要在生成食物前
进行判定食物的位置和蛇头位置,蛇身体位置
如果重复,就重新生成

def food_exist():

is_in =False

while True:

pos = Point(random.randint(0,ROW-1),random.randint(0, COL-1))

if (pos.row ==head.row and pos.col == head.col):

is_in =True

for snake in snakes:

if(pos.row == snake.row and pos.col == snake.col):

is_in = True

if is_in == False:

break

return pos

和死亡判定差不多
先定义一个is_in =False假设不会生成到蛇头和蛇身体位置
一旦 ...就重新生成
好了 到这里 我们简陋的贪吃蛇就全部完成了

九、源码

import pygame

import random

from pygame.locals import *

class Point:

row = 0

col = 0

def __init__(self,row,col):

self.row = row

self.col = col

def copy(self):

return Point(self.row, self.col)

pygame.init()

w = 800

h = 600

ROW = 30

COL = 40

size = (w, h)

direct = "left"

window = pygame.display.set_mode(size)

pygame.display.set_caption("贪吃蛇")

def rect(point, color):

w_cell = w/COL

h_cell = h/ROW

left = point.col*w_cell

top = point.row*h_cell

pygame.draw.rect(window,color,(left,top,w_cell,h_cell))

def food_exist():

is_in =False

while True:

pos = Point(random.randint(0,ROW-1),random.randint(0, COL-1))

if (pos.row ==head.row and pos.col == head.col):

is_in =True

for snake in snakes:

if(pos.row == snake.row and pos.col == snake.col):

is_in = True

if is_in == False:

break

return pos

quit = True

clock =pygame.time.Clock()

head = Point(ROW / 2,COL / 2)

snakes =[Point(head.row,head.col+1),

Point(head.row, head.col+2),

Point(head.row, head.col+3)]

food = food_exist()

head_color = (0, 128, 128)

food_color = (255, 255, 0)

bk_color = (255, 255, 255)

snake_color = (200,200,200)

while quit:

for event in pygame.event.get():

if event.type == pygame.QUIT:

quit = False

elif event.type == pygame.KEYDOWN:

print(event)

if event.key == K_LEFT:

if (direct == "up" or direct == "down"):

direct = "left"

elif event.key == K_RIGHT:

if (direct == "up" or direct == "down"):

direct = "right"

elif event.key == K_UP:

if (direct == "right" or direct == "left"):

direct = "up"

elif event.key == K_DOWN:

if (direct == "right" or direct == "left"):

direct = "down"

dead = False

if (head.row < 0 or head.col< 0 or head.row>ROW or head.col >COL):

print("你死了")

dead = True

for snake in snakes:

if(head.row == snake.row and head.col == snake.col):

print("你死了")

dead = True

if dead ==True:

break

eat =(head.row == food.row and head.col == food.col)

snakes.insert(0,head.copy())

if eat:

food = food_exist()

else:

snakes.pop()

if direct == "left":

head.col -= 1

if direct == "down":

head.row += 1

if direct == "up":

head.row -= 1

if direct == "right":

head.col += 1

pygame.draw.rect(window,bk_color,(0,0,w,h))

rect(head,head_color)

rect(food,food_color)

#生成蛇身体

for snake in snakes:

rect(snake,snake_color)

pygame.display.update()

clock.tick(20)

感谢大家的阅读。
第一次写游戏
也参考了网上的一些教程
有问题欢迎大家讨论纠正

相关知识

py人类与宠物模拟世界
通过python
基于python
Python笔试题
python通过cython编译成可执行文件方式
编写宠物dog类python
Python之函数
深度学习宠物行为识别代码教程
099基于深度学习的动物声音分类
CNN鸟类图片识别教程:从数据集到模型训练

网址: 【py】python https://m.mcbbbk.com/newsview657249.html

所属分类:萌宠日常
上一篇: 今日可以扫舍吗 2024年8月2
下一篇: 使用python pygame库