简单脚本分享--贪吃蛇

使用pygame实现的贪吃蛇,有BUG或意见欢迎留言

# 导入所需的模块
import sys
import pygame
import random

"""
方框大小 默认9; 空间管理 默认10;实际上只有1px的间隙
BUG思考:1.当用户按了太多无用按钮,会导致事件处理延后
"""
# 默认方框大小
unitLength = 15
rectWidth = 14
# 默认方框颜色
rectColor = pygame.Color("blue")
bgColor = pygame.Color("white")
startColor = pygame.Color("black")
# 默认窗口大小
windowWidth = 600
windowHeight = 600
# 默认size
sizeX = windowWidth // unitLength
sizeY = windowHeight // unitLength
# 默认最大空余list
maxSpare = 200
# 默认空白空间
spareWidth = 10
# 默认起始位置
startPos = spareWidth // 2

# 点对象  实现点之间的运算
class Point:
    def __init__(self, x=0, y=0):
        self.X = x
        self.Y = y

    # 加法方法
    def __add__(self, other):
        x = self.X + other.X
        y = self.Y + other.Y
        return Point(x, y)

    #  减法方法
    def __sub__(self, other):
        x = self.X - other.X
        y = self.Y - other.Y
        return Point(x, y)

    #  转字符串方法
    def __str__(self):
        return "(%d,%d)" % (self.X, self.Y)

    #  相等方法
    def __eq__(self, other):
        return self.X == other.X and self.Y == other.Y

    #  绝对值方法
    def __abs__(self):
        return Point(abs(self.X), abs(self.Y))

    #  获取坐标
    def get_coordinate(self):
        return self.X * unitLength, self.Y * unitLength

    #   测试是否超出窗口
    def is_out_of_window(self):
        return not (0 <= self.X < sizeX and 0 <= self.Y < sizeY)


# 用list实现队列,为方便扩容,把list前部当队列尾部
class Queue:
    def __init__(self):
        self.list = [Point()]
        self.start = 0

    #  向头部添加数据
    def push_front(self, data):
        self.list.append(data)

    #  获取头部数据
    def get_top(self):
        return self.list[len(self.list) - 1]

    #  输出尾部数据
    def pop_back(self):
        #  如果前面空闲空间太多,缩短list的长度
        if self.start > maxSpare:
            self.list = self.list[self.start:]
            self.start = 0
        self.start = self.start + 1
        return self.list[self.start - 1]

    #  蛇的头的前一格位置在头的方向
    def get_forbid_direct(self):
        length = len(self.list)
        if length - self.start == 1:
            return None
        else :
            return self.list[length - 2] - self.list[length - 1]

    def __getitem__(self, item):
        return self.list[self.start + item]

    #  用于for in遍历
    def __iter__(self):
        for i in range(len(self.list) - self.start):
            yield self.list[self.start + i]

    #  查找某个点在队列中的位置,找到返回序号,否则返回-1
    def find(self, item):
        for i in range(len(self.list) - self.start):
            data = self.list[self.start + i]
            if data == item:
                return i
            else:
                return -1

    def __str__(self):
        string = "["
        for i in range(len(self.list) - self.start):
            string += str(self.list[self.start + i]) + ","
        string = string[:-1]
        string = string + "]"
        return string


