大脑组织残缺 发表于 2019-7-24 18:59

【Python】Pygame模块实现功能超赞的贪吃蛇

本帖最后由 大脑组织残缺 于 2019-8-1 19:07 编辑

一周前 放假无聊 做了一个贪吃蛇 并发布了1.2版本,现在 2.0最终版已开发完成!效果如图:
不知为何图片会跑到末尾去啊啊啊啊啊,编辑也不显示 无奈啊
https://static.52pojie.cn/static/image/hrline/line1.png


目前实现的功能有:·贪吃蛇基本游戏功能,·可选有无墙,·生成大食物   ·速度变化(有上限)    ·得分减少
·地图选择功能 ·自定义速度功能  ·记录最高分功能 ·玩家绘制地图功能   
百度网盘:exe版本,无需python解释器https://pan.baidu.com/s/1hcPafSZyu_n_6F5eUti4Wg 可直接执行,提取码:yrqk
从1.0版本修改到2.0版本,代码也从100多行到现在的700多行,在这个过程中也总结了一些经验心得,入门编程的可以看下,大佬。。大佬可以出门左转{:1_911:}

[*]按照语法规范写代码。      虽然此代码按照PEP8规范书写,但写多了看着还是眼花缭乱( 代码起高了, 听起来不顺眼 )。
[*]分好模块。 方便添加功能,修改代码。 在楼主逐渐添加功能的过程中,并不是把新功能放在一个新的函数或者类里面就OK的,还要对之前的代码进行大量修改,做好模块分类,可以精准定位。虽然楼主在制作1.0版本时就构建了框架,考虑了可能的模块,11分好,(一开始分了两个文件来完成,由于贪图一时方便在1.2版本就合并为一个文件。若非这样,楼主的代码会更易读),但越往后完善功能 感觉对于模块的分类越模糊,终于在即将完成2.0版本时有了新的分类想法,奈何已经完成了700多行代码, 无力重写,不过一定会对以后在开发大量代码有所帮助。感觉模块分类这东西都是据经验而评吧,楼主也是第一次开发这么多代码的文件,包括核心算法在内没有参考任何东西(初心就是练一下手)。
[*]做好注释。 注释不必详细,但要能够让你自己知道这个东西是干嘛用的。在这个代码从100多行到700多行来,只有每天晚上有几个小时来敲代码,白天经历那么多事,不会对于之前定义的变量和方法都历历在目,只能记得有这个东西,这时候就要回去阅读自己的代码,有些方法没加注释,就要一步一步的看,看它各种传递各种调用。。
[*]添加新功能时在新文件中完成。 由于添加新功能的同时会对已完成的代码进行修改,若在原来的文件上直接进行,(如果突然有了更简单的算法 或者目前正在实现的算法比较难实现 )须重写时,特别时无法撤回时,会很麻烦。 好在楼主在1.0版本的基础上添加功能时遇到了这样的问题,才有了1.x 2.x 版本的诞生:lol




若有任何关于此游戏的 创意 及 建议,请在评论区盖楼提出
你的支持评分 就是我最大的动力!下一版预告:蛇身优化(能够分清移动轨迹)

最后附上20版源码及源文件:   注:运行此段代码需用到的pygame模块需自行安装,可在cmd使用 pip install pygame 命令自动安装。若复制代码运行错误可能由复制、修改时产生格式错误引起,可以直接下载附件
附件内含:1.0版本 为游戏核心部分代码,仅100多行。算法纯属原创 方便阅读学习。

import pygame
import random
import sys
import pygame.freetype
import re
import datetime

pygame.init()# 初始化py_game模块
fl = pygame.freetype.Font("C://Windows//Fonts//simsun.ttc", 30)   # 加载字体 如果此处报错请修改路径为本地字体库
screen = pygame.display.set_mode((1186, 668))   # 界面大小
pygame.display.set_caption("贪吃蛇v-0.2.0   by-吾爱破解:大脑组织残缺")   # 修改名称
clock = pygame.time.Clock()   # 游戏时钟
GOLD = 255, 251, 0          # 颜色设定
RED = pygame.Color('red')
WHITE = 255, 255, 255


