用pygame写一个简单的贪吃蛇

用pygame写一个简单的贪吃蛇

小时候就总想着自己能造一个游戏出来,然后给自己全套神装,吊打全服(狂笑)。虽然现在距离能写大型游戏还有亿点点距离,但学了pygame的我终于能写一些简单的游戏了。千里之行始于足下,话不多说,现在开始。(今天是学pygame的第三天,再加上完全是自己想的思路,水平肯定不高,也因为现在电脑性能够高就没考虑性能的问题。有别的问题欢迎在评论区指出来。)
在这里插入图片描述

1.构思

贪吃蛇这个游戏相信绝大多数人都玩过,注意观察的话会发现,只有蛇头和蛇尾在动,身体部分是不动的。由于pygame是不会自动填充背景的,也就是说,只需要让蛇头走过去,就会留下痕迹,再把蛇尾设置为背景色,在一段距离后跟着,中间的部分自然会形成蛇身。就像一个在前面洒水,一个在后面擦掉,留在中间的水不就像是动起来了吗?

2.编写小蛇

想好这条小蛇怎么实现了, 就可以敲代码了。我这里用的是像素当年诺基亚的感觉,屏幕共16*16个格,每个格是边长20像素,然后实例方格(蛇头、蛇尾、蛋)边长为18,每次前进20像素,每隔半秒刷新一次。喜欢连贯流畅的朋友可以设置每次前进1像素然后time.delay()里的参数调低。

from pygame import *

init()

size = 320, 320#屏幕大小
bg = 125, 125, 125#背景的RGB颜色

#进行初始化
screen = display.set_mode(size)
display.set_caption("贪吃蛇")

screen.fill(bg)
body = [[161, 161]]*2#身体的方格个数
speed = [-1, 0]#前进方向,初始向左
position = [161, 161]#初始蛇头位置(方格左上角的绝对坐标)

while True:
	#接收用户行为并处理
    for eve in event.get():#点击右上角的退出
        if eve.type == QUIT:
            exit()
        if eve.type == KEYDOWN:#从键盘输入
            if eve.key == 27:#esc
                exit()
            if not speed[0]:#这个if和下面那个是防止直接调头操作
                if eve.key == K_LEFT:
                    speed[0] = -1
                    speed[1] = 0
                if eve.key == K_RIGHT:
                    speed[0] = 1
                    speed[1] = 0
            if not speed[1]:
                if eve.key == K_UP:
                    speed[1] = -1
                    speed[0] = 0
                if eve.key == K_DOWN:
                    speed[1] = 1
                    speed[0] = 0

    for i in [0, 1]:
        position[i] += speed[i] * 20
    body = [position[:]] + body[:]#将蛇头的位置添加到身体里
#标记*
    draw.rect(screen, (0,0,0), tuple(position) + (18, 18), 0)
    draw.rect(screen, (bg), tuple(body[-1]) + (18, 18), 0)
    body.pop()

    display.flip()
    time.delay(500)#延时半秒

效果就是这样
在这里插入图片描述
但这时出现问题了:小蛇走出窗口就不见了,但按方向键抢救一下还能回来。原来pygame是支持在窗口外“活动”的,这时坐标为负或者大于窗口的值。我们希望小蛇从左边出就从右边进,所以需要改一下代码

    for p in [0, 1]:
        if position[p] < 0:
            position[p] = 320 + position[p]
        if position[p] > 320:
            position[p] = position[p] - 320

在上文标记*处插入这些代码就能将小蛇牢牢关在窗口里了。

2.创建个蛋(别问我为什么这么叫某度百科上说的)

这个没什么难理解的,import random生成个随机数安排上就行了。值得注意的是不要把蛋正好弄在蛇的身体上,不然会显示异常。

from random import randint
def create_egg():
    if len(body) == 195:
        pass#这里要写一个结束的函数,后面讲。
    while True:
        egg = [randint(0,15)*20+1, randint(0,15)*20+1]
        for b in body:
            if egg == b:
                break
        else:#如果for循环没有被打断(证明生成的坐标不在蛇身上)会
            break
    draw.rect(screen, (0,255,255), tuple(egg) + (18, 18), 0)#这里设置的蛋的颜色为蓝绿色
    return egg#返回蛋的坐标

在初始化和蛇头吃到蛋的时候创建新的蛋

score = 0
if position == egg:
        score += 1
        display.set_caption(f"贪吃蛇 分数:{score}")#因为没地方写分数了,直接写到标题栏里
        egg = create_egg()
        body += [body[-1]]#复制最后一节以达到延长蛇身的目的

