用pygame製作貪吃蛇遊戲(詳細)

案例導入

相信我們絕大多數的人都玩過貪吃蛇這款遊戲
今天我們就用python製作這款遊戲
但是首先我們想做它就得弄明白他的實現原理是什麼

基本原理

首先我們要做的這款遊戲界面是很low的,因爲我們做的這款遊戲算是最簡單最入門的一款遊戲
玩過這個遊戲的人都很清楚,這個蛇在行走時的每一個格子都會移動到他前一個格子的位置,類似於這樣一個一個跟隨着往前走,最前面的那個格子是跟隨着腦袋也就是蛇頭往前走,頭跟着你的控制器的方向走,這就實現了一個移動跟隨
在這裏插入圖片描述
因爲是貪吃蛇所以他要吃東西,當它的頭部碰到了食物之後也就是頭和食物重合了,他的尾部就會增加一格,這就是一個進食的過程 本人靈魂畫師請不要介意
其實這就是這個遊戲的核心思想,就幹了這麼兩件事
在這裏插入圖片描述

所需工具

pygame 下載地址

實際操作

廢話不多說,直接動手
第一步 導入模塊
在這裏插入圖片描述
第二步 初始化框架
在這裏插入圖片描述
因爲寬和高要經常用到,所以把它存在一個變量裏面
在這裏插入圖片描述
在我們set_mode的同時會給我們創建一個window對象,我們就可以拿着window對象去顯示了
set_caption設置標題
現在運行就會有個一閃而過的窗口
下面的們的代碼會解決這個問題
我們代碼最重要的部分 遊戲循環
這個循環要一直循環下去,但是不能讓他變成死循環
怎麼解決這個問題呢,首先,這個遊戲是可以結束的,結束的條件就是當用戶點擊退出或者是操作的蛇撞死的時候,這個循環就可以停了
所以我們可以設置一個變量quit=False,讓他一直是false,循環應該結束的時候變成True
其次我們不能讓這個循環一直不停的跑,我們要留出時間來去做一些遊戲的渲染或者其他的一些工作,這些工作都是交給系統的,這裏我們會用到pygame裏面的time.Clock() 這個就是遊戲的時間控制,比如把這個遊戲調成多少幀
在這裏插入圖片描述
在這裏插入圖片描述
現在已經可以出現一個這樣的窗口了

接下來我們還要處理遊戲的一些事件和渲染
我們第一個要處理的事件就是遊戲的退出
在這裏插入圖片描述
pygame.event.get()是獲取到當前事件的隊列
因爲我們要處理這個隊列的所有事件,
一般我們都會設置一個循環,就可以去處理內部一個一個的event

下面要做的就是渲染了,任何一個遊戲都要有渲染的過程

pygame.draw.rect(window,)繪製工具,參數1要說明你要往哪畫,參數2要說明你要畫什麼顏色的東西,參數三要說明你要畫的範圍,從哪開始到哪裏結束
pygame.display.flip() #暫時把控制權交還給系統,讓系統去做一些渲染操作
結果
顯示結果如下:(不要在意它的顏色)
在這裏插入圖片描述
現在已經完成了框架初始化的操作
第三步 繪製場景
在這裏插入圖片描述可以把上面的場景看成一個相對較大的二維數組(學過numpy的同學應該很好理解)
類似於這樣:0 0 0 0 0
0 2 1 1 0
0 0 0 1 1
1代表蛇 2代表食物 每個元素都有一個數據
現在我們需要把這個給體現出來:
在這裏插入圖片描述
先設置這個格子的行和列 行決定了它的縱向 列決定了它的左右位置 現在我們就得到了每個格子有多大 比如: 寬度=總寬度(width)/列(ROW)後面會有用
這裏我弄一個Point對象,讓每一個點是讓行和列組成的
把點的行和列都保存起來 大致是這樣一個功能

下面開始定義座標:
在這裏插入圖片描述
在這裏插入圖片描述
先從蛇的頭開始,蛇頭其實就是一個point對象 我們讓它的初始位置在正中間

然後再定義蛇的食物,因爲蛇的食物是隨機出現的,所以這裏我們用到random模塊
這裏有個小細節,我們要生成食物並且不讓食物生成在蛇的身體裏面,我們可以定義一個函數去解決

下面開始下一步:
在這裏插入圖片描述
但是我們要計算座標位置,在繪圖中我們是不可以使用行和列的,我們獲取到它的位置就要使用上下左右的間距,由此可以推算出左間距=clo*格子的width(可以畫圖仔細理解一波),上間距=row*格子的height
因爲需要執行很多步畫圖操作 所以定義一個函數,這裏其實是將方塊塗色
下面我們就開始畫蛇的部分:
在這裏插入圖片描述
下面是蛇的移動:
比如我們要朝左邊,row不動,clo-=1 右邊就是clo+=1 依次類推
我們可以先定義一個變量表示當前蛇移動的方向 再進行移動判斷

在這裏插入圖片描述
在這裏插入圖片描述
這裏還有一個小細節 就是當你在往左移動時,不能直接朝右邊移動,朝上移動時,不能直接朝下,所以我們加了if判斷
pygame.KEYDOWN 鍵盤摁下事件
event.key是每個鍵的編碼,273->W 119->↑…