class Snake:
    body_list = []# 记录蛇身位置的列表
    center_1 = None# 小食物中心
    center_2 = None# 大食物中心
    center_2_key = False# 大食物控制钥匙
    big_time = None
    score = 0       # 分数记录
    long = 0      # 蛇身记录
    fs = 0          # 最终得分
    WALL = False    # 墙 不存在

    def __init__(self):
      self.r = 5# 食物半径
      self.FOOD_SIZE = 21

      self.old_pop = None# 尾巴列表
      self.switch = (0, 0)# 防止撞头开关
      self.big_food_time_1 = None# 大豆豆时间
      self.eat_big_food_key = 0# 大豆豆增长钥匙
      Snake.body_list = []# 记录蛇身位置的列表
      Snake.center_1 = None# 小食物中心
      Snake.center_2 = None# 大食物中心
      Snake.center_2_key = False# 大食物控制钥匙
      Snake.big_time = None
      Snake.score = 0# 分数记录
      Snake.long = 7# 蛇的长度
      self.SNAKE_SIZE = 21# 每一块🐍的大小
      self.x_speech = 0
      self.y_speech = 0
      self.speech = (0, 0)
      self.head_rect = # 蛇头的相对位置
      self.__draw_head()# 绘制蛇头
      for p in range(Snake.long):# 绘制蛇身
            if p != 0:
                pygame.draw.rect(screen, WHITE, (
                  81 + (self.head_rect - p) * self.SNAKE_SIZE + 1, 66 + self.head_rect * self.SNAKE_SIZE + 1,
                  self.SNAKE_SIZE - 1,
                  self.SNAKE_SIZE - 1))
                Snake.body_list.append((self.head_rect - p, self.head_rect))

    def Speech(self, p, switch_1):
      if switch_1 == 0:
            self.switch = self.speech
            switch_1 = 1
      if p.type == pygame.KEYDOWN:
            if p.key == pygame.K_UP:
                if self.speech != (0, 1) and self.switch != (0, 1):
                  self.y_speech = -1
                  self.x_speech = 0
            elif p.key == pygame.K_DOWN:
                if self.speech != (0, -1) and self.switch != (0, -1):
                  self.y_speech = 1
                  self.x_speech = 0
            elif p.key == pygame.K_RIGHT:
                if self.speech != (-1, 0) and self.switch != (-1, 0):
                  self.x_speech = 1
                  self.y_speech = 0
            elif p.key == pygame.K_LEFT:
                if self.speech != (1, 0) and self.switch != (1, 0) and self.speech != (0, 0):
                  self.x_speech = -1
                  self.y_speech = 0
      self.speech = (self.x_speech, self.y_speech)
      return switch_1

    def move(self):

      if self.x_speech or self.y_speech != 0:
            Snake.body_list = [(self.head_rect, self.head_rect)] + Snake.body_list
            self.__draw_body()

      # 位置移动区块
      self.head_rect += self.speech
      self.head_rect += self.speech
      self.__wall()         # 墙面传送
      self.__draw_head()      # 绘制蛇头

      # 判断蛇头吃豆豆
      if self.head_rect == list(Snake.center_1):
            Snake.long += 1
            self.draw_new_food()
            Snake.score += 10
            if self.eat_big_food_key > 0:
                self.old_pop = Snake.body_list.pop()
                self.eat_big_food_key += 1
            else:
                pygame.draw.rect(screen, WHITE, (
                  81 + Snake.body_list * self.SNAKE_SIZE + 1,
                  66 + Snake.body_list * self.SNAKE_SIZE + 1,
                  self.SNAKE_SIZE - 1, self.SNAKE_SIZE - 1))# 身体增长
      elif self.x_speech or self.y_speech != 0:
            self.old_pop = Snake.body_list.pop()
            self.draw_new_food(False)

      if Snake.center_2_key:# 大豆豆的时间控制 与 吃到大豆豆的变化
            if self.head_rect == list(Snake.center_2):
                Snake.long += 3# 长度+3
                Snake.score += 50# 分数+50
                self.eat_big_food_key = 3# 大豆豆增长钥匙
                Snake.center_2 = None# 清空大豆豆列表
                Snake.center_2_key = False
                fl.render_to(screen, (560, 80), str(8 - Snake.big_time), (0, 0, 0), size=40)
                fl.render_to(screen, (560, 80), str(9 - Snake.big_time), (0, 0, 0), size=40)
            self.big_food_time()

      if self.eat_big_food_key > 0:
            Snake.body_list.append(self.old_pop)
            self.eat_big_food_key -= 1
            pygame.draw.rect(screen, WHITE, (
                81 + Snake.body_list * self.SNAKE_SIZE + 1,
                66 + Snake.body_list * self.SNAKE_SIZE + 1,
                self.SNAKE_SIZE - 1, self.SNAKE_SIZE - 1))

      # 判断头吃身体
      if tuple(self.head_rect) in Snake.body_list:
            self.speech = (0, 0)
            self.x_speech = self.y_speech = 0
            # 游戏结束
            return 1

      # 判断头撞地形
      if AllMap.map_list is not None:
            if tuple(self.head_rect) in AllMap.map_list:
                self.speech = (0, 0)
                self.x_speech = self.y_speech = 0
                return 1

    def __draw_head(self):
      pygame.draw.rect(screen, RED, (
            81 + self.head_rect * self.SNAKE_SIZE + 1, 66 + self.head_rect * self.SNAKE_SIZE + 1,
            self.SNAKE_SIZE - 1,
            self.SNAKE_SIZE - 1))

    def __draw_body(self):
      # 覆盖老蛇头
      pygame.draw.rect(screen, WHITE, (
            81 + Snake.body_list * self.SNAKE_SIZE + 1, 66 + Snake.body_list * self.SNAKE_SIZE + 1,
            self.SNAKE_SIZE - 1,
            self.SNAKE_SIZE - 1))

      # 删除蛇尾
      if self.eat_big_food_key <= 0:
            pygame.draw.rect(screen, (0, 0, 0), (
                81 + Snake.body_list * self.SNAKE_SIZE + 1,
                66 + Snake.body_list * self.SNAKE_SIZE + 1,
                self.SNAKE_SIZE, self.SNAKE_SIZE))

    @staticmethod
    def __Center():
      """随机生成豆豆位置"""
      center = (random.randint(0, 24), random.randint(0, 24))# 随机生成食物的相对位置
      # 判断随机数是否与蛇身重合,并处理
      while True:
            if center in Snake.body_list:
                center = (random.randint(0, 24), random.randint(0, 24))
            elif center == Snake.center_1 or center == Snake.center_2:
                center = (random.randint(0, 24), random.randint(0, 24))
            elif AllMap.map_list is not None and center in AllMap.map_list:
                center = (random.randint(0, 24), random.randint(0, 24))
            else:
                return center

    def draw_new_food(self, key=True):
      if key:
            Snake.center_1 = Snake.__Center()
      pygame.draw.circle(screen, WHITE,
                           (81 + Snake.center_1 * self.FOOD_SIZE + 11, 66 + Snake.center_1 * self.FOOD_SIZE + 11),
                           self.r)

      if Snake.long % 12 == 0 and key:
            Snake.center_2 = Snake.__Center()
            pygame.draw.circle(screen, GOLD,
                               (81 + Snake.center_2 * self.FOOD_SIZE + 11,
                              66 + Snake.center_2 * self.FOOD_SIZE + 11),
                               self.r + 2)
            Snake.center_2_key = True
            self.big_food_time_1 = int(pygame.time.get_ticks() / 1000)

    def big_food_time(self):
      time_2 = int(pygame.time.get_ticks() / 1000)
      Snake.big_time = time_2 - self.big_food_time_1
      if time_2 - self.big_food_time_1 >= 8:
            pygame.draw.circle(screen, (0, 0, 0),
                               (81 + Snake.center_2 * self.FOOD_SIZE + 11,
                              66 + Snake.center_2 * self.FOOD_SIZE + 11),
                               self.r + 2)
            fl.render_to(screen, (560, 80), '1', (0, 0, 0), size=40)
            Snake.center_2 = None
            Snake.center_2_key = False

    def __wall(self):
      """判断是否有墙及传送"""
      if Snake.WALL:
            if self.head_rect == 25 or self.head_rect == -1 or self.head_rect == 25 or self.head_rect == -1:# 判断撞墙
                over()
      else:
            if self.head_rect == 25:# 墙面传送
                self.head_rect = 0
            elif self.head_rect == 25:
                self.head_rect = 0
            elif self.head_rect == -1:
                self.head_rect = 24
            elif self.head_rect == -1:
                self.head_rect = 24


