Python實戰練習_貪吃蛇 (pygame的初次使用)


正如標題所寫的那樣,我將一步步的完成本次實戰練習——貪吃蛇。廢話不多說,感興趣的伙伴可以一同挑戰一下。

首先說明本次實戰中我的配備:

開發環境:python 3.7;

開發工具:pycharm2019.2.2;

開發模塊:pygame;

首先在本次開發中,我們要借用一下pygame模塊,那么問題來了,什么是pygame模塊?有什么用?

pygame 是包含圖像、聲音建立在SDL基礎上,允許實時電子游戲研發而無需被低級語言(如機器語言和匯編語言)束縛。

基於這樣一個設想,所有需要的游戲功能和理念都(主要是圖像方面)都完全簡化為游戲邏輯本身,所有的資源結構都可以由高級語言提供,如Python。

我個人理解 pygame是一個簡化2d游戲開發的開發模塊。

本次開發的第一步便是裝載pygame,具體方法如下

1.通過在python文件中 打開命令提示 輸入對應代碼

 

2.pycharm軟件 可以通過設置內,添加新模塊

確保安裝完成可以在命令提示符中打開python  輸入 import pygame檢測 如下所示

有需要的話,可以通過留言,我在下一期博客中專門做一個pygame安裝教程。

接下來便是我們的開發之旅:

首先展示一下我們的效果圖,由一個個大小為20*20的方塊兒組成的貪吃蛇游戲

1.調用python開發環境,包括pygame、sys、random。

# python 運行時的環境
import pygame, sys, random

 

2.調用pygame相關常量、還有配置顏色。

# 這個模塊包含所有pygame所使用的常量
from pygame.locals import *
# 定義顏色變量
# 目標方塊兒紅顏色
redColor = pygame.Color(255, 0, 0)
# 背景顏色為黑色
blackColor = pygame.Color(0, 0, 0)
# 蛇顏色為白色
whiteColor = pygame.Color(255, 255, 255)

 

3.定義游戲結束的函數  主要包含兩部分操作,第一部分為pygame結束,第二部分為sys結束。

# 定義游戲結束
def gameOver():
    pygame.quit()
    sys.exit()

 

4.有了前面的鋪墊,我們可以正式開始設計我們的游戲,我將游戲內容存放到main函數中。

4.1初始化pygame,設定變量來控制蛇的速度,然后制作一個界面,界面的大小為640*480,界面標題為貪吃蛇。

其中界面大小是必須設定的,貪吃蛇游戲的規則之一便是不能觸及邊界,但界面的標題是可以不寫的,界面標題默認為python文件名

特別注意pygame.display.set_mode()函數中需要插入為兩項序列而不是整數型  所以參數應為(640, 480)

具體代碼如下

def main():
    # 初始化pygame
    pygame.init()
    # 定義一個變量 控制速度
    fpsClock = pygame.time.Clock()
    # 創建一個窗口界面,界面大小為640*480
    playSurface = pygame.display.set_mode((640, 480))
# 界面標題為“貪吃蛇” 可不寫,默認為python文件名 pygame.display.set_caption(
'貪吃蛇')

 

4.2設定目標方塊

目標方塊是由計算機隨機生成的,但在那之前需要我們手動設定一個初值,同時設定一個target_flag來判斷目標方塊是否被貪吃蛇 “吃” 掉

    # 初始化目標方塊的位置
    targetPosition = [300, 300]
    # 目標方塊標記 判斷貪吃蛇是否吃掉目標方塊 1為沒吃掉 0為吃掉
    targetFlag = 1

 

4.3設定貪吃蛇的相關屬性

初始化蛇需要注意什么?首先蛇的位置,其次蛇的長度,最后便是蛇的方向。那么一步步來實現

我們可以將蛇看做兩部分組成組成,蛇頭和蛇身。蛇身只要不斷跟隨蛇頭便可,蛇頭需要用來判斷貪吃蛇的前進方向、是否結束游戲、是否 “吃” 掉目標方塊兒等等

我們設定蛇頭以(100, 100)為基准,蛇為水平方向放置,並且向右前進,所以蛇身的第一部分 應等於蛇頭的’“Y”值,而“X”應當減去一個方塊兒的位置,也就是減少20,貪吃蛇第一塊應當是(80, 100)

