python實(shí)戰(zhàn)之利用pygame實(shí)現(xiàn)貪吃蛇游戲(二)
一、前言
在上一篇博客中,我們實(shí)現(xiàn)了基本的界面搭建,這次實(shí)現(xiàn)一下邏輯部分。
二、創(chuàng)建蛇
首先,先分析一下蛇的移動(dòng),不然我們一定會(huì)吃虧的(別問,問就是自己寫了一堆無效代碼)。
蛇的移動(dòng)其實(shí)并沒有想象中那樣復(fù)雜,每一個(gè)模塊都需要有一個(gè)方向,按照方向進(jìn)行移動(dòng)。
其實(shí)實(shí)際上就是一個(gè)出隊(duì)的感覺,即每一個(gè)元素都取代上一個(gè)元素的位置,然后再按照貪吃蛇當(dāng)前的方向,移動(dòng)一下頭節(jié)點(diǎn)即可。
snake.py:
""""🐍類""" import pygame class Snake(): def __init__(self,snake_color,snake_head_color,x,y,lattice_wh): self.color = snake_color self.head_color = snake_head_color # 格子的左上角坐標(biāo) self.pos = (x,y) self.lattice_wh = lattice_wh self.rect = pygame.Rect(x,y,self.lattice_wh,self.lattice_wh) self.move_distance = { 0:(0,0), 1:(0,-self.lattice_wh), 2:(0, self.lattice_wh), 3:(-self.lattice_wh,0), 4:( self.lattice_wh,0) } def move(self,direction): self.rect.x += self.move_distance[direction][0] self.rect.y += self.move_distance[direction][1] def forecast(self,direction): return (self.rect.x+self.move_distance[direction][0], self.rect.y+self.move_distance[direction][1])
創(chuàng)建蛇,需要給一個(gè)位置(坐標(biāo)),同時(shí)也需要輸入一個(gè)顏色。
這里為了區(qū)分頭節(jié)點(diǎn),我傳入了兩個(gè)顏色,一個(gè)為頭節(jié)點(diǎn)的顏色,另一個(gè)為身子部分的顏色。
(其實(shí)顏色不需要給在這里,在update傳入一個(gè)即可)
蛇的主要部分就是移動(dòng),這里我給出了兩個(gè)方法:
1.移動(dòng)方法,是針對頭節(jié)點(diǎn)的移動(dòng)
2.預(yù)測移動(dòng)位置方法,是判斷下一步蛇的移動(dòng)的位置,看看是否會(huì)撞到自己/墻壁,或者吃到食物。
為了方便我們針對方向進(jìn)行處理,我使用了哈希的方式(其實(shí)就是字典),將每一個(gè)方向移動(dòng)一次(x,y)坐標(biāo)變化量記錄好。
【那個(gè)方向0,是最開始我們的蛇是固定的,所以我添加了一個(gè)(0,0)】
最開始,我們在main文件中創(chuàng)建一個(gè)snakes列表,來存儲(chǔ)所有的蛇節(jié)點(diǎn),并且添加了最開始的兩個(gè)節(jié)點(diǎn)(頭和第一部分的身子)
# 蛇頭&1個(gè)蛇身 snakes = [] snakes.append(Snake(snake_color,snake_head_color,lattice_wh,24*lattice_wh,lattice_wh)) snakes.append(Snake(snake_color,snake_head_color,0,24*lattice_wh,lattice_wh))
效果:
(主要是左下角的兩個(gè)方塊,紫色為頭,綠色為身子,我是寫完了才寫的博客)
三、創(chuàng)建食物
這部分,主要就是隨機(jī)生成一個(gè)位置,然后保證這個(gè)位置不在蛇身上即可。
食物類:
傳入顏色、渲染的界面、一個(gè)格子的寬度以及坐標(biāo)
另外我還提供了一個(gè)繪制圓的方法(pos為坐標(biāo),radius為直徑)
circle函數(shù)參數(shù):界面screen,顏色,位置(元組形式),直徑,線條寬度。
這里我們將線條設(shè)置為直徑,就能繪制一個(gè)圓盤。(注意寬度一定要是int類型,需要強(qiáng)轉(zhuǎn))
"""食物類""" import pygame class Food(): def __init__(self,food_color,screen,lattice_wh,x,y): self.screen = screen self.food_color = food_color self.lattice_wh = lattice_wh self.radius = lattice_wh/2 self.x,self.y = x,y def draw(self): pos = (self.x+self.lattice_wh/2,self.y+self.lattice_wh/2) pygame.draw.circle(self.screen,self.food_color,pos,self.radius,int(self.radius))
fuc.py中,寫了一個(gè)生成食物的函數(shù):
def create_food(food_color,screen,lattice_wh,snakes): success = 0 x,y = 0,0 while not success: x,y = randint(0,24),randint(0,24) x *= lattice_wh y *= lattice_wh for i in snakes: if (x,y) != (i.rect.x,i.rect.y): success = 1 break food = Food(food_color,screen,lattice_wh,x,y) return food
randint生成一個(gè)整數(shù)位置,乘上格子的寬度,我們就能得到一個(gè)格子的左上角坐標(biāo),看看是否在蛇身上,不在就可以生成了。
四、蛇的移動(dòng)
之前只給出了方法,現(xiàn)在我們來實(shí)現(xiàn)一下。
蛇的移動(dòng)就三種情況:
- 撞到自己或者邊界
- 吃到食物
- 正常移動(dòng)
如果是第一種,直接結(jié)束游戲,第三中我們就按照上面說的,將身子向前移動(dòng)一位,修改一下頭節(jié)點(diǎn)即可。
但是第二種,涉及到了需要在snakes添加一個(gè)對象,我們就需要搞清楚添加的位置。
在即將碰到食物時(shí),我們將食物位置添加到列表首項(xiàng)。
實(shí)現(xiàn):
這里的game_stats為游戲種需要傳遞并需要被修改的項(xiàng),整合成一個(gè)列表好看一點(diǎn):
game_stats =[if_lose,direction,num,food]
游戲是否結(jié)束的狀態(tài)變量、蛇頭方向(1234:上下左右,0為靜止)、吃到的食物個(gè)數(shù)、食物的實(shí)例
def going(snakes,snake_color,snake_head_color,lattice_wh,game_stats,food_color,screen): """蛇的移動(dòng)和轉(zhuǎn)向問題""" # 初始狀態(tài),不需要移動(dòng) if not game_stats[1]: return # 預(yù)測位置 (x,y) = snakes[0].forecast(game_stats[1]) # 撞到邊界 if x == -lattice_wh or x == 25*lattice_wh or y == -lattice_wh or y == 25*lattice_wh: game_stats[0] = 0 return # 吃到食物 if (x,y) == (game_stats[3].x,game_stats[3].y): head = Snake(snake_color,snake_head_color,x,y,lattice_wh) snakes.insert(0,head) game_stats[2] += 1 game_stats[3] = create_food(food_color,screen,lattice_wh,snakes) return # 撞到蛇身 for i in snakes: if (x,y) == (i.rect.x,i.rect.y): game_stats[0] = 0 return # 都沒有,就正常移動(dòng) for i in range(len(snakes)-1,0,-1): snakes[i].rect.x = snakes[i-1].rect.x snakes[i].rect.y = snakes[i-1].rect.y snakes[0].move(game_stats[1])
這里的正常移動(dòng),我們是否可以這樣寫?
snake[i] = snakes[i-1
這樣是不行的,在python中,賦值是將地址賦值過去,所以實(shí)際上我們是將兩個(gè)實(shí)例指向一個(gè)地址。
對于snakes[1],當(dāng)我們指向snakes[0],然后修改snakes[0]之后,兩者會(huì)合并為一個(gè),而整個(gè)蛇身就會(huì)缺失一部分。
五、按鍵感應(yīng)
對于蛇方向的控制,我們是通過上下左右四個(gè)按鍵實(shí)現(xiàn)的,所以我們還需要修改一下check_events。
先說明一下,這里我沒有使用正常的if-elif對每一個(gè)方向進(jìn)行判斷,其實(shí)都一樣的。
首先,蛇不能在向上的情況下按向下,所以是有一個(gè)方向沖突的,拿小本本記下來。
# 方向沖突 conflict = { pygame.K_RIGHT:4, pygame.K_LEFT :3, pygame.K_UP :1, pygame.K_DOWN :2, 0:0, # 這個(gè)純屬湊數(shù),問題不大 1:2, 2:1, 3:4, 4:3 }
事件檢測:
def check_events(game_stats,conflict,snakes,snake_color,snake_head_color, lattice_wh,food_color,screen): for event in pygame.event.get(): if event.type == pygame.KEYDOWN: # 按鍵匹配 if event.key in conflict: ret = conflict[event.key] # 判斷我們輸入的方向和當(dāng)前方向是否沖突,不沖突就可以修改,然后賦值 if conflict[ret] != game_stats[1]: game_stats[1] = ret # 調(diào)用移動(dòng)函數(shù) going(snakes,snake_color,snake_head_color, lattice_wh,game_stats,food_color,screen) elif event.type == pygame.QUIT: sys.exit()
(這部分,其實(shí)改變方向不使用going,也沒什么問題)
六、整合部分
剩下的工作,就是將整體串起來。
換掉了之前的time.sleep,改成了設(shè)置幀率。
import pygame from fuc import * from snake import Snake from time import sleep from food import Food # 基本屬性 lattice_wh = 20 #長寬 snake_color = (84, 255, 159) snake_head_color = (123, 104, 238) food_color = (255, 64, 64) # 繪制界面 pygame.init() screen = pygame.display.set_mode((25*lattice_wh,25*lattice_wh)) pygame.display.set_caption('貪吃蛇') # 設(shè)置幀率 FPS=10 level = 0.9 # 每吃掉一個(gè),間隔時(shí)間縮短系數(shù) FPSClock=pygame.time.Clock() if_lose = 1 if_food = 1 # 蛇的方向 direction = 0 # 得分,吃一個(gè)一分 num = 0 # 蛇頭&1個(gè)蛇身 snakes = [] snakes.append(Snake(snake_color,snake_head_color,lattice_wh,24*lattice_wh,lattice_wh)) snakes.append(Snake(snake_color,snake_head_color,0,24*lattice_wh,lattice_wh)) # 食物 food = create_food(food_color,screen,lattice_wh,snakes) # 游戲狀態(tài)打包 game_stats =[if_lose,direction,num,food] # 方向沖突 conflict = { pygame.K_RIGHT:4, pygame.K_LEFT :3, pygame.K_UP :1, pygame.K_DOWN :2, 0:0, 1:2, 2:1, 3:4, 4:3 } while game_stats[0]: update(screen,lattice_wh,snakes,game_stats) check_events(game_stats,conflict,snakes,snake_color,snake_head_color, lattice_wh,food_color,screen) going(snakes,snake_color,snake_head_color,lattice_wh,game_stats,food_color,screen) FPSClock.tick(FPS* level**num)
然后修改一下update函數(shù):
def update(screen,lattice_wh,snakes,game_stats): """屏幕刷新""" # 背景顏色 screen.fill((255,255,255)) # 畫蛇,需要先畫,不然網(wǎng)格會(huì)被蓋住 pygame.draw.rect(screen,snakes[0].head_color,snakes[0].rect) for i in range(1,len(snakes)): pygame.draw.rect(screen,snakes[i].color,snakes[i].rect) # 繪制網(wǎng)格 for i in range(25): pygame.draw.line(screen,(105, 105, 105),(0,lattice_wh*i),(500,lattice_wh*i)) for i in range(25): pygame.draw.line(screen,(105, 105, 105),(lattice_wh*i,0),(lattice_wh*i,500)) # 繪制食物 game_stats[3].draw() pygame.display.flip()
七、結(jié)語
本來還想添加一些其他的部分,比如在死亡時(shí)候顯示一下得分什么的,但是好象基本上都在這篇博客的彈窗顯示部分寫過了,那么我們這個(gè)就先結(jié)束吧,然后開新坑。
到此這篇關(guān)于python實(shí)戰(zhàn)之利用pygame實(shí)現(xiàn)貪吃蛇游戲(二)的文章就介紹到這了,更多相關(guān)pygame實(shí)現(xiàn)貪吃蛇游戲內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 教你一步步利用python實(shí)現(xiàn)貪吃蛇游戲
- python實(shí)現(xiàn)貪吃蛇游戲源碼
- 200行python代碼實(shí)現(xiàn)貪吃蛇游戲
- python實(shí)戰(zhàn)之利用pygame實(shí)現(xiàn)貪吃蛇游戲(一)
- Python turtle實(shí)現(xiàn)貪吃蛇游戲
- Python使用海龜繪圖實(shí)現(xiàn)貪吃蛇游戲
- Python實(shí)現(xiàn)貪吃蛇小游戲(單人模式)
- Python實(shí)現(xiàn)貪吃蛇小游戲(雙人模式)
- Python利用手勢識(shí)別實(shí)現(xiàn)貪吃蛇游戲
- python實(shí)現(xiàn)一個(gè)簡單的貪吃蛇游戲附代碼
相關(guān)文章
Python使用Selenium實(shí)現(xiàn)按文本查找元素
本文我們將通過示例為大家詳細(xì)介紹如何在Python中使用selenium通過文本查找元素的方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以參考一下2023-11-11Windows下安裝python2和python3多版本教程
這篇文章主要介紹下Windows(我用的Win10)環(huán)境下的python2.x 和 python3.x 的安裝,以及python2.x 與 python3.x 共存時(shí)的配置問題。2017-03-03Python中sorted()函數(shù)之排序的利器詳解
sorted()函數(shù)是Python中的內(nèi)置函數(shù),用于對可迭代對象進(jìn)行排序,下面這篇文章主要給大家介紹了關(guān)于Python中sorted()函數(shù)之排序的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-08-08Python使用GeoIP2實(shí)現(xiàn)地圖定位
GeoIP2是一種IP地址定位庫,它允許開發(fā)人員根據(jù)IP地址查找有關(guān)位置和地理位置的信息,這篇文章主要為大家介紹了python如何使用GeoIP2實(shí)現(xiàn)地圖定位,感興趣的可以了解下2023-10-10python 函數(shù)進(jìn)階之閉包函數(shù)
這篇文章主要介紹了python 函數(shù)進(jìn)階之閉包函數(shù),內(nèi)函數(shù)使用了外函數(shù)的局部變量,并且外函數(shù)把內(nèi)函數(shù)返回出來的過程叫做閉包,里面的內(nèi)函數(shù)是閉包函數(shù),下文相關(guān)介紹需要的小伙伴可以參考一下2022-04-04Python練習(xí)之操作MySQL數(shù)據(jù)庫
這篇文章主要介紹了Python練習(xí)之操作MySQL數(shù)據(jù)庫,文章通過如何創(chuàng)建MySQL數(shù)據(jù)表?如何向MySQL表中插入數(shù)據(jù)?如何查詢MySQL中的數(shù)據(jù)?的三個(gè)問題展開了詳細(xì)的內(nèi)容介紹2022-06-06LyScript實(shí)現(xiàn)Hook隱藏調(diào)試器的方法詳解
LyScript?插件集成的內(nèi)置API函數(shù)可靈活的實(shí)現(xiàn)繞過各類反調(diào)試保護(hù)機(jī)制。本文將運(yùn)用LyScript實(shí)現(xiàn)繞過大多數(shù)通用調(diào)試機(jī)制,實(shí)現(xiàn)隱藏調(diào)試器的目的,需要的可以參考一下2022-09-09Python棧的實(shí)現(xiàn)方法示例【列表、單鏈表】
這篇文章主要介紹了Python棧的實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了Python基于列表、單鏈表定義棧的相關(guān)操作技巧,需要的朋友可以參考下2020-02-02Python實(shí)現(xiàn)批量讀取HDF多波段柵格數(shù)據(jù)并繪制像元直方圖
這篇文章主要為大家詳細(xì)介紹了如何基于Python語言gdal模塊,實(shí)現(xiàn)多波段HDF柵格圖像文件的讀取、處理與像元值可視化(直方圖繪制)等操作,需要的可以參考一下2023-03-03