3.让游戏可以结束

到目前为止,我们的游戏还不能结束,这也是游戏十分重要的一环。我用了一个函数把结束的代码封装起来,一个是用在蛇头与蛇身相碰的时候,另一个是在蛇已经布满全屏的时候(就是上面的pass)。

def over():
    draw.rect(screen, (255,0,0), tuple(position) + (18, 18), 0)#在结束的方块标红提示
    my_font = font.SysFont("microsoft Yahei", 30)#字体是微软雅黑
    textSurfaceObj = my_font.render("Game Over!", True, (255,255,255))
    screen.blit(textSurfaceObj, (100, 130))
    display.flip()
    while True:
        for eve in event.get():
            if eve.type == QUIT:
                exit()
        time.delay(30)

然后写一个碰撞检测

for b in body:
        if position == b:
            over()

就可以了
在这里插入图片描述
具体代码组织放在最后吧

4.润色一下

虽然在监听键盘操作的时候就加入了if判断防止小蛇做出直接调头的操作,但是用户仍然还可以快速按下两个方向键达到相同效果。比如小蛇正在向左前进,用户如果快速按下↑→就可以直接向右走。这显然是不合逻辑的,也会让游戏暴毙,影响体验。所以我设置了一个变量move_flag,判断键盘输入时写为if eve.type == KEYDOWN and move_flag:。当用户按下键盘的时候move_flag被设置为False锁定,当移动完刷新屏幕的时候设置为True释放,这个问题就解决了。

5.完整代码

from pygame import *
from random import randint

def create_egg():
    if len(body) == 195:
        over()
    while True:
        egg = [randint(0,15)*20+1, randint(0,15)*20+1]
        for b in body:
            if egg == b:
                break
        else:
            break
    draw.rect(screen, (0,255,255), tuple(egg) + (18, 18), 0)
    return egg

def over():
    draw.rect(screen, (255,0,0), tuple(position) + (18, 18), 0)
    my_font = font.SysFont("microsoft Yahei", 30)
    textSurfaceObj = my_font.render("Game Over!", True, (255,255,255))
    screen.blit(textSurfaceObj, (100, 130))
    display.flip()
    while True:
        for eve in event.get():
            if eve.type == QUIT:
                exit()
        time.delay(30)

init()

size = 320, 320
bg = 125, 125, 125

screen = display.set_mode(size)
display.set_caption("贪吃蛇")

screen.fill(bg)
body = [[161, 161]]*3
speed = [-1, 0]
position = [161, 161]
move_flag = True
egg = create_egg()
score = 0

while True:
    for eve in event.get():
        if eve.type == QUIT:
            exit()
        if eve.type == KEYDOWN and move_flag:
            move_flag = False
            if eve.key == 27:
                exit()
            if not speed[0]:
                if eve.key == K_LEFT:
                    speed[0] = -1
                    speed[1] = 0
                if eve.key == K_RIGHT:
                    speed[0] = 1
                    speed[1] = 0
            if not speed[1]:
                if eve.key == K_UP:
                    speed[1] = -1
                    speed[0] = 0
                if eve.key == K_DOWN:
                    speed[1] = 1
                    speed[0] = 0


    for i in [0, 1]:
        position[i] += speed[i] * 20

    for p in [0, 1]:
        if position[p] < 0:
            position[p] = 320 + position[p]
        if position[p] > 320:
            position[p] = position[p] - 320

    for b in body:
        if position == b:
            over()

    body = [position[:]] + body[:]

    if position == egg:
        score += 1
        display.set_caption(f"贪吃蛇 分数:{score}")
        egg = create_egg()
        body += [body[-1]]


    draw.rect(screen, (0,0,0), tuple(position) + (18, 18), 0)
    draw.rect(screen, (bg), tuple(body[-1]) + (18, 18), 0)
    body.pop()

    move_flag = True

    display.flip()
    time.delay(500)

6.拓展

目前我想到的有开始画面和暂停功能,日后可能会继续写完,也可能不写了,因为到这里已经实现贪吃蛇的基本功能,再写下去意义不大。
——————————————————分割线——————————————————
首先感谢你能看到这里吧。本人大学生一枚,非计算机相关专业。这是我第二篇博客,可能写得有点烂。以后我会继续写博客跟踪我的学习状态,同时跟大家分享一些我的学习心得。有问题欢迎下方留言!

发布了2 篇原创文章 · 获赞 4 · 访问量 1753

猜你喜欢

转载自blog.csdn.net/qq_45474427/article/details/105368011