設定存在方向的變量direction,初始方向向右,也需要設定改變方向的變量changedirection,令changedirection == direction

所寫代碼如下

    # 初始化貪吃蛇的位置 (100,100)為基准
    # 初始化貪吃蛇長度 列表中有幾個元素 就有幾個身體
    snake_head = [100, 100]
    snake_body = [[80, 100], [60, 100]]


    # 初始化方向 默認為右
    direction = 'right'
    # 定義一個認為控制的方向的變量
    changedirection = direction

 

4.4需要貪吃蛇動起來

特別說明 pygame的所有事件全都在一個實時循環中

由於操作比較簡單,鼠標操作的便只有一個,點擊右上角的叉叉關閉游戲,但鍵盤上的操作相對比較多 包括↑↓←→,控制蛇的移動,esc退出游戲

所以首先要判斷發生的事件類型是點擊QUIT ,又或者是KEYDOWN

QUIT不必說,游戲結束之前上面也有描述 pygame.quit() 與sys.exit()

KEYDOWN 就需要判斷是上下左右的哪一個,發生按鍵要使得蛇的移動方向發生改變,所以changedirection 需要發生變動,更改為按鍵方向。

 

# pygame 所有事件全部放到一個實時循環中
    while True:
        # 從隊列中獲取事件
        for event in pygame.event.get():

            if event.type == QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == KEYDOWN:
                if event.key == K_RIGHT:
                    changedirection = 'right'
                if event.key == K_LEFT:
                    changedirection = 'left'
                if event.key == K_UP:
                    changedirection = 'up'
                if event.key == K_DOWN:
                    changedirection = 'down'
                if event.key == K_ESCAPE:
                    pygame.event.post(pygame.event.Event(QUIT))

 

蛇的移動方向由direction決定,按鍵改變的是changedirection,所以我們需要將changedirection的值賦予direction

眾所周知,貪吃蛇是不可以走回頭路的,也就是說當貪吃蛇向右移動,按左鍵是沒喲效果的

所以在將changedirection的值賦予direction 之前 還需要判斷兩個值是否相反

 

# 確定方向
        if changedirection == 'left' and not direction == 'right':
            direction = changedirection
        if changedirection == 'right' and not direction == 'left':
            direction = changedirection
        if changedirection == 'up' and not direction == 'down':
            direction = changedirection
        if changedirection == 'down' and not direction == 'up':
            direction = changedirection

 

 

 

4.5貪吃蛇轉彎

就像上文提到的那樣,蛇身是跟着蛇頭運動,所以轉彎實際上是改變蛇頭的位置。

將蛇身與蛇頭分開來寫相對來說這時候比較占優勢,只要改變蛇頭snake_head的位置信息就可以。

並不是說蛇頭和蛇身必須分開寫,也可以放在一起,我們只需要多寫一步 提取蛇的第一個方塊信息就可以了

那么問題來了,怎么改變蛇頭位置信息才能達到轉彎的效果?

我們以蛇在向右移動,這時按↓鍵為例

蛇頭這時候應當向下移動一個方塊的位置,也就是說這時候蛇頭的“X”不發生改變,“Y”值增加一個方塊的數值,也就是20

同理可得蛇頭向上等操作的方法,注意snake_head是一個數組 ,snake_head[0]即為“X”  snake_head[1]即為“Y”

代碼如下

# 根據方向移動蛇頭
        if direction == 'right':
            snake_head[0] += 20
        if direction == 'left':
            snake_head[0] -= 20
        if direction == 'up':
            snake_head[1] -= 20
        if direction == 'down':
            snake_head[1] += 20

 

4.5貪吃蛇吃方塊

貪吃蛇游戲的目的便是控制貪吃蛇“吃”掉方塊兒,那么怎樣來實現呢?

首先蛇的嘴巴長在蛇頭上,所以蛇吃掉方塊需要用到蛇頭的位置信息。

其次目標方塊兒存放在指定位置,所以當蛇頭的位置信息等於目標方塊兒的位置信息即可

位置信息包含x與y,所以當蛇頭x=目標方塊兒x,並且蛇頭y=目標方塊兒y時,我們便認定貪吃蛇吃了方塊