class GameSpeed:

    game_fps_min_speed = 5
    game_fps_high_speed = 10
    game_fps_max_speed = 24


class AllMap:
    GAME_WINDOW_NO = (80, 65, 529, 529)
    GAME_WINDOW_HA = (78, 63, 532, 532)
    WALL = False      # 无墙
    map_list = [None,
                ((2, 2), (2, 4), (2, 5), (2, 19), (2, 20), (2, 21), (2, 22), (1, 1), (1, 2), (1, 4), (1, 5), (2, 1),
               (4, 1), (5, 1), (3, 19), (3, 20), (3, 21), (3, 22), (4, 2), (4, 4), (4, 5), (4, 19), (4, 20), (4, 21),
               (4, 22), (19, 1), (20, 1), (5, 2), (5, 4), (5, 5), (5, 19), (5, 20), (5, 21), (5, 22), (19, 2),
               (19, 4), (19, 5), (22, 1), (23, 1), (23, 2), (19, 19), (19, 20), (19, 21), (19, 22), (20, 2), (20, 4),
               (20, 5), (20, 19), (20, 20), (23, 4), (23, 5), (20, 21), (20, 22), (21, 19), (21, 20), (21, 21),
               (21, 22), (22, 2), (22, 4), (22, 5), (22, 19), (22, 20), (22, 21), (22, 22), (7, 7), (8, 7), (9, 7),
               (10, 7), (11, 7), (12, 7), (13, 7), (14, 7), (15, 7), (16, 7), (17, 7), (7, 8), (8, 8), (9, 8),
               (10, 8), (11, 8), (12, 8), (13, 8), (14, 8), (15, 8), (16, 8), (17, 8), (7, 16), (8, 16), (9, 16),
               (10, 16), (11, 16), (12, 16), (13, 16), (14, 16), (15, 16), (16, 16), (17, 16), (7, 17), (8, 17),
               (9, 17), (10, 17), (11, 17), (12, 17), (13, 17), (14, 17), (15, 17), (16, 17), (17, 17)),
                ((1, 10), (2, 9), (3, 8), (4, 7), (5, 6), (6, 5), (7, 4), (8, 3), (9, 2), (10, 1), (2, 10), (3, 9),
               (4, 8), (5, 7), (6, 6), (7, 5), (8, 4), (9, 3), (10, 2), (14, 1), (15, 2), (16, 3), (17, 4), (18, 5),
               (19, 6), (20, 7), (21, 8), (22, 9), (23, 10), (14, 2), (15, 3), (16, 4), (17, 5), (18, 6), (19, 7),
               (20, 8), (21, 9), (22, 10), (6, 15), (6, 16), (6, 17), (6, 18), (6, 19), (6, 20), (6, 21), (6, 22),
               (6, 23), (6, 24), (7, 17), (7, 18), (7, 19), (7, 20), (7, 21), (7, 22), (7, 23), (7, 24), (17, 17),
               (17, 18), (17, 19), (17, 20), (17, 21), (17, 22), (17, 23), (17, 24), (18, 15), (18, 16), (18, 17),
               (18, 18), (18, 19), (18, 20), (18, 21), (18, 22), (18, 23), (18, 24), (8, 15), (9, 15), (10, 15),
               (11, 15), (12, 15), (13, 15), (14, 15), (15, 15), (16, 15)),
                ((3, 7), (4, 7), (7, 7), (8, 7), (3, 8), (4, 8), (7, 8), (8, 8), (3, 9), (4, 9), (7, 9), (8, 9),
               (3, 10), (4, 10), (7, 10), (8, 10), (3, 11), (4, 11), (7, 11), (8, 11), (3, 12), (4, 12), (7, 12),
               (8, 12), (3, 13), (4, 13), (7, 13), (8, 13), (3, 14), (4, 14), (7, 14), (8, 14), (3, 15), (4, 15),
               (7, 15), (8, 15), (3, 16), (4, 16), (7, 16), (8, 16), (3, 18), (4, 18), (7, 18), (8, 18), (3, 19),
               (4, 19), (7, 19), (8, 19), (18, 1), (18, 2), (18, 3), (18, 6), (18, 7), (18, 8), (21, 1), (21, 2),
               (21, 3), (21, 6), (21, 7), (21, 8), (16, 3), (17, 3), (22, 3), (23, 3), (23, 6), (22, 6), (17, 6),
               (16, 6))]    # 地图列表   只内置了两个地图,不喜可在此列表中删除,也可以将ini文件中自定义的元组复制到此处防止自定义的地图丢失
    numb = 0            # 地图选择

    def __init__(self):
      map_file = open('gamer_map.ini', 'a+')    # 创建地图文件
      map_file.seek(0)
      map_fl_read = map_file.read()             # 将读取到的地图合并到map_list
      lien = re.findall('<([\s\S]*?)>', map_fl_read)
      for i in lien:
            AllMap.map_list.append(eval(i))
      map_file.close()

    @classmethod
    def draw_window(cls, mode):
      if mode:
            pygame.draw.rect(screen, GOLD, cls.GAME_WINDOW_HA, 5)
      else:
            pygame.draw.rect(screen, (0, 0, 0), cls.GAME_WINDOW_HA, 5)
            pygame.draw.rect(screen, GOLD, cls.GAME_WINDOW_NO, 1)

    @classmethod
    def draw_map(cls):
      """绘制地图"""
      pygame.draw.rect(screen, (0, 0, 0), (81, 66, 526, 526))
      Snake()
      if AllMap.numb == len(AllMap.map_list):
            fl.render_to(screen, (250, 250), "绘制地图", fgcolor=(255, 0, 255), bgcolor=(0, 0, 0, 60), size=50)
      elif cls.map_list is not None:
            for i in cls.map_list:
                pygame.draw.rect(screen, (0, 255, 255), (81 + i * 21 + 1, 66 + i * 21 + 1, 20, 20))

    @classmethod
    def gamer_draw_map(cls):
      pointer_place = (12, 10)      # 指针位置列表
      new_map_list = []               # 创建一个空列表
      while True:
            pygame.draw.rect(screen, (0, 0, 0), (81 + pointer_place * 21, 66 + pointer_place * 21, 22, 22), 1)
            if int(pygame.time.get_ticks() / 100) % 10 < 5:   # 指针闪烁效果
                color_set = RED
            else:
                color_set = (0, 255, 255)

            for i in pygame.event.get():         # 获取监听事件
                if i.type == pygame.QUIT:
                  sys.exit()
                elif i.type == pygame.KEYDOWN:   # 按键操作
                  if i.key == pygame.K_UP:
                        pointer_place = (pointer_place, pointer_place - 1)
                        if pointer_place < 0:
                            pointer_place = (pointer_place, 24)
                  elif i.key == pygame.K_DOWN:
                        pointer_place = (pointer_place, pointer_place + 1)
                        if pointer_place > 24:
                            pointer_place = (pointer_place, 0)
                  elif i.key == pygame.K_LEFT:
                        pointer_place = (pointer_place - 1, pointer_place)
                        if pointer_place < 0:
                            pointer_place = (24, pointer_place)
                  elif i.key == pygame.K_RIGHT:
                        pointer_place = (pointer_place + 1, pointer_place)
                        if pointer_place > 24:
                            pointer_place = (0, pointer_place)
                  elif i.key == pygame.K_SPACE and pointer_place not in (Snake.body_list + [(15, 12)]):   # 绘制地形
                        # 判断是否在列表中,不在则添加,在则删除 并绘制
                        if pointer_place in new_map_list:
                            new_map_list.remove(pointer_place)
                            pygame.draw.rect(screen, (0, 0, 0),
                                             (81 + pointer_place * 21 + 1,
                                              66 + pointer_place * 21 + 1, 20, 20))
                        else:
                            new_map_list.append(pointer_place)
                            pygame.draw.rect(screen, (0, 255, 255),
                                             (81 + pointer_place * 21 + 1,
                                              66 + pointer_place * 21 + 1, 20, 20))
                  elif i.key == pygame.K_ESCAPE:# 返回上层,此次绘制无效
                        maps()
                  elif i.key == pygame.K_KP_ENTER or i.key == pygame.K_RETURN:    # 完成绘制
                        # 提醒是否绘制完成
                        fl.render_to(screen, (220, 110), '保存并开始', fgcolor=WHITE, size=50, bgcolor=(0, 0, 0, 60))
                        fl.render_to(screen, (240, 180), '确定   取消', fgcolor=WHITE, bgcolor=(0, 0, 0, 60))
                        yx_list = [(230, 195), (365, 195)]
                        yx_key = 0
                        switch_key = True
                        while switch_key:
                            pygame.draw.circle(screen, (0, 0, 0), yx_list, 6)
                            for p in pygame.event.get():         # 获取监听事件
                              if p.type == pygame.QUIT:
                                    sys.exit()
                              elif p.type == pygame.KEYDOWN:
                                    if p.key == pygame.K_LEFT or p.key == pygame.K_RIGHT:
                                        if yx_key == 0:
                                          yx_key = 1
                                        else:
                                          yx_key = 0
                                    elif p.key == pygame.K_KP_ENTER or p.key == pygame.K_RETURN:
                                        pygame.draw.rect(screen, (0, 0, 0), (220, 110, 250, 100))
                                        for j in new_map_list:
                                          pygame.draw.rect(screen, (0, 255, 255), (81 + j * 21 + 1, 66 + j * 21 + 1, 20, 20))
                                        if yx_key == 0:   # 保存并开始
                                          if len(new_map_list) != 0:
                                                AllMap.map_list.append(tuple(new_map_list))
                                                map_file = open('gamer_map.ini', 'a+')    # 追加写入创建的地图
                                                map_file.write('<')
                                                map_file.write(str(tuple(new_map_list)))
                                                map_file.write('>\n')
                                                map_file.close()
                                          else:
                                                AllMap.numb = 0
                                          action()
                                        else:               # 继续绘制
                                          switch_key = False
                            if switch_key:
                              pygame.draw.circle(screen, (255, 0, 255), yx_list, 6)
                            pygame.display.update()# 刷新屏幕
                            clock.tick(30)# 游戏时钟

            pygame.draw.rect(screen, color_set, (81 + pointer_place * 21, 66 + pointer_place * 21, 22, 22), 1)
            pygame.display.update()# 刷新屏幕
            clock.tick(30)# 游戏时钟


