zoukankan      html  css  js  c++  java
  • 基于Pygame的贪吃蛇python小游戏实现

    基于Pygame的贪吃蛇python小游戏实现

    0.前言

    许多程序员入门的第一个项目都会选择贪吃蛇。用贪吃蛇来练手比较合适。因为贪吃蛇的算法并不难,但绝对够有启发作用,也比较经典。相对来说它很容易就能实现。对于新手来说,拿贪吃蛇来作为练习是很有必要的。

    各个语言都会有许多共性,但实现的算法基本都差不多。这里就用Python为例,分析一下算法实现,并附上相应代码。不足之处还请指正。

    1.分类

    python是一门面向对象的程序语言,我们在编写一个项目时要首先根据需要对其进行分类,模块化处理。

    分析得到,需要定义Snake类、Food类、Game类,分别代表蛇、食物、游戏规则。然后对类定义成员方法,比如Snake类需要进行拐弯、增加、减少等操作。

    Food类
    //Author:xiaobei
    
    import random
    
    class Food(object):
        def __init__(self,r_pos,color,state):
            self.r_pos = r_pos
            self.color = color
            self.state = state
        def update(self,snake,sound_effect):
            if self.r_pos in snake.body:
                self.state = 1
            else:
                self.state = 0
            if self.state == 1:
                self.r_pos = [random.randrange(30,720,30),random.randrange(30,540,30)]
                self.color = random.choice([(255,255,0),(255,0,255),(0,255,255)])
                snake.length+=1
                sound_effect.play()
    Snake类
    //Author:xiaobei
    
    Snake(object):
        def __init__(self,length,body,direction,direction_change,head_pos,end):
            self.length = length
            self.body = body
            self.direction = "RIGHT"
            self.direction_change = "RIGHT"
            self.head_pos = head_pos
            self.end = False
    
    #控制蛇的爬行
        def move(self):
            if self.length > len(self.body):
                self.body.append([0,0])
            for i in range(self.length-1,0,-1):
                self.body[i][0] = self.body[i-1][0]     #这里多重列表互相赋值不能整体,因为最外层代表首地址,即首元素,因此要分开赋值
                self.body[i][1] = self.body[i-1][1]
            if self.direction == "LEFT" :
                self.body[0][0]-=30
            elif self.direction == "RIGHT":
                self.body[0][0]+=30
            elif self.direction == "UP":
                self.body[0][1]-=30
            else:
                if self.direction == "DOWN":
                    self.body[0][1]+=30
    
    #控制不让贪吃蛇溢出
            if self.head_pos[0]>850:
    
                self.end = True
            elif self.head_pos[1] > 650:
    
                self.end = True
            elif self.head_pos[0] < -30:
    
                self.end = True
            else:
                if self.head_pos[1]<-30:
                    self.end = True
    
    
        def turn(self):
            if self.direction_change == "LEFT" and self.direction != "RIGHT":
                self.direction = self.direction_change
            elif self.direction_change == "RIGHT" and self.direction != "LEFT":
                self.direction = self.direction_change
            elif self.direction_change == "UP" and self.direction != "DOWN":
                self.direction = self.direction_change
            else :
                if self.direction_change == "DOWN" and self.direction != "UP":
                    self.direction = self.direction_change

    这里偷了一个懒,没有定义Game类,我把游戏规则掺进了主程序main()中。

    2.主要算法

    (1)控制贪吃蛇拐弯

    用pygame产生一个界面,我们把这个界面当做一个坐标网格,蛇身是一个坐标列表。用蛇头坐标作为蛇的行进方向,控制蛇身整体的方向。难点在于如何使蛇身在转弯的时候,使蛇身每一部分逐个而不是整体转向呢?

    for i in range(self.length-1,0,-1):
                self.body[i][0] = self.body[i-1][0]     #这里多重列表互相赋值不能整体,因为最外层代表首地址,即首元素,因此要分开赋值
                self.body[i][1] = self.body[i-1][1]
    

    这里我们采用一个循环,从尾部开始,只有蛇头在变动,后面的所有部分都在被蛇头牵连着动。假设有n个结点,nn-1 = nn,……,n2 = n1 .依次移动,形成一个拐弯效果。

    (2)食物的刷新

    食物刷新位置是在,蛇吃到食物之后才激发。所以重点在于如何判断是否吃到食物。这里有一个易错点:容易使食物坐标和蛇头的坐标永不吻合的的情况。这是因为蛇的坐标间隔以及食物刷新间隔位置,不是以同一递增/递减公差q进行的。

    def update(self,snake,sound_effect):
        if self.r_pos in snake.body:
            self.state = 1
        else:
            self.state = 0
        if self.state == 1:
            self.r_pos = [random.randrange(30,720,30),random.randrange(30,540,30)]
            self.color = random.choice([(255,255,0),(255,0,255),(0,255,255)])
            snake.length+=1
            sound_effect.play()
    

    在此基础上,当蛇头坐标与食物坐标吻合,便激发食物刷新位置。

    (3)游戏结束条件

    游戏结束条件无非两种:一是蛇头与自身重合,二十蛇头触到边界。这两种方法同样是通过坐标判断来实的。

    if snake.head_pos in snake.body[1:] or snake.end:
        screen.blit(text2Image,(200,200))
        pygame.mixer.music.stop()
        sound_end.play()
        pygame.display.update()
        time.sleep(5)
        pygame.quit()
        sys.exit()
    

    3.界面实现与主函数

    界面实现依靠pygame第三方库来执行,pygame库的安装可以用pip命令行来实现,在控制台进行。

    pip install -U pygame

    参数-U是安装game为最新版。

    pygame的使用请参考《Python 游戏开发—Pygame 快速入门》

    主要代码如下:

    //Author:xiaobei
    
    import pygame
    import os
    import sys
    import time
    import random
    from pygame.locals import *
    from Snake import Snake
    from Food import Food
    
    pygame.init()
    
    #混音器初始化
    pygame.mixer.init()
    
    #加载音效
    sound_effect = pygame.mixer.Sound("C:\Windows\media\Windows Proximity Notification.wav")
    sound_end = pygame.mixer.Sound("C:\Windows\media\Ring07.wav")
    pygame.mixer.music.load("C:\Windows\media\flourish.mid")
    pygame.mixer.music.set_volume(0.5)
    sound_effect.set_volume(1)
    pygame.mixer.music.play(-1) #-1控制无限循环
    
    #设置游戏时钟
    clock = pygame.time.Clock()
    
    #设置主窗体相对位置、大小,标题、背景颜色
    os.environ["SDL_VIDEO_WINDOW_POS"] = "%d,%d"%(50,50)
    screen = pygame.display.set_mode((820,620))
    screen.fill([255,235,100])
    pygame.display.set_caption("贪吃蛇小游戏")
    
    #设置文本
    pygame.font.init
    text1 = pygame.font.Font(None,35)
    text1Image = text1.render("SCORE:",True,[100,125,255])
    text2 = pygame.font.Font(None,120)
    text2Image = text2.render("Gameover",True,[100,125,255])
    text3 = pygame.font.Font(None,35)
    text4 = pygame.font.Font(None,35)
    screen.blit(text1Image,(5,5))
    
    
    
    #创建贪吃蛇对象、食物等对象
    snake = Snake(length = 3,body = [[120,90],[90,90],[60,90]],direction = "RIGHT",direction_change ="RIGHT", head_pos = [120,100],end = False)
    food = Food(r_pos = [120,420],color = (100,255,100),state = 0)
    
    
    score = 0
    
    #进入循环
    while True:
    #设置帧率刷新速度
        clock.tick(5)
    
    #设置窗口便于刷新
        screen = pygame.display.set_mode((820,620))
        screen.fill([255,235,100])
    
    #绘制文本“分数”
        score = len(snake.body)-3
        screen.blit(text1Image,(5,5))
        text3Image = text3.render("{}".format(score),True,[100,125,255])
        screen.blit(text3Image,(120,5))
    
    #绘制文本“时间”
        text4Image = text4.render("time: {} seconds".format(int(time.clock())),True,[100,125,255])
        screen.blit(text4Image,(200,5))
    
    #绘制蛇身、食物
        food_circle = pygame.draw.rect(screen,food.color,(food.r_pos[0],food.r_pos[1],28,28),0)
        for i in range(snake.length):
            snake_rent = pygame.draw.rect(screen,(120,255,205),(snake.body[i][0],snake.body[i][1],28,28),0)
    
    
    
    #设置退出条件
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
    
    #获取键盘事件
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    snake.direction_change = "LEFT"
                elif event.key == pygame.K_RIGHT:
                    snake.direction_change = "RIGHT"
                elif event.key == pygame.K_UP:
                    snake.direction_change = "UP"
                else:
                    if event.key == pygame.K_DOWN:
                        snake.direction_change = "DOWN"
    
    
    #控制蛇的转向
        snake.head_pos = snake.body[0]
        food.update(snake,sound_effect)
        snake.move()
        snake.turn()
    
    #游戏结束
        if snake.head_pos in snake.body[1:] or snake.end:
            screen.blit(text2Image,(200,200))
            pygame.mixer.music.stop()
            sound_end.play()
            pygame.display.update()
            time.sleep(5)
            pygame.quit()
            sys.exit()
    #刷新界面
        pygame.display.update()

    4.说明

    我把每个类模块独立为单个文件,把它们放在同一项目文件夹下,然后在主程序中调用它们,主程序也是一个文件,直接运行主文件即可运行程序。(不好意思,这里又偷了一个懒,嘿嘿!)

    运行界面如下:运行效果界面
    主程序中有背景音乐和音效的绝对路径引用,读者可自行忽略删改。恭喜,到这里一个贪吃蛇小程序大功告成!

    不当之处,还望指正,谢谢。

  • 相关阅读:
    流的概念(转自本站progor)
    Centos7安装OpenLDAP
    python发送post请求
    小计安装部署滴滴开源kafkamanager工具
    VSCode集成Cmder控制台输入中文乱码
    在win10的pycharm使用wsl中的python进行开发
    《Python数据科学手册》学习笔记及书评
    VSCode小说插件ReadNovel根据内容查找页码
    《TensorFlow实战Google深度学习框架(第二版)》学习笔记及书评
    Cmder启动WSL中的Ubuntu出现复制粘贴异常
  • 原文地址:https://www.cnblogs.com/slz99/p/12527753.html
Copyright © 2011-2022 走看看