首页 > 编程语言 >Python实现贪吃蛇大作战

Python实现贪吃蛇大作战

时间:2023-12-17 11:34:51浏览次数:27  
标签:Python pygame 作战 change 贪吃蛇 snake event block dis

贪吃蛇

初始版本

初始版本,只存在基本数据结构——双向队列。

游戏思路

贪吃蛇通过不断得吃食物来增长自身,如果贪吃蛇碰到边界或者自身则游戏失败。

食物是绿色矩形来模拟,坐标为随机数生成,定义一个蛇长变量,判断蛇头坐标和食物坐标是否接近,如果蛇头接近食物,蛇长增加一个单位。

蛇结构体通过双向队列实现蛇的移动和增长。用pygame相应库函数读取键盘事件,每次事件发生都对应蛇头的相应方向,例如按键盘下键贪吃蛇向下走。蛇的移动是通过在队头添加一个新的坐标,然后删掉队尾元素实现的。队列的长度始终为蛇长变量的值。

得分变量为蛇长变量减去一个单位,初始化的时候蛇长就为1个单位长度,故而需要减1。

完整代码

import pygame
import random

pygame.init()

# 以RGB的形式定义颜色
white = (255, 255, 255)
yellow = (255, 255, 102)
black = (0, 0, 0)
red = (213, 50, 80)
green = (0, 255, 0)
blue = (50, 153, 213)

# 设置窗体大小
dis_width = 800
dis_height = 600
dis = pygame.display.set_mode((dis_width, dis_height))
pygame.display.set_caption('贪吃蛇 KevenDuan1.0')

# 创建clock对象
clock = pygame.time.Clock()

# 蛇的宽度
snake_block = 15
# 蛇的速度
snake_speed = 15

# 从系统库里获取字体
font_style = pygame.font.SysFont("bahnschrift", 25)
score_font = pygame.font.SysFont("comicsansms", 35)

def Your_score(score):
    value = score_font.render("Score: " + str(score), True, yellow)
    # 在主surface里添加字体surface
    dis.blit(value, [0, 0])

def our_snake(snake_block, snake_list):
    for x in snake_list:
        pygame.draw.rect(dis, black, [x[0], x[1], snake_block, snake_block])