def single_move(sin_rect, p, mode=1):
    """
    选项移动
    :param sin_rect: 三角坐标
    :param p: 按键检测
    :param mode: 模式
    :return: 三角坐标
    """
    if mode == 1:
      if p.key == pygame.K_UP:
            for j in sin_rect:
                j -= 80
      elif p.key == pygame.K_DOWN:
            for j in sin_rect:
                j += 80
      elif p.key == pygame.K_RETURN or p.key == pygame.K_KP_ENTER:
            pygame.draw.rect(screen, (0, 0, 0), (100, 70, 500, 500))
            if sin_rect == 200:# 开始游戏 选择地图
                maps()
            elif sin_rect == 280:# 速度设置
                speed_setting()
            elif sin_rect == 360:# 历史高分
                high_score()
            elif sin_rect == 440:# 退出游戏
                sys.exit()
      if sin_rect < 200:
            for j in sin_rect:
                j += 320
      elif sin_rect > 440:
            for j in sin_rect:
                j -= 320
      return sin_rect

    elif mode == 2:
      if p.key == pygame.K_UP:
            for j in sin_rect:
                j -= 50
      elif p.key == pygame.K_DOWN:
            for j in sin_rect:
                j += 50
      elif p.key == pygame.K_RETURN or p.key == pygame.K_KP_ENTER:
            pygame.draw.rect(screen, (0, 0, 0), (81, 66, 526, 526))
            if sin_rect == 310:
                AllMap.draw_map()
                action()
            elif sin_rect == 360:
                star()
      if sin_rect < 310:
            for j in sin_rect:
                j += 100
      elif sin_rect > 360:
            for j in sin_rect:
                j -= 100
      return sin_rect

    elif mode == 3:
      if p.key == pygame.K_UP and sin_rect == 210:   # 指针位置
            for j in sin_rect:
                j -= 140
            for j in sin_rect:
                j -= 140
      elif p.key == pygame.K_DOWN and sin_rect == 210:
            for j in sin_rect:
                j += 140
            for j in sin_rect:
                j += 140
      elif p.key == pygame.K_LEFT:
            if sin_rect == 185:
                GameSpeed.game_fps_min_speed -= 1
                if GameSpeed.game_fps_min_speed < 1:
                  GameSpeed.game_fps_min_speed = GameSpeed.game_fps_high_speed
            elif sin_rect == 325:
                GameSpeed.game_fps_high_speed -= 1
                if GameSpeed.game_fps_high_speed < GameSpeed.game_fps_min_speed:
                  GameSpeed.game_fps_high_speed = GameSpeed.game_fps_max_speed - 1
            elif sin_rect == 465:
                GameSpeed.game_fps_max_speed -= 1
                if GameSpeed.game_fps_max_speed <= GameSpeed.game_fps_high_speed:
                  GameSpeed.game_fps_max_speed = 35
      elif p.key == pygame.K_RIGHT:
            if sin_rect == 185:
                GameSpeed.game_fps_min_speed += 1
                if GameSpeed.game_fps_min_speed > GameSpeed.game_fps_high_speed:
                  GameSpeed.game_fps_min_speed = 1
            elif sin_rect == 325:
                GameSpeed.game_fps_high_speed += 1
                if GameSpeed.game_fps_high_speed > GameSpeed.game_fps_max_speed - 1:
                  GameSpeed.game_fps_high_speed = GameSpeed.game_fps_min_speed
            elif sin_rect == 465:
                GameSpeed.game_fps_max_speed += 1
                if GameSpeed.game_fps_max_speed > 35:
                  GameSpeed.game_fps_max_speed = GameSpeed.game_fps_high_speed + 1
      elif p.key == pygame.K_RETURN or p.key == pygame.K_KP_ENTER:
            if sin_rect == 120:
                sin_rect = [[, , ],
                            [, , ]]
            elif sin_rect == 260:
                sin_rect = [[, , ],
                            [, , ]]
            elif sin_rect == 400:
                sin_rect = [[, , ],
                            [, , ]]
            elif sin_rect == 540:# 回主页
                pygame.draw.rect(screen, (0, 0, 0), (100, 70, 500, 520))
                star()
            elif sin_rect == 185:
                sin_rect = [[, , ],
                            [, , ]]
            elif sin_rect == 325:
                sin_rect = [[, , ],
                            [, , ]]
            elif sin_rect == 465:
                sin_rect = [[, , ],
                            [, , ]]

      if sin_rect < 120:   # 指针位置循环
            for j in sin_rect + sin_rect:
                j += 560
      elif sin_rect > 540:
            for j in sin_rect + sin_rect:
                j -= 560
      return sin_rect

    elif mode == 4:
      if p.key == pygame.K_LEFT:   # 左切换地图
            AllMap.numb -= 1
            if AllMap.numb < 0:
                AllMap.numb = len(AllMap.map_list)
            AllMap.draw_map()
      elif p.key == pygame.K_RIGHT:    # 右切换地图
            AllMap.numb += 1
            if AllMap.numb > len(AllMap.map_list):
                AllMap.numb = 0
            AllMap.draw_map()
      elif p.key == pygame.K_RETURN or p.key == pygame.K_KP_ENTER:
            if AllMap.numb == len(AllMap.map_list):   # 进入绘图模式
                pygame.draw.rect(screen, (0, 0, 0), (250, 250, 200, 50))
                pygame.draw.polygon(screen, (0, 0, 0), (, , ))
                pygame.draw.polygon(screen, (0, 0, 0), (, , ))
                pygame.draw.rect(screen, (0, 0, 0), (666, 66, 500, 530))
                fl.render_to(screen, (670, 110), '绘制地图:', fgcolor=WHITE, size=50)
                fl.render_to(screen, (670, 180), '  使用 "←" "→" "↑"', fgcolor=WHITE, size=40)
                fl.render_to(screen, (670, 250), '"↓" 移动,空格键绘制', fgcolor=WHITE, size=40)
                fl.render_to(screen, (670, 320), '地图,再次使用空格键可', fgcolor=WHITE, size=40)
                fl.render_to(screen, (670, 390), '撤销,"←┘"键完成绘', fgcolor=WHITE, size=40)
                fl.render_to(screen, (670, 460), '制,ESC键取消绘制。', fgcolor=WHITE, size=40)
                fl.render_to(screen, (670, 520), '  提示: 请勿将封闭的几何图形留', fgcolor=WHITE, size=25)
                fl.render_to(screen, (670, 560), '空,否则食物有可能随机产生在其中!', fgcolor=WHITE, size=25)
                AllMap.gamer_draw_map()
            else:                                       # 开始游戏
                pygame.draw.polygon(screen, (0, 0, 0), (, , ))
                pygame.draw.polygon(screen, (0, 0, 0), (, , ))
                pygame.draw.rect(screen, (0, 0, 0), (650, 65, 520, 600))
                action()
      elif p.key == pygame.K_SPACE:
            AllMap.WALL = not AllMap.WALL
            Snake.WALL = not Snake.WALL
            AllMap.draw_window(AllMap.WALL)
      elif p.key == pygame.K_ESCAPE:
            pygame.draw.rect(screen, (0, 0, 0), (81, 66, 526, 526))
            pygame.draw.polygon(screen, (0, 0, 0), (, , ))
            pygame.draw.polygon(screen, (0, 0, 0), (, , ))
            star()


