python實(shí)現(xiàn)貪吃蛇雙人大戰(zhàn)
本文實(shí)例為大家分享了python實(shí)現(xiàn)貪吃蛇雙人大戰(zhàn)的具體代碼,供大家參考,具體內(nèi)容如下
晚上家里小朋友要玩貪吃蛇游戲,還要跟我對(duì)戰(zhàn),一時(shí)半會(huì)我沒(méi)想到去哪里下這樣一個(gè)游戲,忽然靈機(jī)一動(dòng),可以自己寫一個(gè),順便還可以跟小朋友展示一下程序員的厲害,于是開工。
原始版本
這是一個(gè)很基礎(chǔ)的程序,自然不用從頭寫,在網(wǎng)上隨便一搜,找到有人共享的代碼,點(diǎn)擊鏈接,據(jù)說(shuō)是來(lái)源于《Raspberry Pi 用戶指南》的代碼,我也沒(méi)有去查。代碼如下:
#!/usr/bin/env python import pygame,sys,time,random from pygame.locals import * # 定義顏色變量 redColour = pygame.Color(255,0,0) blackColour = pygame.Color(0,0,0) whiteColour = pygame.Color(255,255,255) greyColour = pygame.Color(150,150,150) # 定義gameOver函數(shù) def gameOver(playSurface): gameOverFont = pygame.font.Font('arial.ttf',72) gameOverSurf = gameOverFont.render('Game Over', True, greyColour) gameOverRect = gameOverSurf.get_rect() gameOverRect.midtop = (320, 10) playSurface.blit(gameOverSurf, gameOverRect) pygame.display.flip() time.sleep(5) pygame.quit() sys.exit() # 定義main函數(shù) def main(): # 初始化pygame pygame.init() fpsClock = pygame.time.Clock() # 創(chuàng)建pygame顯示層 playSurface = pygame.display.set_mode((640,480)) pygame.display.set_caption('Raspberry Snake') # 初始化變量 snakePosition = [100,100] snakeSegments = [[100,100],[80,100],[60,100]] raspberryPosition = [300,300] raspberrySpawned = 1 direction = 'right' changeDirection = direction while True: # 檢測(cè)例如按鍵等pygame事件 for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit() elif event.type == KEYDOWN: # 判斷鍵盤事件 if event.key == K_RIGHT or event.key == ord('d'): changeDirection = 'right' if event.key == K_LEFT or event.key == ord('a'): changeDirection = 'left' if event.key == K_UP or event.key == ord('w'): changeDirection = 'up' if event.key == K_DOWN or event.key == ord('s'): changeDirection = 'down' if event.key == K_ESCAPE: pygame.event.post(pygame.event.Event(QUIT)) # 判斷是否輸入了反方向 if changeDirection == 'right' and not direction == 'left': direction = changeDirection if changeDirection == 'left' and not direction == 'right': direction = changeDirection if changeDirection == 'up' and not direction == 'down': direction = changeDirection if changeDirection == 'down' and not direction == 'up': direction = changeDirection # 根據(jù)方向移動(dòng)蛇頭的坐標(biāo) if direction == 'right': snakePosition[0] += 20 if direction == 'left': snakePosition[0] -= 20 if direction == 'up': snakePosition[1] -= 20 if direction == 'down': snakePosition[1] += 20 # 增加蛇的長(zhǎng)度 snakeSegments.insert(0,list(snakePosition)) # 判斷是否吃掉了樹莓 if snakePosition[0] == raspberryPosition[0] and snakePosition[1] == raspberryPosition[1]: raspberrySpawned = 0 else: snakeSegments.pop() # 如果吃掉樹莓,則重新生成樹莓 if raspberrySpawned == 0: x = random.randrange(1,32) y = random.randrange(1,24) raspberryPosition = [int(x*20),int(y*20)] raspberrySpawned = 1 # 繪制pygame顯示層 playSurface.fill(blackColour) for position in snakeSegments: pygame.draw.rect(playSurface,whiteColour,Rect(position[0],position[1],20,20)) pygame.draw.rect(playSurface,redColour,Rect(raspberryPosition[0], raspberryPosition[1],20,20)) # 刷新pygame顯示層 pygame.display.flip() # 判斷是否死亡 if snakePosition[0] > 620 or snakePosition[0] < 0: gameOver(playSurface) if snakePosition[1] > 460 or snakePosition[1] < 0: for snakeBody in snakeSegments[1:]: if snakePosition[0] == snakeBody[0] and snakePosition[1] == snakeBody[1]: gameOver(playSurface) # 控制游戲速度 fpsClock.tick(5) if __name__ == "__main__": main()
此代碼實(shí)現(xiàn)了基本功能,主循環(huán)中先判斷按鍵事件,然后調(diào)整蛇的位置,若蛇吃到了豆子(這個(gè)代碼里叫樹莓,我嫌名字太長(zhǎng),改成了習(xí)慣的豆子),則增加蛇的長(zhǎng)度,并重新生成豆子,接著刷新顯示,最后判斷是否死亡,若死亡則調(diào)用gameOver。
當(dāng)然這個(gè)是滿足不了小朋友的需求的,小朋友嘗試了一下,馬上提取了如下需求:
1、要跟我一起玩,也就是要有兩條蛇,每人控制一個(gè),看誰(shuí)吃得多。
2、蛇死了之后不要結(jié)束,太麻煩,改為重新開始。
3、蛇的顏色要能自己定。
4、要能看出來(lái)蛇頭,即蛇頭需要用不同的顏色。
5、豆子數(shù)量太少,每次才一個(gè),要一下子出現(xiàn)很多豆子,可以隨便吃。
看來(lái)天下用戶都一樣,總是各種需求。于是為了便于以后的修改,我把蛇相關(guān)的操作提取了一個(gè)蛇的類如下。
蛇類
class Snake: def __init__(self, color, headColor, ctrlKeys): self.color = color self.headColor = headColor self.ctrlKeys = ctrlKeys #按[上,下,左,右]的順序 self.direction = random.choice([-2,2,-1,1]) # 方向[-2,2,-1,1]分別表示[上,下,左,右] x = random.randrange(5,SCREEN_WIDTH/20-5) y = random.randrange(5,SCREEN_HEIGHT/20-5) self.headPos = [int(x*20),int(y*20)] self.segments = [self.headPos] self.moveAndAdd() self.moveAndAdd() def changeDirection(self, pressKey): directions = [-2,2,-1,1] for direct, key in zip(directions, self.ctrlKeys): if key == pressKey and direct + self.direction != 0: self.direction = direct def moveAndAdd(self): # 根據(jù)方向移動(dòng)蛇頭的坐標(biāo) if self.direction == 1: self.headPos[0] += 20 if self.direction == -1: self.headPos[0] -= 20 if self.direction == -2: self.headPos[1] -= 20 if self.direction == 2: self.headPos[1] += 20 self.segments.insert(0,list(self.headPos)) # 在蛇頭插入一格 def pop(self): self.segments.pop() # 在蛇尾減去一格 def show(self, playSurface): # 畫蛇身 for pos in self.segments[1:]: pygame.draw.rect(playSurface,self.color,Rect(pos[0],pos[1],20,20)) # 畫蛇頭 pygame.draw.rect(playSurface,self.headColor,Rect(self.headPos[0],self.headPos[1],20,20)) def respawnIfDead(self): if self.headPos[0] > SCREEN_WIDTH-20 or self.headPos[0] < 0 or self.headPos[1] > SCREEN_HEIGHT-20 or self.headPos[1] < 0: x = random.randrange(5,SCREEN_WIDTH/20-5) y = random.randrange(5,SCREEN_HEIGHT/20-5) self.direction = random.choice([-2,2,-1,1]) self.headPos = [int(x*20),int(y*20)] self.segments = [self.headPos] self.moveAndAdd() self.moveAndAdd()
其中初始化函數(shù)有三個(gè)參數(shù),分別是蛇的顏色,蛇頭顏色,以及控制的按鍵。初始化的蛇為3格,隨機(jī)出現(xiàn)在中央?yún)^(qū)域(太靠邊怕還來(lái)不及反應(yīng)就死了)。調(diào)用初始化的代碼如下:
# 初始化蛇 ctrlKeys1 = [ord('w'),ord('s'),ord('a'),ord('d')] ctrlKeys2 = [K_UP,K_DOWN,K_LEFT,K_RIGHT] snake1 = Snake(GREEN,GREEN_HEAD,ctrlKeys1) snake2 = Snake(RED,RED_HEAD,ctrlKeys2)
changeDirection 函數(shù)顧名思義是改變方向的,有一個(gè)參數(shù)是按鍵。self.direction 記錄當(dāng)前蛇移動(dòng)的方向,用[-2,2,-1,1]分別表示[上,下,左,右],這主要是為了簡(jiǎn)化代碼。changeDirection 函數(shù)根據(jù)按鍵值判斷是否要改變方向。這里要注意蛇是不能后退的,例如往上走的時(shí)候按下鍵是沒(méi)有效果的。
moveAndAdd 函數(shù)根據(jù)移動(dòng)方向移動(dòng)一格,并增加一格在蛇頭。pop 函數(shù)在蛇尾減去一格。這兩個(gè)函數(shù)結(jié)合起來(lái)即可實(shí)現(xiàn)蛇的移動(dòng),以及蛇增長(zhǎng)一格并移動(dòng)。
show 函數(shù)將蛇顯示出來(lái),先畫蛇身,再畫蛇頭。以防蛇頭被蛇身?yè)踝 ?/p>
respawnIfDead 函數(shù)判斷蛇是否死亡,若死了就重生。目前死亡方式為超出邊界。重生后的蛇隨機(jī)出現(xiàn)在中央?yún)^(qū)域,身體恢復(fù)為3格。
為了滿足很多豆子可以隨便吃的需求,考慮到以后的擴(kuò)展,把豆子也做了一個(gè)類Bean,并給豆子們也做了一個(gè)類Beans,如下。
豆類
class Bean: def __init__(self, color, pos): self.color = color self.pos = pos def beEaten(self, snakePos): if snakePos[0] == self.pos[0] and snakePos[1] == self.pos[1]: return True else: return False class Beans: def __init__(self, color, totalNum): self.color = color self.totalNum = totalNum self.curNum = 0 self.beans = [] def generate(self): while self.curNum < self.totalNum: x = random.randrange(0,SCREEN_WIDTH/20) y = random.randrange(0,SCREEN_HEIGHT/20) self.beans.append(Bean(self.color, [int(x*20),int(y*20)])) self.curNum = self.curNum + 1 def beEaten(self, snakePos): for bean in self.beans: if bean.beEaten(snakePos): self.beans.remove(bean) self.curNum = self.curNum - 1 return True return False def show(self, playSurface): for bean in self.beans: pygame.draw.rect(playSurface,self.color,Rect(bean.pos[0],bean.pos[1],20,20))
豆類比較簡(jiǎn)單,初始化的時(shí)候要指定顏色和位置,有一個(gè)函數(shù)beEaten判斷是否被吃了。
豆子們的類稍微復(fù)雜點(diǎn),其包含了 totalNum 個(gè)豆子。豆子們初始化的時(shí)候需要指定顏色和數(shù)量。 curNum 用來(lái)記錄當(dāng)前有多少個(gè)豆子,因?yàn)橛械亩棺涌赡鼙怀缘袅恕enerate 函數(shù)負(fù)責(zé)生成豆子,初始化以及豆子被吃掉后都可以用它來(lái)生成豆子,生成的豆子隨機(jī)出現(xiàn)在屏幕范圍內(nèi)。beEaten 函數(shù)判斷豆子們中是否有的被吃了,若被吃了就從列表 beans 中移除它,同時(shí)調(diào)整 curNum 用來(lái)記錄當(dāng)前還剩多少豆子。show 函數(shù)將豆子們都顯示出來(lái)。
初始化豆子們的代碼如下:
# 初始化豆子 yellowBeans = Beans(YELLOW, BEAN_NUM) yellowBeans.generate()
在蛇和豆子們都初始化好了之后,主循環(huán)的代碼可以簡(jiǎn)化如下:
while True: # 檢測(cè)按鍵等pygame事件 for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit() elif event.type == KEYDOWN: if event.key == K_ESCAPE: pygame.event.post(pygame.event.Event(QUIT)) else: snake1.changeDirection(event.key) snake2.changeDirection(event.key) # 根據(jù)方向移動(dòng)蛇并增加蛇長(zhǎng)度一格 snake1.moveAndAdd() snake2.moveAndAdd() # 如果豆子被吃掉,則重新生成豆子,否則蛇長(zhǎng)度減少一格 if yellowBeans.beEaten(snake1.headPos): yellowBeans.generate() else: snake1.pop() if yellowBeans.beEaten(snake2.headPos): yellowBeans.generate() else: snake2.pop() # 繪制刷新 playSurface.fill(BLACK) # 繪制pygame顯示層 yellowBeans.show(playSurface) snake1.show(playSurface) snake2.show(playSurface) pygame.display.flip() # 刷新pygame顯示層 # 若死亡則重生 snake1.respawnIfDead() snake2.respawnIfDead() # 控制游戲速度 fpsClock.tick(5)
當(dāng)然,為了能運(yùn)行,pygame的初始化還是需要的:
pygame.init() fpsClock = pygame.time.Clock() # 創(chuàng)建pygame顯示層 playSurface = pygame.display.set_mode((SCREEN_WIDTH,SCREEN_HEIGHT)) pygame.display.set_caption('Snake Eat Beans')
最后,代碼中用到的一些固定值定義如下:
# 定義界面大小 SCREEN_WIDTH = 1080 SCREEN_HEIGHT = 720 # 定義豆子數(shù)量 BEAN_NUM = 10 # 定義顏色變量 RED = pygame.Color(255,0,0) RED_HEAD = pygame.Color(255,150,0) BLACK = pygame.Color(0,0,0) WHITE = pygame.Color(255,255,255) GREY = pygame.Color(150,150,150) GREEN = pygame.Color(0,255,0) GREEN_HEAD = pygame.Color(100,200,200) YELLOW = pygame.Color(255,255,0) BLUE = pygame.Color(0,0,255)
終于,可以和我家小朋友一起愉快的玩耍了
更多關(guān)于python游戲的精彩文章請(qǐng)點(diǎn)擊查看以下專題:
更多有趣的經(jīng)典小游戲?qū)崿F(xiàn)專題,分享給大家:
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 用Python實(shí)現(xiàn)童年貪吃蛇小游戲功能的實(shí)例代碼
- python語(yǔ)言實(shí)現(xiàn)貪吃蛇游戲
- python實(shí)現(xiàn)簡(jiǎn)單貪吃蛇游戲
- 利用Python如何制作貪吃蛇及AI版貪吃蛇詳解
- 150行python代碼實(shí)現(xiàn)貪吃蛇游戲
- 200行python代碼實(shí)現(xiàn)貪吃蛇游戲
- python實(shí)現(xiàn)貪吃蛇游戲源碼
- 使用Python第三方庫(kù)pygame寫個(gè)貪吃蛇小游戲
- 教你一步步利用python實(shí)現(xiàn)貪吃蛇游戲
- 五分鐘學(xué)會(huì)怎么用python做一個(gè)簡(jiǎn)單的貪吃蛇
相關(guān)文章
python實(shí)現(xiàn)簡(jiǎn)單的計(jì)時(shí)器功能函數(shù)
這篇文章主要介紹了python實(shí)現(xiàn)簡(jiǎn)單的計(jì)時(shí)器功能函數(shù),涉及Python操作時(shí)間的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-03-03python數(shù)據(jù)庫(kù)操作mysql:pymysql、sqlalchemy常見用法詳解
這篇文章主要介紹了python數(shù)據(jù)庫(kù)操作mysql:pymysql、sqlalchemy常見用法,結(jié)合實(shí)例形式分析了Python mysql操作庫(kù)pymysql、sqlalchemy基本使用技巧與操作注意事項(xiàng),需要的朋友可以參考下2020-03-03Django實(shí)現(xiàn)翻頁(yè)的示例代碼
翻頁(yè)是經(jīng)常使用的功能,Django提供了翻頁(yè)器。用Django的Paginator類實(shí)現(xiàn),有需要了解Paginator類用法的朋友可參考。希望此文章對(duì)各位有所幫助2021-05-05Python實(shí)戰(zhàn)之實(shí)現(xiàn)簡(jiǎn)單的名片管理系統(tǒng)
這篇文章主要介紹了Python實(shí)戰(zhàn)之實(shí)現(xiàn)簡(jiǎn)單的名片管理系統(tǒng),文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)python的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-04-04Python如何批量處理經(jīng)緯度數(shù)據(jù)并生成位置信息
這篇文章主要介紹了Python如何批量處理經(jīng)緯度數(shù)據(jù)并生成位置信息問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08Python實(shí)現(xiàn)帶參數(shù)與不帶參數(shù)的多重繼承示例
這篇文章主要介紹了Python實(shí)現(xiàn)帶參數(shù)與不帶參數(shù)的多重繼承,結(jié)合具體實(shí)例形式對(duì)比分析了Python實(shí)現(xiàn)帶參數(shù)與不帶參數(shù)的多重繼承相關(guān)操作技巧,需要的朋友可以參考下2018-01-01關(guān)于你不想知道的所有Python3 unicode特性
我的讀者知道我是一個(gè)喜歡痛罵Python3 unicode的人。這次也不例外。我將會(huì)告訴你用unicode有多痛苦和為什么我不能閉嘴。我花了兩周時(shí)間研究Python3,我需要發(fā)泄我的失望。在這些責(zé)罵中,仍然有有用的信息,因?yàn)樗涛覀內(nèi)绾蝸?lái)處理Python3。如果沒(méi)有被我煩到,就讀一讀吧2014-11-11