案例導入
相信我們絕大多數的人都玩過貪吃蛇這款遊戲
今天我們就用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背景圖片