pygame国游up程序员

贪吃蛇(三)

2017-08-14  本文已影响167人  lovetianyats

上一期,我们基本上完成了我们的贪吃蛇游戏。但是任然存在一些小问题:

  1. 游戏一打开,我们的小蛇就开始跑了,没有任何的提示,而且游戏结束之后,窗口就被直接关闭了,很不友好。

  2. 游戏没有评分,没有等级什么的,用户不知道自己到底在什么水平上。

好的,本期我们就来解决这两个问题。

原先我们的设计是:无论用户是按关闭按钮还是小蛇死亡,我们都置running=False,也就是游戏退出,而不是游戏结束。这明显是不合理的,我们只有在用户按关闭按钮的时候才应该退出,而再其他情况下应该使本局游戏结束,但用户仍然可以开始下一局。这里我们引入另外一个变量game_is_over,用于标注本局游戏结束。

在本局游戏结束之后,如果用户需要重新开始新一局游戏,我们可以重新初始化游戏中用到的用于存储游戏状态的数据,从而开始新的一局游戏。 为了方便,我们可以将初始化用户状态变量的语句用一个函数封装起来,再将这边变量及函数用一个GameStatus类封装起来,这样可以使我们的游戏代码更加清晰,更容易重构。

为了方便,我们提示用户按任意键可以开始游戏。

GameStatus

首先,我们将原先定义为全局变量的状态,放在一个类GameStatus里面,再定义一个实例用于保存当前状态

class GameStatus():
    def __init__(self):
        self.reset_game_status()

    # 重置所有的状态为初始态
    def reset_game_status(self):
        self.food_pos = generate_food()
        self.direction = D_LEFT
        self.game_is_over = True
        self.running = True
        self.hardness = HARD_LEVEL[0]

        # 每次小蛇身体加长的时候,我们就将身体的位置加到列表末尾
        self.snake_body = [(int(GRID_WIDTH_NUM / 2) * CUBE_WIDTH,
                            int(GRID_HEIGHT_NUM / 2) * CUBE_WIDTH)]

# 定义一个类的实例,用于保存当前游戏状态
status = GameStatus()

这样的话,我们原先用的到一些状态,比如running/direction 等等,只要在变量面前加上 [status.] 就好了也就是 status.running/status.direction 是不是很简单~~

开始、结束界面

改完状态类之后,我们还需要绘制两个界面,一个开始界面,一个结束界面。开始界面我么显示“欢乐贪吃蛇“,”按任意键开始游戏“。结束界面,我们显示”你挂了“。OK,我们开始吧!

文字输出

由于要在屏幕上输出文字,我么需要指定字体,所以首先我们获取一个字体(这里我已经提前把字体放到了font目录下面):

font_name = os.path.join(base_folder, 'font/font.ttc')
font = pygame.font.Font(font_name, size)

定义好字体之后我们需要把我们需要显示的文字用我们选定的字体“写”出来,这个写出来的字呢,我们可以将它放到屏幕的任何地方哦~,就像之前我们导入的图片一样,只需要指定一个位置,我们就可以将图片复制过去

text_surface = font.render(text, True, color)

上面那行代码中,text是我们需要显示的文字。

结下来我们需要获取我们文字所在的矩形,并且将矩形的中心,设置到我们想要的位置,当然你也可以选择其他对齐的方式,大家可以参考pygame的文档。最后就是将其画到屏幕上了,所用到的函数和我们画图片时的一样,也是blit,ok,看一下我们的函数

def show_text(surf, text, size, x, y, color=WHITE):
    font_name = os.path.join(base_folder, 'font/font.ttc')
    font = pygame.font.Font(font_name, size)
    text_surface = font.render(text, True, color)
    text_rect = text_surface.get_rect()
    text_rect.midtop = (x, y)
    surf.blit(text_surface, text_rect)

接下来,欢迎界面就简单多了

def show_welcome(screen):
    show_text(screen, u'欢乐贪吃蛇', 30, WIDTH / 2, HEIGHT / 2)
    show_text(screen, u'按任意键开始游戏', 20, WIDTH / 2, HEIGHT / 2 + 50)

结束界面,只需要打印几个字,并加一下延迟

show_text(screen, u'你挂了', 30, WIDTH / 2, HEIGHT / 2)
          pygame.display.update()
          pygame.time.delay(2000)

好了,各个部件都已经完成了,我们来修改一下游戏逻辑,在检测到有按钮按下时,我们需要判断一下游戏是否还没有开始,如果没有开始我们就需要,将游戏状态置为开始。并且游戏没有开始的时候,我们不需要更新屏幕

for event in pygame.event.get():
    if event.type == pygame.QUIT:
        status.running = False
    elif event.type == pygame.KEYDOWN:      # 如果有按键被按下了
        # 如果本局游戏已经结束(或者没有开始),那么按任意键开始游戏
        if status.game_is_over:
            # 重置游戏状态
            status.reset_game_status()
            status.game_is_over = False
            break

# ................................................................................

if status.game_is_over:
    show_welcome(screen)
    pygame.display.update()

    如果游戏还没有开始,接下来的操作就没有必要进行了
    continue

大功告成!!

我们开一下效果~


game_start.png

评分

现在我们来解决下一个问题 --- 评分

我们在屏幕右端添加一个宽为200px的区域用于展示分数和当前我们的 level

SCREEN_WIDTH = WIDTH + 200

然后更改一下我们的画布

# 设置画布
screen = pygame.display.set_mode((SCREEN_WIDTH, HEIGHT))

这样我们的屏幕就变宽了~

我们在GameStatus类中添加一个score字段用于存储当前的得分,每次小蛇吃到一个事物我们就加点分数

class GameStatus():
    def __init__(self):
        self.reset_game_status()

    # 重置所有的状态为初始态
    def reset_game_status(self):
        # ...
        self.score = 0

然后再定义一个展示分数的函数

def show_scores(screen, status):
    show_text(screen, u'级别: {}'.format(status.hardness), CUBE_WIDTH,
        WIDTH + CUBE_WIDTH * 3, CUBE_WIDTH * 4)

    show_text(screen, u'得分: {}'.format(status.score), CUBE_WIDTH,
        WIDTH + CUBE_WIDTH * 3, CUBE_WIDTH * 6)

OK!现在来修改一下我们主函数

# 如果吃到了食物我们就产生一个新的食物
if got_food:
    status.score += status.hardness

# 每次刷新屏幕前加上刷新分数的函数调用
show_scores(screen, status)

好的~ 我们看一下最终效果~


snake-v2.png

我们的贪吃蛇又进一步完善了~

完整的代码可以去我的 github 看,点击这里进入GitHub。
如果这篇文章对您有帮助,赞赏一下吧~

您的支持是我继续创作的动力~~~

上一篇下一篇

猜你喜欢

热点阅读