下面處理蛇的跟隨移動:
在這裏插入圖片描述
我們可以吧座標以元組的形式放入一個列表,每次移動頭的位置會放對應的方向移動1格(吧原來的頭插入到前面insert),並且尾部會消失pop(因爲頭往前移動了一格),其他不需要變動,只變動頭和尾就可以
在這裏插入圖片描述
爲了方便我們再給point對象添加一個方法 copy,在copy的過程中其實就是創建一個新的point,這樣就可以複製他自己
在這裏插入圖片描述
但是如果蛇吃到食物之後,他是會增加一格的,所以我們這裏判斷一下,如果蛇頭與食物重合,就說明蛇遲到了食物,沒重合就說明沒吃到這個食物,並且每次吃到這個食物,食物又會在隨機位置出現

最後,我們要處理蛇撞到牆壁或者撞到自身之後遊戲結束的操作,其實很簡單,如果蛇頭出現在了格子以外的地方或者蛇頭與蛇的身體重合,就會視爲遊戲失敗,隨即會退出遊戲

做到這裏就告一段落了,其實這個遊戲還有很多地方可以改進,比如添加一個計分系統、失敗後出現重新開始按鈕和開始時出現開始遊戲按鈕等等。。。如果有人需要的話我再後面會加以改進。

下面是源碼

代碼

import pygame
from sys import exit
import random


class Point():
    row = 0
    clo = 0

    def __init__(self, row, clo):
        self.row = row
        self.clo = clo

    def copy(self):
        return Point(row=self.row, clo=self.clo)


# 初始化
pygame.init()
width = 800
hight = 400

ROW = 30
CLO = 40

direct = 'left'
window = pygame.display.set_mode((width, hight))
pygame.display.set_caption('貪吃蛇遊戲')

# 蛇頭座標定在中間
head = Point(row=int(ROW / 2), clo=int(CLO / 2))
# 初始化蛇身的元素數量
snake = [
    Point(row=head.row, clo=head.clo + 1),
    Point(row=head.row, clo=head.clo + 2),
    Point(row=head.row, clo=head.clo + 3)
]


# 生成食物並且不讓食物生成在蛇的身體裏面
def gen_food():
    while 1:
        position = Point(row=random.randint(0, ROW - 1), clo=random.randint(0, CLO - 1))
        is_coll = False
        if head.row == position.row and head.clo == position.clo:
            is_coll = True
        for body in snake:
            if body.row == position.row and body.clo == position.clo:
                is_coll = True
                break
        if not is_coll:
            break
    return position


# 定義座標
# 蛇頭顏色可以自定義
head_color = (0, 158, 128)
# 食物座標
snakeFood = gen_food()
# 食物顏色
snakeFood_color = (255, 255, 0)

snake_color = (200, 147, 158)


# 需要執行很多步畫圖操作 所以定義一個函數
def rect(point, color):
    # 定位 畫圖需要left和top
    left = point.clo * width / CLO
    top = point.row * hight / ROW
    # 將方塊塗色
    pygame.draw.rect(window, color, (left, top, width / CLO, hight / ROW))


quit = True
# 設置幀頻率
clock = pygame.time.Clock()
while quit:
    # 處理幀頻 鎖幀
    clock.tick(30)
    # pygame.event.get()獲取當前事件的隊列 可以同時發生很多事件
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            quit = False
        elif event.type == pygame.KEYDOWN:
            # 這裏小細節蛇不可以直接左右上下 要判斷當前是在什麼狀態下前行
            if event.key == 273 or event.key == 119:
                if direct == 'left' or direct == 'right':
                    direct = 'top'
            if event.key == 274 or event.key == 115:
                if direct == 'left' or direct == 'right':
                    direct = 'bottom'
            if event.key == 276 or event.key == 97:
                if direct == 'top' or direct == 'bottom':
                    direct = 'left'
            if event.key == 275 or event.key == 100:
                if direct == 'top' or direct == 'bottom':
                    direct = 'right'
    # 吃東西
    eat = (head.row == snakeFood.row and head.clo == snakeFood.clo)

    # 處理蛇的身子
    # 1.把原來的頭插入到snake的頭上
    # 2.把最後一個snake刪掉
    if eat:
        snakeFood = Point(row=random.randint(0, ROW - 1), clo=random.randint(0, CLO - 1))
    snake.insert(0, head.copy())
    if not eat:
        snake.pop()

    # 移動一下
    if direct == 'left':
        head.clo -= 1
    if direct == 'right':
        head.clo += 1
    if direct == 'top':
        head.row -= 1
    if direct == 'bottom':
        head.row += 1
    dead = False
    if head.clo < 0 or head.row < 0 or head.clo >= CLO or head.row >= ROW:
        dead = True
    for body in snake:
        if head.clo == body.clo and head.row == body.row:
            dead = True
            break
    if dead:
        print('Game Over')
        quit = False
    # 背景畫圖
    pygame.draw.rect(window, (245, 135, 155), (0, 0, width, hight))

    # 蛇頭
    rect(head, head_color)
    # 繪製食物
    rect(snakeFood, snakeFood_color)
    # 繪製蛇的身子
    for body in snake:
        rect(body, snake_color)

    # 交還控制權
    pygame.display.flip()

希望此文章對你有所幫助,最後謝謝閱讀

PS:pycharm背景圖片
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章