def star(fps=60):
    single_rect = [, , ]
    fl.render_to(screen, (260, 190), "开始游戏", fgcolor=GOLD, size=50)
    fl.render_to(screen, (260, 270), "速度设置", fgcolor=GOLD, size=50)
    fl.render_to(screen, (260, 350), "历史高分", fgcolor=GOLD, size=50)
    fl.render_to(screen, (260, 430), "退出游戏", fgcolor=GOLD, size=50)
    pygame.draw.rect(screen, (0, 0, 0), (650, 65, 520, 600))
    fl.render_to(screen, (700, 180), '   使用 "↑"', fgcolor=WHITE, size=40)
    fl.render_to(screen, (700, 270), '"↓" 键选择模式,', fgcolor=WHITE, size=40)
    fl.render_to(screen, (700, 360), '"←┘" 键确认。', fgcolor=WHITE, size=40)

    """开始界面"""
    while True:
      pygame.draw.rect(screen, (0, 0, 0), (220, single_rect, 26, 31))
      for i in pygame.event.get():
            if i.type == pygame.QUIT:
                sys.exit()
            elif i.type == pygame.KEYDOWN:
                single_rect = single_move(single_rect, i, mode=1)

      pygame.draw.polygon(screen, RED, single_rect)
      pygame.display.update()# 刷新屏幕
      clock.tick(fps)# 游戏时钟


