贪吃蛇小游戏Python Pygame实现

运行结果

 

游戏规则

1. ↑ ↓ ← → 来控制蛇的移动方向

2. 蛇吃到自己身体的任意一部分游戏结束, 自动退出窗口

3. 蛇的速度会随游戏时间增长越来越快, 与吃食物的多少 (分数) 无关

4. 蛇可以穿过边界到达另一边

5. 场上食物同时只会存在一个, 颜色随机, 但每个颜色的所得分数不同, 生存概率也不同

 

实现思路

此段介绍代码逻辑, 比较简单, 可以直接跳过, 最后有全部代码

 

1. 棋盘实现

棋盘采用最简单的方法来实现, 即一个grid[][]二元列表来表示棋盘, 下标表示棋盘的位置

例如: grid[5][4]表示第5行第4列的一格

  1) None表示该一格为空, 即蛇可以安全通过

  2) 颜色例如(0, 0, 0)为该一格有食物

  3) True表示该一格是蛇的身体

 

SIZE = 30
SIDE = HEIGHT // SIZE
grid = [[None for _ in range(SIDE)] for _ in range(SIDE)]

 

 

2. 蛇的实现

用双端队列表示蛇, 这样尾部和头部的更新时间复杂度都为O(1).

蛇初始长度为3, 方向向右

1). 蛇的动态实现

  根据蛇的前进速度, 每前进一格, 若没有吃到食物, 则删除尾部一格, 添加头部一格, 并更新棋盘的值; 若吃到食物, 则头部添加一格, 尾部不会删除, 即实现了蛇的长度增加一格

2). 蛇的方向改变

  在按上下左右来改变蛇的方向时, 为了防止蛇反向移动吃掉自己, 需要获取蛇此时的移动方向

  例如: 蛇此时往右移动, 那么按"左"时蛇的移动方向不会发生改变, 否则会立即吃到自己结束游戏

  若成功改变移动方向, 则根据DIR变量来改变移动方向

复制代码
snake = collections.deque()  # 蛇的实现
DIR = ((-1, 0), (1, 0), (0, -1), (0, 1))  # 上下左右
dir = DIR[3]  # 初始方向右
speed = 0.12

# 蛇初始有三格
snake.append((0, 0))
snake.append((0, 1))
snake.append((0, 2))
grid[0][0], grid[0][1], grid[0][2] = True, True, True
.
.
.
# 蛇的速度随时间非线性增长
if game_t >= 10 * up:
    speed /= 1.2
    up += 1

s -= F
if s <= 0:  # 移动一次
    x, y = snake[-1][0] + dir[0], snake[-1][1] + dir[1]  # 下一步的坐标
    x, y = x % SIDE, y % SIDE  # 过墙穿到另一边
    if grid[x][y] == True:  # 吃到自己, 游戏结束
        pygame.quit()
        exit()
    elif grid[x][y]:  # 吃到食物, 加分, 重新生成食物
        score += SCORE[grid[x][y]]
        create_food()  # 重新生成
    else:  # 无事发生, 前进一格
        xp, yp = snake.popleft()
        grid[xp][yp] = None
    snake.append((x, y))
    grid[x][y] = True
    s = speed

for e in pygame.event.get():
    if e.type == QUIT:
        pygame.quit()
        exit()
    if e.type == KEYDOWN:
        if e.key == K_UP and dir != DIR[1]:
            dir = DIR[0]
        elif e.key == K_DOWN and dir != DIR[0]:
            dir = DIR[1]
        elif e.key == K_LEFT and dir != DIR[3]:
            dir = DIR[2]
        elif e.key == K_RIGHT and dir != DIR[2]:
            dir = DIR[3]
复制代码

 

3. 食物生成

食物采用随机生成在棋盘任意位置的方式, 但不能直接生成在蛇的身上.

这里为了避免食物一直生成在蛇身上, 然后导致程序卡在一个循环里, 我们设置最大循环次数为100, 若100次循环后还没找到位置生成食物, 就会遍历棋盘直接寻找空位, 没有空位则不生成食物 (你的蛇铺满了整个棋盘, 好耶)

  食物得分: 绿色:2分, 蓝色: 3分, 白色: 1分

  食物生成概率: 绿色25%, 蓝色 12.5%, 白色62.5%

复制代码
SCORE = {GREEN: 2, LIGHTBLUE: 3, WHITE: 1}
RCOL = (GREEN, GREEN, LIGHTBLUE, WHITE, WHITE, WHITE, WHITE, WHITE)
score = 0  # 得分

# 生成食物
def create_food():
    i, j = random.randint(0, SIDE-1), random.randint(0, SIDE-1)
    c = 0  # 重置次数
    while grid[i][j] and c <= 100:
        i, j = random.randint(0, SIDE-1), random.randint(0, SIDE-1)
        c += 1
    if c <= 100:
        grid[i][j] = (random.choice(RCOL))
        return
    for i in range(SIDE):
        for j in range(SIDE):
            if not grid[i][j]:
                grid[i][j] = (random.choice(RCOL))
                return

.
.
.
create_food()
复制代码

 

全部代码:

复制代码
# 游戏规则: ↑ ↓ ← →控制蛇的移动方向
# 可以穿过边界
# 蛇的速度每10s增长一次, 不随分数增长


