python實現(xiàn)貪吃蛇雙人大戰(zhàn)
本文實例為大家分享了python實現(xiàn)貪吃蛇雙人大戰(zhàn)的具體代碼,供大家參考,具體內(nèi)容如下
晚上家里小朋友要玩貪吃蛇游戲,還要跟我對戰(zhàn),一時半會我沒想到去哪里下這樣一個游戲,忽然靈機一動,可以自己寫一個,順便還可以跟小朋友展示一下程序員的厲害,于是開工。
原始版本
這是一個很基礎(chǔ)的程序,自然不用從頭寫,在網(wǎng)上隨便一搜,找到有人共享的代碼,點擊鏈接,據(jù)說是來源于《Raspberry Pi 用戶指南》的代碼,我也沒有去查。代碼如下:
#!/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: # 檢測例如按鍵等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ù)方向移動蛇頭的坐標 if direction == 'right': snakePosition[0] += 20 if direction == 'left': snakePosition[0] -= 20 if direction == 'up': snakePosition[1] -= 20 if direction == 'down': snakePosition[1] += 20 # 增加蛇的長度 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()
此代碼實現(xiàn)了基本功能,主循環(huán)中先判斷按鍵事件,然后調(diào)整蛇的位置,若蛇吃到了豆子(這個代碼里叫樹莓,我嫌名字太長,改成了習慣的豆子),則增加蛇的長度,并重新生成豆子,接著刷新顯示,最后判斷是否死亡,若死亡則調(diào)用gameOver。
當然這個是滿足不了小朋友的需求的,小朋友嘗試了一下,馬上提取了如下需求:
1、要跟我一起玩,也就是要有兩條蛇,每人控制一個,看誰吃得多。
2、蛇死了之后不要結(jié)束,太麻煩,改為重新開始。
3、蛇的顏色要能自己定。
4、要能看出來蛇頭,即蛇頭需要用不同的顏色。
5、豆子數(shù)量太少,每次才一個,要一下子出現(xiàn)很多豆子,可以隨便吃。
看來天下用戶都一樣,總是各種需求。于是為了便于以后的修改,我把蛇相關(guān)的操作提取了一個蛇的類如下。
蛇類
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ù)方向移動蛇頭的坐標 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ù)有三個參數(shù),分別是蛇的顏色,蛇頭顏色,以及控制的按鍵。初始化的蛇為3格,隨機出現(xiàn)在中央?yún)^(qū)域(太靠邊怕還來不及反應就死了)。調(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ù)顧名思義是改變方向的,有一個參數(shù)是按鍵。self.direction 記錄當前蛇移動的方向,用[-2,2,-1,1]分別表示[上,下,左,右],這主要是為了簡化代碼。changeDirection 函數(shù)根據(jù)按鍵值判斷是否要改變方向。這里要注意蛇是不能后退的,例如往上走的時候按下鍵是沒有效果的。
moveAndAdd 函數(shù)根據(jù)移動方向移動一格,并增加一格在蛇頭。pop 函數(shù)在蛇尾減去一格。這兩個函數(shù)結(jié)合起來即可實現(xiàn)蛇的移動,以及蛇增長一格并移動。
show 函數(shù)將蛇顯示出來,先畫蛇身,再畫蛇頭。以防蛇頭被蛇身擋住。
respawnIfDead 函數(shù)判斷蛇是否死亡,若死了就重生。目前死亡方式為超出邊界。重生后的蛇隨機出現(xiàn)在中央?yún)^(qū)域,身體恢復為3格。
為了滿足很多豆子可以隨便吃的需求,考慮到以后的擴展,把豆子也做了一個類Bean,并給豆子們也做了一個類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))
豆類比較簡單,初始化的時候要指定顏色和位置,有一個函數(shù)beEaten判斷是否被吃了。
豆子們的類稍微復雜點,其包含了 totalNum 個豆子。豆子們初始化的時候需要指定顏色和數(shù)量。 curNum 用來記錄當前有多少個豆子,因為有的豆子可能被吃掉了。generate 函數(shù)負責生成豆子,初始化以及豆子被吃掉后都可以用它來生成豆子,生成的豆子隨機出現(xiàn)在屏幕范圍內(nèi)。beEaten 函數(shù)判斷豆子們中是否有的被吃了,若被吃了就從列表 beans 中移除它,同時調(diào)整 curNum 用來記錄當前還剩多少豆子。show 函數(shù)將豆子們都顯示出來。
初始化豆子們的代碼如下:
# 初始化豆子 yellowBeans = Beans(YELLOW, BEAN_NUM) yellowBeans.generate()
在蛇和豆子們都初始化好了之后,主循環(huán)的代碼可以簡化如下:
while True: # 檢測按鍵等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ù)方向移動蛇并增加蛇長度一格 snake1.moveAndAdd() snake2.moveAndAdd() # 如果豆子被吃掉,則重新生成豆子,否則蛇長度減少一格 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)
當然,為了能運行,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游戲的精彩文章請點擊查看以下專題:
更多有趣的經(jīng)典小游戲?qū)崿F(xiàn)專題,分享給大家:
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
python數(shù)據(jù)庫操作mysql:pymysql、sqlalchemy常見用法詳解
這篇文章主要介紹了python數(shù)據(jù)庫操作mysql:pymysql、sqlalchemy常見用法,結(jié)合實例形式分析了Python mysql操作庫pymysql、sqlalchemy基本使用技巧與操作注意事項,需要的朋友可以參考下2020-03-03Python實戰(zhàn)之實現(xiàn)簡單的名片管理系統(tǒng)
這篇文章主要介紹了Python實戰(zhàn)之實現(xiàn)簡單的名片管理系統(tǒng),文中有非常詳細的代碼示例,對正在學習python的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-04-04Python如何批量處理經(jīng)緯度數(shù)據(jù)并生成位置信息
這篇文章主要介紹了Python如何批量處理經(jīng)緯度數(shù)據(jù)并生成位置信息問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08Python實現(xiàn)帶參數(shù)與不帶參數(shù)的多重繼承示例
這篇文章主要介紹了Python實現(xiàn)帶參數(shù)與不帶參數(shù)的多重繼承,結(jié)合具體實例形式對比分析了Python實現(xiàn)帶參數(shù)與不帶參數(shù)的多重繼承相關(guān)操作技巧,需要的朋友可以參考下2018-01-01關(guān)于你不想知道的所有Python3 unicode特性
我的讀者知道我是一個喜歡痛罵Python3 unicode的人。這次也不例外。我將會告訴你用unicode有多痛苦和為什么我不能閉嘴。我花了兩周時間研究Python3,我需要發(fā)泄我的失望。在這些責罵中,仍然有有用的信息,因為它教我們?nèi)绾蝸硖幚鞵ython3。如果沒有被我煩到,就讀一讀吧2014-11-11