def action(fps=GameSpeed.game_fps_min_speed):
    snake = Snake()
    pygame.draw.rect(screen, (0, 0, 0), (650, 420, 500, 300))
    fl.render_to(screen, (682, 470), '游戏说明:', fgcolor=WHITE)
    fl.render_to(screen, (682, 520), '  使用 "↑" "↓" "←" "→"', fgcolor=WHITE)
    fl.render_to(screen, (682, 570), '键控制方向,长按空格键加速移', fgcolor=WHITE)
    fl.render_to(screen, (682, 620), '动。', fgcolor=WHITE)
    fl.render_to(screen, (682, 620), '      @ 大脑组织残缺', fgcolor=WHITE, size=20)
    action_time = int(pygame.time.get_ticks() / 1000)
    snake.draw_new_food()

    while True:
      """游戏主循环"""

      switch = 0

      for i in pygame.event.get():
            if i.type == pygame.QUIT:
                sys.exit()
            else:
                switch = snake.Speech(i, switch)
                fps = GameSpeed.game_fps_min_speed + int(Snake.long / 15)
                if fps >= GameSpeed.game_fps_high_speed:
                  fps = GameSpeed.game_fps_high_speed
            if i.type == pygame.KEYDOWN:
                if i.key == pygame.K_SPACE:
                  fps = GameSpeed.game_fps_max_speed

      a = snake.move()# 蛇身移动
      Snake.fs = Snake.score - (int(pygame.time.get_ticks() / 1000) - action_time) // 5 * 3
      pygame.draw.rect(screen, (0, 0, 0), (650, 65, 520, 355))
      fl.render_to(screen, (680, 70), "得  分:%5d" % Snake.fs,
                     fgcolor=WHITE, size=60)
      fl.render_to(screen, (682, 270), "当前速度:%2dm/s" % fps, fgcolor=WHITE, size=60)
      fl.render_to(screen, (682, 370), "游戏时长:%4ds" % (int(pygame.time.get_ticks() / 1000) - action_time),
                     fgcolor=WHITE, size=60)
      fl.render_to(screen, (682, 170), "蛇身长度:%4dm" % Snake.long, fgcolor=WHITE, size=60)
      if Snake.center_2_key:
            fl.render_to(screen, (560, 80), str(8 - Snake.big_time + 1), (0, 0, 0), size=40)
            fl.render_to(screen, (560, 80), str(8 - Snake.big_time), (0, 0, 0), size=40)
            fl.render_to(screen, (560, 80), str(8 - Snake.big_time), (250, 250, 0), size=40)
      pygame.display.update()# 刷新屏幕

      clock.tick(fps)# 游戏时钟
      if a == 1:# 判断结束游戏
            write_score()
            over()