def message(msg, color):
    mesg = font_style.render(msg, True, color)
    dis.blit(mesg, [dis_width // 2 - 180, dis_height // 2])

def gameLoop():
    game_over = False
    game_close = False

    x1 = dis_width / 2
    y1 = dis_height / 2

    x1_change = 0
    y1_change = 0

    # 存放蛇的身体
    snake_List = []
    # 蛇的长度
    Length_of_snake = 1

    # 食物坐标随机生成
    foodx = round(random.randrange(snake_block, dis_width - snake_block, snake_block))
    foody = round(random.randrange(snake_block, dis_height - snake_block, snake_block))
    print(foodx, foody)

    while not game_over:
        while game_close == True:
            dis.fill(blue)
            message("Game over, press p again or q quit!", red)
            Your_score(Length_of_snake - 1)
            # 修改得分
            pygame.display.update()

            for event in pygame.event.get():
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_q:
                        game_over = True
                        game_close = False
                    if event.key == pygame.K_p:
                        gameLoop()

        # 获取事件
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                game_over = True
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT or event.key == pygame.K_a:
                    x1_change = -snake_block
                    y1_change = 0
                elif event.key == pygame.K_RIGHT or event.key == pygame.K_d:
                    x1_change = snake_block
                    y1_change = 0
                elif event.key == pygame.K_UP or event.key == pygame.K_w:
                    y1_change = -snake_block
                    x1_change = 0
                elif event.key == pygame.K_DOWN or event.key == pygame.K_s:
                    y1_change = snake_block
                    x1_change = 0

        if x1 >= dis_width or x1 < 0 or y1 >= dis_height or y1 < 0:
            # 判断为游戏失败
            game_close = True

        x1 += x1_change
        y1 += y1_change

        dis.fill(blue)
        pygame.draw.rect(dis, green, [foodx, foody, snake_block, snake_block])
        snake_Head = []
        snake_Head.append(x1)
        snake_Head.append(y1)
        snake_List.append(snake_Head)
        # 贪吃蛇的移动
        if len(snake_List) > Length_of_snake:
            del snake_List[0]

        # 判断是否咬到自身
        for x in snake_List[:-1]:
            if x == snake_Head:
                game_close = True

        # 画蛇出来
        our_snake(snake_block, snake_List)
        Your_score(Length_of_snake - 1)

        # 更新画面
        pygame.display.update()

        # 判断蛇是否迟到食物
        if foodx - 10 <= x1 <= foodx + 10 and foody - 10 <= y1 <= foody + 10:
            foodx = round(random.randrange(snake_block, dis_width - snake_block, snake_block))
            foody = round(random.randrange(snake_block, dis_height - snake_block, snake_block))
            # print(foodx, foody)
            Length_of_snake += 1

        # 调节帧率来控制蛇的速度
        clock.tick(snake_speed)

    pygame.quit()
    quit()

gameLoop()

代码讲解

使用的pygamerandom两个库。Pygame是一种流行的Python游戏开发库,它提供了许多功能,使开发人员可以轻松创建2D游戏。它具有良好的跨平台支持,可以在多个操作系统上运行。random库是用来获取随机数的,后面使用其获取食物的随机坐标。

import pygame
import random

初始化一些后期用到的参数,以及初始化pygame,创建clock时钟对象。

# 初始化pygame
pygame.init()
# 以RGB的形式定义颜色
white = (255, 255, 255)
yellow = (255, 255, 102)
black = (0, 0, 0)
red = (213, 50, 80)
green = (0, 255, 0)
blue = (50, 153, 213)

# 设置窗体大小
dis_width = 800
dis_height = 600
dis = pygame.display.set_mode((dis_width, dis_height))
# 设置窗体的名称
pygame.display.set_caption('贪吃蛇 KevenDuan1.0')

# 创建clock对象
clock = pygame.time.Clock()

# 蛇的宽度
snake_block = 15
# 蛇的速度
snake_speed = 15

# 从系统库里获取字体
font_style = pygame.font.SysFont("bahnschrift", 25)
score_font = pygame.font.SysFont("comicsansms", 35)

定义得分函数,实际上就是在画面中添加字体。

def Your_score(score):
    value = score_font.render("Score: " + str(score), True, yellow)
    # 在主surface里添加字体surface
    dis.blit(value, [0, 0])

定义蛇体函数,实际上就是遍历蛇身队列,依次在画面中画出矩形。

def our_snake(snake_block, snake_list):
    for x in snake_list:
        pygame.draw.rect(dis, black, [x[0], x[1], snake_block, snake_block])

定义文本函数,实际上就是在画面中显示文字。

def message(msg, color):
    mesg = font_style.render(msg, True, color)
    dis.blit(mesg, [dis_width // 2 - 180, dis_height // 2])

两个循环结构一个判断游戏是否结束一个判断游戏是否需要退出。

    while not game_over:
        while game_close == True:
            dis.fill(blue)
            message("Game over, press p again or q quit!", red)
            Your_score(Length_of_snake - 1)
            # 修改得分
            pygame.display.update()

            for event in pygame.event.get():
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_q:
                        game_over = True
                        game_close = False
                    if event.key == pygame.K_p:
                        gameLoop()

获取键盘事件改变蛇头方向

# 获取事件
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                game_over = True
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT or event.key == pygame.K_a:
                    x1_change = -snake_block
                    y1_change = 0
                elif event.key == pygame.K_RIGHT or event.key == pygame.K_d:
                    x1_change = snake_block
                    y1_change = 0
                elif event.key == pygame.K_UP or event.key == pygame.K_w:
                    y1_change = -snake_block
                    x1_change = 0
                elif event.key == pygame.K_DOWN or event.key == pygame.K_s:
                    y1_change = snake_block
                    x1_change = 0

蛇的移动是通过在队头添加一个新的坐标,然后删掉队尾元素实现的。队列的长度始终为蛇长变量的值。

		x1 += x1_change
        y1 += y1_change

        dis.fill(blue)
        pygame.draw.rect(dis, green, [foodx, foody, snake_block, snake_block])
        snake_Head = []
        snake_Head.append(x1)
        snake_Head.append(y1)
        snake_List.append(snake_Head)
        # 贪吃蛇的移动
        if len(snake_List) > Length_of_snake:
            del snake_List[0]

        # 判断是否咬到自身
        for x in snake_List[:-1]:
            if x == snake_Head:
                game_close = True

        # 画蛇出来
        our_snake(snake_block, snake_List)
        Your_score(Length_of_snake - 1)

        # 更新画面
        pygame.display.update()

判断蛇头是否吃到食物,设置一定的范围,防止出现永远吃不到的bug

# 判断蛇是否吃到食物
        if foodx - 10 <= x1 <= foodx + 10 and foody - 10 <= y1 <= foody + 10:
            foodx = round(random.randrange(snake_block, dis_width - snake_block, snake_block))
            foody = round(random.randrange(snake_block, dis_height - snake_block, snake_block))
            # print(foodx, foody)
            Length_of_snake += 1

增加菜单功能

通过查阅资料,发现pygame_menu提供了比较完善的游戏菜单功能。我通过pip下载后,查阅了官方样例代码,这个菜单确实是比较精美的,正是我所需要给游戏添加的东西。

import pygame
import pygame_menu

pygame.init()

surface = pygame.display.set_mode((600, 400))

def set_difficulty(value, difficulty):
    # Do the job here !
    print(1)
    pass

def start_the_game():
    # Do the job here !
    pass

menu = pygame_menu.Menu('Welcome', 600, 400,
                       theme=pygame_menu.themes.THEME_BLUE)

menu.add.text_input('Name :', default='kevenduan')
menu.add.selector('Difficulty :', [('Hard', 1), ('Easy', 2)], onchange=set_difficulty)
menu.add.button('Play', start_the_game)
menu.add.button('Quit', pygame_menu.events.EXIT)
menu.mainloop(surface)

最终版本


新功能

最终版本添加了游戏界面菜单,有查询得分记录的功能,以及可以选择两个难度。

查询分数通过列表记录后,通过排序来显示得分前5的分数。

难度的控制是由蛇的速度来控制,由于咬到自身就游戏失败有点坑,在这里删除了。

完整代码

import pygame
import random
import pygame_menu

score = [0, 0, 0, 0, 0]
pygame.init()
# 以RGB的形式定义颜色
white = (255, 255, 255)
yellow = (255, 255, 102)
black = (0, 0, 0)
red = (213, 50, 80)
green = (0, 255, 0)
blue = (50, 153, 213)

# 设置窗体大小
dis_width = 800
dis_height = 600
dis = pygame.display.set_mode((dis_width, dis_height))
pygame.display.set_caption('Snakes KevenDuan 1.0')

# 创建clock对象
clock = pygame.time.Clock()

# 蛇的宽度
snake_block = 15
# 蛇的速度
snake_speed = 15

# 从系统库里获取字体
font_style = pygame.font.SysFont("bahnschrift", 25)
score_font = pygame.font.SysFont("comicsansms", 35)

def Your_score(score):
    value = score_font.render("Score: " + str(score), True, yellow)
    # 在主surface里添加字体surface
    dis.blit(value, [0, 0])

def our_snake(snake_block, snake_list):
    for x in snake_list:
        pygame.draw.rect(dis, black, [x[0], x[1], snake_block, snake_block])

def message(msg, color):
    mesg = font_style.render(msg, True, color)
    dis.blit(mesg, [dis_width // 2 - 150, dis_height // 2])

def gameLoop():
    game_over = False
    game_close = False

    x1 = dis_width / 2
    y1 = dis_height / 2

    x1_change = 0
    y1_change = 0

    # 存放蛇的身体
    snake_List = []
    # 蛇的长度
    Length_of_snake = 1

    # 食物坐标随机生成
    foodx = round(random.randrange(snake_block, dis_width - snake_block, snake_block))
    foody = round(random.randrange(snake_block, dis_height - snake_block, snake_block))
    print(foodx, foody)

    while not game_over:
        while game_close == True:
            dis.fill(blue)
            score.append(Length_of_snake - 1)
            message(f"Game Over! your score is {Length_of_snake - 1}", red)
            Your_score(Length_of_snake - 1)
            # 修改得分
            pygame.display.update()
            pygame.time.wait(2000)
            # 显示出菜单
            menu.mainloop(dis)

        # 获取事件
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                game_over = True
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT or event.key == pygame.K_a:
                    x1_change = -snake_block
                    y1_change = 0
                elif event.key == pygame.K_RIGHT or event.key == pygame.K_d:
                    x1_change = snake_block
                    y1_change = 0
                elif event.key == pygame.K_UP or event.key == pygame.K_w:
                    y1_change = -snake_block
                    x1_change = 0
                elif event.key == pygame.K_DOWN or event.key == pygame.K_s:
                    y1_change = snake_block
                    x1_change = 0

        if x1 >= dis_width or x1 < 0 or y1 >= dis_height or y1 < 0:
            # 判断为游戏失败
            game_close = True

        x1 += x1_change
        y1 += y1_change

        dis.fill(blue)
        pygame.draw.rect(dis, green, [foodx, foody, snake_block, snake_block])
        snake_Head = []
        snake_Head.append(x1)
        snake_Head.append(y1)
        snake_List.append(snake_Head)
        # 贪吃蛇的移动
        if len(snake_List) > Length_of_snake:
            del snake_List[0]

        # 判断是否咬到自身
        # for x in snake_List[:-1]:
        #     if x == snake_Head:
        #         game_close = True

        # 画蛇出来
        our_snake(snake_block, snake_List)
        Your_score(Length_of_snake - 1)

        # 更新画面
        pygame.display.update()

        # 判断蛇是否吃到食物
        if foodx - 10 <= x1 <= foodx + 10 and foody - 10 <= y1 <= foody + 10:
            foodx = round(random.randrange(snake_block, dis_width - snake_block, snake_block))
            foody = round(random.randrange(snake_block, dis_height - snake_block, snake_block))
            # print(foodx, foody)
            Length_of_snake += 1

        # 调节帧率来控制蛇的速度
        clock.tick(snake_speed)

    pygame.quit()
    quit()



def set_difficulty(value, difficulty):
    # Do the job here !
    global snake_speed
    if snake_speed == 15: snake_speed = 30
    else: snake_speed = 15

def start_the_game():
    # Do the job here !
    gameLoop()

def rank():
    # flag = True
    while True:
        dis.fill(blue)
        score.sort()
        print(score)
        mesg1 = font_style.render(f"Your highest score is {score[-1]}", True, yellow)
        dis.blit(mesg1, [dis_width // 2 - 150, dis_height // 2 - 30])
        mesg2 = font_style.render(f"Ranking of scores:{score[-1:-6:-1]}", True, yellow)
        dis.blit(mesg2, [dis_width // 2 - 190, dis_height // 2 + 10])

        pygame.display.update()
        pygame.time.wait(3000)
        menu.mainloop(dis)
        # menu.add.button('Quit', pygame_menu.events.EXIT)
        # for event in pygame.event.get():
        #     if event.type == pygame.QUIT:
        #         flag = True

menu = pygame_menu.Menu('Welcome to my game', 800, 600,
                       theme=pygame_menu.themes.THEME_BLUE)

menu.add.text_input('Author :', default='KevenDuan')
menu.add.selector('Difficulty :', [('Easy', 1), ('Hard', 2)], onchange=set_difficulty)
menu.add.button('Yours socres', rank)
menu.add.button('Play', start_the_game)
menu.add.button('Quit', pygame_menu.events.EXIT)
menu.mainloop(dis)

标签:Python,pygame,作战,change,贪吃蛇,snake,event,block,dis
From: https://www.cnblogs.com/itduan/p/17908878.html

相关文章

  • Python实现软件设计模式4:建造者模式
    特点建造者模式是一步一步构建一个复杂的对象,属于对象创建型模式将一个复杂对象的构建与他的表示分离,使得同样的构建过程可以创建不同的表示关注如何逐步地创建一个复杂的对象或产品,不同的创造者定义了不同的创建过程用户不需要知道内部的具体构造细节、只用指定复杂对象的类......
  • Python实现软件设计模式3:抽象工厂模式
    特点系统中除了有多种产品类型(产品等级结构,如果汁、方便面、矿泉水),还出现了多个品牌(产品族,或农夫山泉、娃哈哈、康师傅、统一等品牌几乎都有这些产品)在工厂方法模式中,只有一个产品等级结构一个抽象产品(父类)、多个具体产品(子类)形成一个产品等级结构产品族是指由同一个工厂生产......
  • python 使用 Google Gemini API
    python使用GoogleGeminiAPI注册APIKEY:GoogleAIStudio[免费]importbase64importrequestsimportjsonAPI_KEY='yourapikey'img_path='./scones.jpg'#设置模型参数和过滤规则https://ai.google.dev/api/rest/v1beta/SafetySetting?hl=zh-cn#H......
  • Python NumPy 与 Pandas 结合使用
    1、NumPy数组与PandasDataFrame/Series转换NumPy数组与PandasDataFrame/Series是Python中常用的两种数据结构,它们都用于存储和处理数据。NumPy数组是一种多维数组,它可以存储一维、二维、三维或更高维的数据。NumPy数组的优点是速度快、效率高,适合用于数值计算。Panda......
  • python之tkinter的button控件
    按钮组件,用于监听用户行为,调用具体功能函数。按钮上可以是文字或者图片。语法:Button(master,option……)master父容器option参数参数:参数属性举例或备注bg按钮背景颜色 fg按钮前景颜色按钮上的文字颜色bd按钮边框大小边框会呈现立体感activebackground鼠标点击时按钮背景色 act......
  • 面试Python时必会的知识点总结
    目前代码技能已经成了测试同学面试考核的刚需,对于测试开发来讲需求最大的是java和python两门语言,二者也都是面向对象语言。对于刚入门代码的同学来说面向对象相关的概念比较难于理解,而面向对象编程相关的知识点偏偏又是面试中的高频问题,所以本文我以python为例,带大家快速搞定面向......
  • python 基础极简解释
    python基础局部与全局声明全局变量global数据存储列表变量=[数据1,数据2]变量[索引]基本:方法说明列表名.index(值)输入列表值取索引列表名[索引]=数据赋值lea(列表)统计元素列表.count(数据)统计数据出现的次数排序:方法说明列表......
  • Python中级之解压赋值
    解压赋值【一】解压赋值的概念解压赋值是指将一个可迭代对象(如列表、元组、字典的键值对等)中的元素拆分并分配给多个变量。这种技术非常方便,可以简洁地从一个数据结构中提取元素并将它们分配给多个变量。需要确保变量的数量与可迭代对象中的元素数量匹配,否则会引发ValueError......
  • Python装饰器:深入探索功能增强的神奇工具(特点+应用+举例)
    Python装饰器是一项强大的特性,它允许程序员在不改变函数或类本身的情况下,增加、扩展或修改它们的行为。从日志记录到权限验证,再到性能分析和缓存,装饰器在Python编程中发挥着重要的作用。本文将深入探讨装饰器的各个方面,从基本概念到实际应用,带您领略装饰器的神奇之处。装饰器是Pyth......
  • python高级之生成器
    生成器一、生成器与yield若函数体包含yield关键字,再调用函数,并不会执行函数体代码,得到的返回值即生成器对象defmy_range(start,stop,step=1):print('start...')whilestart<stop:yieldstartstart+=stepprint('end...')g=my_range(0,3)......