import pygame, random, collections
from pygame.locals import *

pygame.init()
WIDTH, HEIGHT = 750, 600
sur = pygame.display.set_mode((WIDTH, HEIGHT))
FPS = 200
fpsClock = pygame.time.Clock()


# 颜色变量
WHITE =  (255, 255, 255)
RED  =   (255, 0, 0)
GREEN =  (0, 255, 0)
BLUE  =  (0, 0, 255)
BLACK =  (0, 0, 0)
YELLOW = (255, 255, 0)
SILVER = (192, 192, 192)
GRAY =   (169, 169, 169)
PURPLE = (127, 0, 255)
PINK =   (255, 51, 153)
ORANGE = (255, 128, 0)
BROWN =  (102, 51, 0)
LIGHTBLUE = (137, 207, 240)
WOOD = (222, 184, 135)


# 游戏变量
SIZE = 30
SIDE = HEIGHT // SIZE
snake = collections.deque()
grid = [[None for _ in range(SIDE)] for _ in range(SIDE)]
DIR = ((-1, 0), (1, 0), (0, -1), (0, 1))  # 上下左右
dir = DIR[3]  # 初始方向右
SCORE = {GREEN: 2, LIGHTBLUE: 3, WHITE: 1}
RCOL = (GREEN, GREEN, LIGHTBLUE, WHITE, WHITE, WHITE, WHITE, WHITE)
score = 0  # 得分
speed = 0.12



# 写入文本
def write(x, y, text, color, size):
    font = pygame.font.SysFont('SimHei', size)
    Text = font.render(text, True, color)
    sur.blit(Text, (x, y))


# 生成食物
def create_food():
    i, j = random.randint(0, SIDE-1), random.randint(0, SIDE-1)
    c = 0  # 重置次数
    while grid[i][j] and c <= 100:
        i, j = random.randint(0, SIDE-1), random.randint(0, SIDE-1)
        c += 1
    if c <= 100:
        grid[i][j] = (random.choice(RCOL))
        return
    for i in range(SIDE):
        for j in range(SIDE):
            if not grid[i][j]:
                grid[i][j] = (random.choice(RCOL))
                return


def main():
    global speed, dir, score
    # 蛇初始有三格
    snake.append((0, 0))
    snake.append((0, 1))
    snake.append((0, 2))
    grid[0][0], grid[0][1], grid[0][2] = True, True, True
    create_food()
    F = 1/FPS
    game_t = 0
    s = speed
    up = 0
    while True:
        sur.fill(BLACK)
        sur.fill(GRAY, (WIDTH-150, 0, 200, HEIGHT))
        game_t += F

        # 右侧信息栏
        write(620, 80, '时间:'+str(int(game_t)), BLACK, 25)
        write(620, 20, '分数:'+str(score), BLACK, 25)
        write(620, 140, '速度:'+str(int(1/speed)), BLACK, 25)

        # 画蛇和食物
        for i in range(SIDE):
            for j in range(SIDE):
                if grid[i][j] == True:
                    pygame.draw.rect(sur, PINK, (j*SIZE, i*SIZE, SIZE, SIZE))
                elif grid[i][j]:
                    pygame.draw.rect(sur, grid[i][j], (j*SIZE, i*SIZE, SIZE, SIZE))

        # 画棋盘的线
        for i in range(0, WIDTH-149, SIZE):
            pygame.draw.line(sur, BLUE, (i, 0), (i, HEIGHT), 1)
        for j in range(0, HEIGHT+1, SIZE):
            pygame.draw.line(sur, BLUE, (0, j), (WIDTH-150, j), 1)

        # 蛇的速度随时间非线性增长
        if game_t >= 10*up:
            speed /= 1.2
            up += 1

        s -= F
        if s <= 0:  # 移动一次
            x, y = snake[-1][0]+dir[0], snake[-1][1]+dir[1]  # 下一步的坐标
            x, y = x % SIDE, y % SIDE  # 过墙穿到另一边
            if grid[x][y] == True:  # 吃到自己, 游戏结束
                pygame.quit()
                exit()
            elif grid[x][y]:  # 吃到食物, 加分, 重新生成食物
                score += SCORE[grid[x][y]]
                create_food()  # 重新生成
            else:  # 无事发生, 前进一格
                xp, yp = snake.popleft()
                grid[xp][yp] = None
            snake.append((x, y))
            grid[x][y] = True
            s = speed


        for e in pygame.event.get():
            if e.type == QUIT:
                pygame.quit()
                exit()
            if e.type == KEYDOWN:
                if e.key == K_UP and dir != DIR[1]:
                    dir = DIR[0]
                elif e.key == K_DOWN and dir != DIR[0]:
                    dir = DIR[1]
                elif e.key == K_LEFT and dir != DIR[3]:
                    dir = DIR[2]
                elif e.key == K_RIGHT and dir != DIR[2]:
                    dir = DIR[3]


        pygame.display.update()
        fpsClock.tick(FPS)


main()
复制代码

 

最后

请勿用于商业用途, 若有问题或bug, 感谢各位大佬及时指出!

posted @   典明粥  阅读(74)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示