def over(fps_s=30):
    """结束界面"""
    single_rect = [, , ]
    fl.render_to(screen, (240, 250), "GAME OVER", fgcolor=GOLD, size=50)
    fl.render_to(screen, (240, 310), "重新开始", fgcolor=WHITE, bgcolor=(0, 0, 0, 60))
    fl.render_to(screen, (240, 360), "返回主页", fgcolor=WHITE, bgcolor=(0, 0, 0, 60))

    while True:
      pygame.draw.rect(screen, (0, 0, 0), (200, single_rect, 26, 31))
      for i in pygame.event.get():
            if i.type == pygame.QUIT:
                sys.exit()
            elif i.type == pygame.KEYDOWN:
                single_rect = single_move(single_rect, i, mode=2)

      pygame.draw.polygon(screen, RED, single_rect)
      pygame.display.update()# 刷新屏幕
      clock.tick(fps_s)# 游戏时钟


def speed_setting():
    """速度设置"""
    single_rect = [[, , ],
                   [, , ]]
    fl.render_to(screen, (250, 110), "初始速度", fgcolor=WHITE, size=50)
    fl.render_to(screen, (250, 250), "最大速度", fgcolor=WHITE, size=50)
    fl.render_to(screen, (250, 390), "加速速度", fgcolor=WHITE, size=50)
    fl.render_to(screen, (250, 530), "返回主页", fgcolor=WHITE, size=50)
    pygame.draw.rect(screen, (0, 0, 0), (650, 65, 520, 600))
    fl.render_to(screen, (700, 150), '   使用 "↑",', fgcolor=WHITE, size=40)
    fl.render_to(screen, (700, 240), '"↓"键选择模式,', fgcolor=WHITE, size=40)
    fl.render_to(screen, (700, 330), '"←","→"键调节,', fgcolor=WHITE, size=40)
    fl.render_to(screen, (700, 420), '"←┘" 键确认。', fgcolor=WHITE, size=40)
    while True:
      pygame.draw.rect(screen, (0, 0, 0), (single_rect, single_rect, 26, 31))
      pygame.draw.rect(screen, (0, 0, 0), (single_rect, single_rect, -26, 31))
      pygame.draw.rect(screen, WHITE, (300, 175, 100, 50))
      pygame.draw.rect(screen, WHITE, (300, 315, 100, 50))
      pygame.draw.rect(screen, WHITE, (300, 455, 100, 50))
      fl.render_to(screen, (340, 186), "%2d" % GameSpeed.game_fps_min_speed, fgcolor=(0, 0, 0), bgcolor=WHITE, size=40)   # 初始速度
      fl.render_to(screen, (340, 326), "%2d" % GameSpeed.game_fps_high_speed, fgcolor=(0, 0, 0), bgcolor=WHITE, size=40)   # 最大速度
      fl.render_to(screen, (340, 466), "%2d" % GameSpeed.game_fps_max_speed, fgcolor=(0, 0, 0), bgcolor=WHITE, size=40)   # 加速速度
      for i in pygame.event.get():
            if i.type == pygame.QUIT:
                sys.exit()
            elif i.type == pygame.KEYDOWN:
                single_rect = single_move(single_rect, i, mode=3)

      pygame.draw.polygon(screen, RED, single_rect)
      pygame.draw.polygon(screen, RED, single_rect)
      pygame.display.update()# 刷新屏幕
      clock.tick(60)# 游戏时钟