之前設定判斷目標方塊的狀態變量 targetflag便起到作用,1表示沒吃,0表示吃了,所以targetflag從1變成了0

# 如果貪吃蛇位置和目標方塊位置重合
        if snake_head[0] == targetPosition[0] and 
        snake_head[1] == targetPosition[1]:
            
            targetFlag = 0

        else:
            snake_body.pop()            

 

4.6重新生成新的目標方塊

當判斷目標方塊兒被吃了,也就是說targetflag=0時,系統需要重新生成一個新的目標方塊。

目標方塊的設定相對來說比較簡單,只需要生成一個新的位置信息並將targetflag=1即可。

目標方塊將會出現在一個隨機的位置,所以我們在這里需要引入一個隨機數,這也是為什么剛開始開發游戲時,需要import random

由於一個方塊的大小為20*20,游戲界面為640*480,所以x的取值范圍只有(20/20, 640/20)即為(1, 32)

同理可得y的取值范圍應當是(1,24)  所以隨機生成的目標方塊兒位置信息應當為(x*20, y*20)

輸入的位置信息應當為整數類型,所以還需要加強轉,代碼如下

     if targetFlag == 0:
            x = random.randrange(1, 32)
            y = random.randrange(1, 24)
            targetPosition = [int(x * 20), int(y * 20)]
            targetFlag = 1

 

5.界面生成

寫到這里,游戲的規則基本完成,接下來我們需要“畫”出我們的界面

首先給自己的游戲界面填充為黑色,借用playSurface.fill()函數,將黑色的參數傳入

之后就是畫我們的貪吃蛇,用for循環畫每一部分的身子,利用pygame中draw所帶的Rect函數來繪畫方塊   rect函數需要傳四個參數

第一個為surface,需要制定一個surface編輯區域

第二個為color,即繪畫的顏色,這個很好理解

第三個為rect,rect為繪畫矩形,需要提供矩形的位置,長度,寬度

第四個為width,這並不代表寬度,而是特指線條的粗細, width=0實心,width=1空心 ,一般可以不傳入,默認為0

然后便是畫目標方塊,原理如上所示,但不需要用到for循環,畢竟就一個目標方塊兒

最后開啟實時更新界面

 # 填充背景顏色
        playSurface.fill(blackColor)

        for position in snake_body:
            # rect函數內
            # 第一個參數surface  指定一個surface編輯區
            # 第二個參數color    指定顏色
            # 第三個參數rect     返回一個矩形包含位置信息(x,y),(width,height)
            # 第四個參數width    表示線條的粗細 width=0 實心  width=1 空心
            # 畫蛇
            pygame.draw.rect(playSurface, whiteColor, Rect(position[0], position[1], 20, 20))
            # 畫目標方塊兒
            pygame.draw.rect(playSurface, redColor, Rect(targetPosition[0], targetPosition[1], 20, 20))

        # 更新顯示到屏幕
        pygame.display.flip()

 

6.游戲結束條件

當貪吃蛇撞擊到邊界時便會觸發游戲結束,也就是蛇頭的位置超過了預定的640*480的界面,這時候游戲結束

# 判斷游戲結束
        if snake_head[0] > 620 or snake_head[0] < 0:
            gameOver()
        if snake_head[1] > 460 or snake_head[1] < 0:
            gameOver()

 

7.調控難度

調控難度主要是更改貪吃蛇的速度,之前有設定貪吃蛇速度的變量,這時候我們只要加以修改即可,個人比較手殘,開三擋即可,有興趣的小伙伴可以嘗試下更高的難度

# 控制游戲速度
        fpsClock.tick(3)

 

8.開啟游戲,啟動main函數

# 啟動入口 main函數
if __name__ == '__main__':
    main()

 

至此就開發完成了一個簡單的像素貪吃蛇,下面便是游戲最終效果

由於種種原因,最后有些地方沒來得及改進,所以也算給諸位留下一些難題。

過段時間我會重新更新更加完善、更加豐富的貪吃蛇項目

改進方案:

1.可以加入分數體系,在每次吃到目標方塊兒后分數加一,最終在結束后呈現給玩家

2.貪吃蛇游戲結束條件:蛇頭碰到自己身體,游戲結束未實現

3.界面過於簡單,可以制作一個簡單的游戲開始界面,或者在游戲結束后創建一個排名榜,重來一次等