# 使用pygame之前必须初始化
pygame.init()
# 游戏数据主队列
mainQueue = Queue()
# 游戏是否已开始
isStart = False
# 游戏是否已暂停
isPause = False
# 游戏是否失败过
isGameOver = False
# 贪吃蛇运动方向  默认向右
direction = Point(1, 0)
# 设置主屏窗口  四周留下5px的边
screen = pygame.display.set_mode((windowWidth + spareWidth, windowHeight + spareWidth))
# 字体管理
font = pygame.font.SysFont("Garamond", size=30, bold=True)
# 渲染开始和结束字符串
welcome = font.render("Press Enter To Start A New Game", True, (255, 0, 0), startColor)
game_over = font.render("Game Over! Please Press Enter To Restart", True, (255, 0, 0), startColor)
# 获得渲染后的rect
welcome_rect = welcome.get_rect()
game_over_rect = game_over.get_rect()
# rect居中
welcome_rect.center = (windowWidth // 2, windowHeight // 2)
game_over_rect.center = (windowWidth // 2, windowHeight // 2)
# 初始化面板
initSurface = pygame.Surface((windowWidth + spareWidth, windowHeight + spareWidth), flags=pygame.HWSURFACE)
# 设置窗口的标题,即游戏名称
pygame.display.set_caption('贪吃蛇')
# 主图像面板
mainSurface = pygame.Surface((windowWidth, windowHeight), flags=pygame.HWSURFACE)
# 初始化方块对象
rectSurface = pygame.Surface((rectWidth, rectWidth), flags=pygame.HWSURFACE)
rectSurface.fill(color=rectColor)
# 删除使用的方块
deleteSurface = pygame.Surface((rectWidth, rectWidth), flags=pygame.HWSURFACE)
deleteSurface.fill(color=bgColor)
# 食物点
foodPos = Point()


#  产生新的点
def generate_new_point():
    while True:
        x = random.randint(0, sizeX - 1)
        y = random.randint(0, sizeY - 1)
        p = Point(x, y)
        if mainQueue.find(p) == -1:
            return p


def init_game():
    global mainQueue, isStart, isGameOver, direction, foodPos
    # 初始化游戏数据主队列
    mainQueue = Queue()
    # 游戏是否已开始初始化
    isStart = True
    # 游戏是否失败过初始化
    isGameOver = False
    # 贪吃蛇运动方向初始化  默认向右
    direction = Point(1, 0)
    mainQueue.push_front(direction)
    mainQueue.push_front(Point(2, 0))
    # 使用初始化面板初始化屏幕
    initSurface.fill(color=bgColor)
    screen.blit(initSurface, (0, 0))
    # 主图像面板初始化
    mainSurface.fill(color=bgColor)
    # 初始化食物点
    foodPos = generate_new_point()
    # 主图像面板点初始化
    for item in mainQueue:
        mainSurface.blit(rectSurface, item.get_coordinate())
    mainSurface.blit(rectSurface, foodPos.get_coordinate())


# python E:\可复用源代码\Python\游戏\pygameTest.py
# 数据项(x,y)指示方块的位置
if __name__ == '__main__':
    # 创建时钟对象(控制游戏的FPS)
    clock = pygame.time.Clock()
    # 固定代码段,实现点击"X"号退出界面的功能,几乎所有的pygame都会使用该段代码
    while True:
        # 通过时钟对象,指定循环频率,每秒循环60次
        clock.tick(5)
        # 循环获取事件,监听事件状态
        for event in pygame.event.get():
            # 判断用户是否点了"X"关闭按钮,并执行if代码段
            if event.type == pygame.QUIT:
                # 卸载所有模块
                pygame.quit()
                # 终止程序,确保退出程序
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                # 获取禁止的方向
                forbid_direction = mainQueue.get_forbid_direct()
                if isStart:
                    # 根据按键初始化新方向
                    if event.key == pygame.K_UP:
                        new_direction = Point(0, -1)
                    elif event.key == pygame.K_DOWN:
                        new_direction = Point(0, 1)
                    elif event.key == pygame.K_LEFT:
                        new_direction = Point(-1, 0)
                    elif event.key == pygame.K_RIGHT:
                        new_direction = Point(1, 0)
                    # 暂停只在开始时有效
                    elif event.key == pygame.K_SPACE:
                        # 保证direction不变
                        new_direction = direction
                        isPause = not isPause
                    elif event.key == pygame.K_ESCAPE:
                        # 卸载所有模块
                        pygame.quit()
                        # 终止程序,确保退出程序
                        sys.exit()
                else:
                    if event.key == pygame.K_RETURN:
                        # 只有非游戏中才可以按Enter开始游戏
                        init_game()
                        new_direction = direction
                if forbid_direction:
                    if forbid_direction != new_direction:
                        direction = new_direction
                else:
                    direction = new_direction
        if isStart and not isPause:
            new_pos = mainQueue.get_top() + direction
            # 如果超出范围,游戏结束
            if new_pos.is_out_of_window():
                isGameOver = True
                isStart = False
                continue
            # 如果新位置是食物位置
            if new_pos == foodPos:
                # 贪吃蛇吃了食物
                mainQueue.push_front(foodPos)
                # 生成新的食物点
                foodPos = generate_new_point()
                # 绘制新的食物点
                mainSurface.blit(rectSurface, foodPos.get_coordinate())
            else:
                # 帧生成
                # 第一步 移动贪吃蛇
                last_pos = mainQueue.pop_back()
                # 丢弃最后的位置后才可以判断贪吃蛇是否头尾相撞  在队列里找到新位置则头尾相撞
                if mainQueue.find(new_pos) != -1:
                    isGameOver = True
                    isStart = False
                    continue
                # 新位置入队列
                mainQueue.push_front(new_pos)
                # 删除被移掉的位置
                mainSurface.blit(deleteSurface, last_pos.get_coordinate())
                # 新增下一个位置
                mainSurface.blit(rectSurface, new_pos.get_coordinate())
                screen.blit(mainSurface, (startPos, startPos))
        #  暂停时只画缓存的内容
        elif isStart and isPause:
            screen.blit(mainSurface, (startPos, startPos))
        else:
            # 转为黑色背景
            initSurface.fill(color=startColor)
            screen.blit(initSurface, (0, 0))
            if isGameOver:
                screen.blit(game_over, game_over_rect)
            else:
                screen.blit(welcome, welcome_rect)
        pygame.display.flip()  # 更新屏幕内容

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蔡海航

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值