def maps(fps=20):
    """地图选择"""
    pygame.draw.rect(screen, (0, 0, 0), (81, 66, 527, 527))
    pygame.draw.rect(screen, (0, 0, 0), (666, 66, 500, 530))
    Snake()
    AllMap.draw_map()
    fl.render_to(screen, (670, 160), '"←" "→"键切换地图,', fgcolor=WHITE, size=40)
    fl.render_to(screen, (670, 260), '空格键切换无墙模式,', fgcolor=WHITE, size=40)
    fl.render_to(screen, (670, 360), '"←┘"键开始游戏,', fgcolor=WHITE, size=40)
    fl.render_to(screen, (670, 460), 'ESC 键返回主页', fgcolor=WHITE, size=40)
    single_rect = [[, , ],
                   [, , ]]
    pygame.draw.polygon(screen, RED, single_rect)
    pygame.draw.polygon(screen, RED, single_rect)

    while True:
      for i in pygame.event.get():
            if i.type == pygame.QUIT:
                sys.exit()
            elif i.type == pygame.KEYDOWN:
                single_move(single_rect, i, mode=4)
      pygame.display.update()# 刷新屏幕
      clock.tick(fps)# 游戏时钟


def high_score(fps=10):
    score_lists = []
    score_fl = open('score_history.txt', 'r+')
    score_str = score_fl.read()
    score_list = re.findall("<([\s\S]*?)>", score_str)
    for i in score_list:
      score_lists.append((int(re.findall("(\d+?),", i)), int(re.findall("long: *(\d+?),", i)), re.findall("time:([\s\S]*?);", i)))
    score_lists.sort(reverse=True)
    score_fl.seek(0)
    for i in score_lists:
      score_fl.write("<score:%5d, long:%3d, time:%s;>\n" % (i, i, i))
    score_fl.close()

    i = 0
    j = len(score_lists)
    if j >= 6:
      j = 6
    while i < j:
      fl.render_to(screen, (105, 100 + i * 78), "NO.%d—分数:%5d 长度:%3d" %
                     (i + 1, score_lists, score_lists), fgcolor=WHITE, size=(40 - i * 2))
      fl.render_to(screen, (180, 140 + i * 76), "时期: %s" % score_lists, fgcolor=WHITE, size=(34 - i * 2))
      i += 1

    while True:
      for i in pygame.event.get():
            if i.type == pygame.QUIT:
                sys.exit()
            elif i.type == pygame.KEYDOWN:
                if i.key == pygame.K_RETURN or i.key == pygame.K_KP_ENTER:
                  pygame.draw.rect(screen, (0, 0, 0), (81, 66, 527, 527))
                  star()
      pygame.display.update()# 刷新屏幕
      clock.tick(fps)# 游戏时钟


def write_score():
    """记录分数"""
    now_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    score_fl = open('score_history.txt', 'a+')
    score_fl.write("<score:%5d, long:%3d, time:%s;>\n" % (Snake.fs, Snake.long, now_time))
    score_fl.close()


AllMap()
AllMap.draw_window(AllMap.WALL)
score_file = open('score_history.txt', 'a+')    # 检测分数记录文件
score_file.close()
star()

大脑组织残缺 发表于 2019-12-16 22:39

ManiManiHong 发表于 2019-11-26 20:42
我能拿去做毕设救急嘛&#128021;

拿去用吧:lol

大脑组织残缺 发表于 2019-7-25 23:58

本帖最后由 大脑组织残缺 于 2019-7-26 00:03 编辑

WuWenNing 发表于 2019-7-25 14:43
没有问题
发现一个bug,有时候会不显示食物,修改代码测试之后发现 有时候食物会随机出现在上一次蛇头传送过的墙边,并且这种食物不能通过边界传送吃到,身体越长越容易出现这个bug。
(虽然已经在随机产生食物之前排除了蛇身所在的位置)
可以把 move(self) 方法内的 # 墙面传送 区块剪切到 # 位置移动区块 后边解决。

isugar 发表于 2020-11-12 07:37

小白路过 学习学习

xuxin56789 发表于 2020-9-23 18:08

看着功能挺全的,好好学习学习。

拆家神犬 发表于 2020-7-24 07:51

这是个可以做毕设的东西{:1_919:}

laoluo来了 发表于 2020-7-22 21:53

感谢大佬分享,虽然看不懂,但还是复制过去玩一下

wdye 发表于 2020-6-5 15:00

做的特别好优秀!赞

zhooou 发表于 2020-4-4 16:46

太厉害了

diyikuai 发表于 2019-12-17 01:58

这个源码技术含量很高。

ManiManiHong 发表于 2019-11-26 20:42

我能拿去做毕设救急嘛&#128021;

forceenable 发表于 2019-7-26 12:37

学习了。。。。。。
页: [1] 2
查看完整版本: 【Python】Pygame模块实现功能超赞的贪吃蛇