4.部分代碼跨度較大 顯得冗長,建議精簡重新構建框架

最后顯示源代碼,以供各位參考

# python 運行時的環境
import pygame, sys, random

# 這個模塊包含所有pygame所使用的常量
from pygame.locals import *

# 定義顏色變量

# 目標方塊兒紅顏色
redColor = pygame.Color(255, 0, 0)
# 背景顏色為黑色
blackColor = pygame.Color(0, 0, 0)
# 蛇顏色為白色
whiteColor = pygame.Color(255, 255, 255)


# 定義游戲結束
def gameOver():
    pygame.quit()
    sys.exit()


# 定義main函數 定義入口函數
def main():
    # 初始化pygame
    pygame.init()
    # 定義一個變量 控制速度
    fpsClock = pygame.time.Clock()
    # 創建一個窗口界面
    playSurface = pygame.display.set_mode((640, 480))
    pygame.display.set_caption('貪吃蛇')

    # 初始化目標方塊的位置
    targetPosition = [300, 300]
    # 目標方塊標記 判斷貪吃蛇是否吃掉目標方塊 1為沒吃掉 0為吃掉
    targetFlag = 1


    # 初始化貪吃蛇的位置 (100,100)為基准
    # 初始化貪吃蛇長度 列表中有幾個元素 就有幾個身體
    snake_head = [100, 100]
    snake_body = [[80, 100], [60, 100]]


    # 初始化方向 默認為右
    direction = 'right'
    # 定義一個認為控制的方向的變量
    changedirection = direction

    # pygame 所有事件全部放到一個實時循環中
    while True:
        # 從隊列中獲取事件
        for event in pygame.event.get():

            if event.type == QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == KEYDOWN:
                if event.key == K_RIGHT:
                    changedirection = 'right'
                if event.key == K_LEFT:
                    changedirection = 'left'
                if event.key == K_UP:
                    changedirection = 'up'
                if event.key == K_DOWN:
                    changedirection = 'down'
                if event.key == K_ESCAPE:
                    pygame.event.post(pygame.event.Event(QUIT))
        # 確定方向
        if changedirection == 'left' and not direction == 'right':
            direction = changedirection
        if changedirection == 'right' and not direction == 'left':
            direction = changedirection
        if changedirection == 'up' and not direction == 'down':
            direction = changedirection
        if changedirection == 'down' and not direction == 'up':
            direction = changedirection

        # 根據方向移動蛇頭
        if direction == 'right':
            snake_head[0] += 20
        if direction == 'left':
            snake_head[0] -= 20
        if direction == 'up':
            snake_head[1] -= 20
        if direction == 'down':
            snake_head[1] += 20

        # 增加蛇的長度
        snake_body.insert(0, list(snake_head))

        # 如果貪吃蛇位置和目標方塊位置重合
        if snake_head[0] == targetPosition[0] and snake_head[1] == targetPosition[1]:
            targetFlag = 0

        else:
            snake_body.pop()

        if targetFlag == 0:
            x = random.randrange(1, 32)
            y = random.randrange(1, 24)
            targetPosition = [int(x * 20), int(y * 20)]
            targetFlag = 1

        # 填充背景顏色
        playSurface.fill(blackColor)

        for position in snake_body:
            # rect函數內
            # 第一個參數surface  指定一個surface編輯區
            # 第二個參數color    指定顏色
            # 第三個參數rect     返回一個矩形包含位置信息(x,y),(width,height)
            # 第四個參數width    表示線條的粗細 width=0 實心  width=1 空心
            # 畫蛇
            pygame.draw.rect(playSurface, whiteColor, Rect(position[0], position[1], 20, 20))
            # 畫目標方塊兒
            pygame.draw.rect(playSurface, redColor, Rect(targetPosition[0], targetPosition[1], 20, 20))

        # 更新顯示到屏幕
        pygame.display.flip()

        # 判斷游戲結束
        if snake_head[0] > 620 or snake_head[0] < 0:
            gameOver()
        if snake_head[1] > 460 or snake_head[1] < 0:
            gameOver()
        # 控制游戲速度
        fpsClock.tick(3)


# 啟動入口 main函數
if __name__ == '__main__':
    main()

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM