1. 程式人生 > >200行PYTHON程式碼實現貪吃蛇

200行PYTHON程式碼實現貪吃蛇

# 200行Python程式碼實現貪吃蛇 話不多說,最後會給出全部的程式碼,也可以從[這裡](https://github.com/NemoHoHaloAi/Game/tree/master/YummySnake)Fork,正文開始; 目前實現的功能列表: 1. 貪吃蛇的控制,通過上下左右方向鍵; 2. 觸碰到邊緣、牆壁、自身則遊戲結束; 3. 接觸到食物則食物消失,同時根據食物型別身體會變長; 4. 目前長度顯示; 5. 暫停、死亡介面; ## 執行動圖 ![](https://img2020.cnblogs.com/blog/666842/202004/666842-20200407204316398-352550443.gif) ## 程式碼片段分析 ### 各個部分繪製的程式碼 ```python # 遊戲背景以及最下方用於顯示文字的背景 def draw_background(): # white background screen.fill(COLORS['white']) pygame.draw.rect(screen,COLORS['black'],(-100,GAME_SIZE[1],3000,200),0) # 繪製牆壁 def draw_wall(): for xy in wall_list: pygame.draw.rect(screen,COLORS['darkgray'],(xy[0]-WALL_WIDTH/2,xy[1]-WALL_WIDTH/2,WALL_WIDTH,WALL_HEIGHT),0) # 繪製蛇,包括頭和身體 def draw_snake(): head = snake_list[0] pygame.draw.circle(screen,COLORS['darkred'],(head[0],head[1]),int(SNAKE_WIDTH/2),0) for xy in snake_list[1:]: pygame.draw.rect(screen,COLORS['darkred'],(xy[0]-SNAKE_WIDTH/2,xy[1]-SNAKE_WIDTH/2,SNAKE_WIDTH,SNAKE_HEIGHT),2) # 繪製食物 def draw_food(): for xyz in food_list: pygame.draw.rect(screen,FOOD_COLORS[xyz[2]-1],(xyz[0]-FOOD_WIDTH/2,xyz[1]-FOOD_WIDTH/2,FOOD_WIDTH,FOOD_HEIGHT),0) # 繪製下方的身體長度記錄 def draw_context(): txt = FONT_M.render('Snake length: '+str(len(snake_list)-1),True,COLORS['lightblue']) x,y = 10,GAME_SIZE[1]+(int((SIZE[1]-GAME_SIZE[1])/2)) y = int(y-FONT_M.size('Count')[1]/2) screen.blit(txt,(x,y)) # 繪製暫停介面 def draw_pause(): s = pygame.Surface(SIZE, pygame.SRCALPHA) s.fill((255,255,255,220)) screen.blit(s, (0,0)) txt = FONT_M.render('PAUSE',True,COLORS['darkgray']) x,y = SIZE[0]/2,SIZE[1]/2 x,y = int(x-FONT_M.size('PAUSE')[0]/2),int(y-FONT_M.size('PAUSE')[1]/2) screen.blit(txt,(x,y)) # 繪製死亡介面 def draw_dead(): s = pygame.Surface(SIZE, pygame.SRCALPHA) s.fill((255,255,255,240)) screen.blit(s, (0,0)) txt = FONT_M.render('YOU DEAD',True,COLORS['black']) x,y = SIZE[0]/2,SIZE[1]/2 x,y = int(x-FONT_M.size('YOU DEAD')[0]/2),int(y-FONT_M.size('YOU DEAD')[1]/2) screen.blit(txt,(x,y)) ``` ### 死亡與食物的碰撞檢查 ```python # 矩形覆蓋檢查作為碰撞檢測,思路是取反,即取所有不會覆蓋的情況的反即可 def rect_cover(rect1,rect2): left1 = int(rect1[0]) right1 = int(rect1[0]+rect1[2]) up1 = int(rect1[1]) down1 = int(rect1[1]+rect1[3]) left2 = int(rect2[0]) right2 = int(rect2[0]+rect2[2]) up2 = int(rect2[1]) down2 = int(rect2[1]+rect2[3]) if not (right2<=left1 or left2>=right1 or down2<=up1 or up2>=down1): return True return False # 檢查是否碰到食物 def check_food(): # 頭與食物 first = snake_list[0] snake_head_rect = (first[0]-SNAKE_WIDTH/2,first[1]-SNAKE_WIDTH/2,SNAKE_WIDTH,SNAKE_HEIGHT) for i in range(len(food_list)): xyz = food_list[i] food_rect = (xyz[0]-FOOD_WIDTH/2,xyz[1]-FOOD_WIDTH/2,FOOD_WIDTH,FOOD_HEIGHT) if rect_cover(snake_head_rect,food_rect): add_body(xyz[2]) del food_list[i] return True return False # 檢查是否碰到邊緣、牆壁或者自己的身體 def check_dead(): first = snake_list[0] snake_head_rect = (first[0]-SNAKE_WIDTH/2,first[1]-SNAKE_WIDTH/2,SNAKE_WIDTH,SNAKE_HEIGHT) # 頭與邊緣 if first[0] < 0 or first[0] > GAME_SIZE[0] or first[1] < 0 or first[1] > GAME_SIZE[1]: return True # 頭與牆壁 for xy in wall_list: wall_rect = (xy[0]-WALL_WIDTH/2,xy[1]-WALL_WIDTH/2,WALL_WIDTH,WALL_HEIGHT) if rect_cover(snake_head_rect,wall_rect): return True # 頭與自身 for xy in snake_list[1:]: body_rect = (xy[0]-SNAKE_WIDTH/2,xy[1]-SNAKE_WIDTH/2,SNAKE_WIDTH,SNAKE_HEIGHT) if rect_cover(snake_head_rect,body_rect): return True return False ``` ### 更新食物以及增加蛇的身體長度 ```python def add_food(): while(True): xyz = [random.choice(X_LIST),random.choice(Y_LIST),random.choice([1,2,3,4])] if xyz not in wall_list: food_list.append(xyz) break def add_body(length=1): for c in range(length): # 尾巴加一節 last2,last1 = snake_list[-2],snake_list[-1] if last2[0]==last1[0]: # 豎著的兩段 if last2[1]>last1[1]: # 朝下 snake_list.append([last1[0],last1[1]-SNAKE_WIDTH]) else: snake_list.append([last1[0],last1[1]+SNAKE_WIDTH]) else: # 橫著的兩段 if last2[0]>last1[0]: # 朝右 snake_list.append([last1[0]-SNAKE_WIDTH,last1[1]]) else: snake_list.append([last1[0]+SNAKE_WIDTH,last1[1]]) ``` ### 蛇的自動移動 ```python # 通過按鍵判斷當前蛇的朝向 if event.key == K_LEFT: if head in ['up','down']: head = 'left' elif event.key == K_RIGHT: if head in ['up','down']: head = 'right' elif event.key == K_UP: if head in ['left','right']: head = 'up' elif event.key == K_DOWN: if head in ['left','right']: head = 'down' # 通過朝向判斷蛇的下一個位置 first = snake_list[0] snake_list[1:] = snake_list[:-1] if head == 'up': snake_list[0] = [first[0],first[1]-SNAKE_WIDTH] elif head == 'down': snake_list[0] = [first[0],first[1]+SNAKE_WIDTH] elif head == 'left': snake_list[0] = [first[0]-SNAKE_WIDTH,first[1]] elif head == 'right': snake_list[0] = [first[0]+SNAKE_WIDTH,first[1]] ``` ## 全部程式碼 ```python import sys,random import pygame from pygame.color import THECOLORS as COLORS from pygame.locals import * def draw_background(): # white background screen.fill(COLORS['white']) pygame.draw.rect(screen,COLORS['black'],(-100,GAME_SIZE[1],3000,200),0) def draw_wall(): for xy in wall_list: pygame.draw.rect(screen,COLORS['darkgray'],(xy[0]-WALL_WIDTH/2,xy[1]-WALL_WIDTH/2,WALL_WIDTH,WALL_HEIGHT),0) def draw_snake(): head = snake_list[0] pygame.draw.circle(screen,COLORS['darkred'],(head[0],head[1]),int(SNAKE_WIDTH/2),0) for xy in snake_list[1:]: pygame.draw.rect(screen,COLORS['darkred'],(xy[0]-SNAKE_WIDTH/2,xy[1]-SNAKE_WIDTH/2,SNAKE_WIDTH,SNAKE_HEIGHT),2) def draw_food(): for xyz in food_list: pygame.draw.rect(screen,FOOD_COLORS[xyz[2]-1],(xyz[0]-FOOD_WIDTH/2,xyz[1]-FOOD_WIDTH/2,FOOD_WIDTH,FOOD_HEIGHT),0) def draw_context(): txt = FONT_M.render('Snake length: '+str(len(snake_list)-1),True,COLORS['lightblue']) x,y = 10,GAME_SIZE[1]+(int((SIZE[1]-GAME_SIZE[1])/2)) y = int(y-FONT_M.size('Count')[1]/2) screen.blit(txt,(x,y)) def draw_pause(): s = pygame.Surface(SIZE, pygame.SRCALPHA) s.fill((255,255,255,220)) screen.blit(s, (0,0)) txt = FONT_M.render('PAUSE',True,COLORS['darkgray']) x,y = SIZE[0]/2,SIZE[1]/2 x,y = int(x-FONT_M.size('PAUSE')[0]/2),int(y-FONT_M.size('PAUSE')[1]/2) screen.blit(txt,(x,y)) def draw_dead(): s = pygame.Surface(SIZE, pygame.SRCALPHA) s.fill((255,255,255,240)) screen.blit(s, (0,0)) txt = FONT_M.render('YOU DEAD',True,COLORS['black']) x,y = SIZE[0]/2,SIZE[1]/2 x,y = int(x-FONT_M.size('YOU DEAD')[0]/2),int(y-FONT_M.size('YOU DEAD')[1]/2) screen.blit(txt,(x,y)) def rect_cover(rect1,rect2): left1 = int(rect1[0]) right1 = int(rect1[0]+rect1[2]) up1 = int(rect1[1]) down1 = int(rect1[1]+rect1[3]) left2 = int(rect2[0]) right2 = int(rect2[0]+rect2[2]) up2 = int(rect2[1]) down2 = int(rect2[1]+rect2[3]) if not (right2<=left1 or left2>=right1 or down2<=up1 or up2>=down1): return True return False def add_food(): while(True): xyz = [random.choice(X_LIST),random.choice(Y_LIST),random.choice([1,2,3,4])] if xyz not in wall_list: food_list.append(xyz) break def add_body(length=1): for c in range(length): # 尾巴加一節 last2,last1 = snake_list[-2],snake_list[-1] if last2[0]==last1[0]: # 豎著的兩段 if last2[1]>last1[1]: # 朝下 snake_list.append([last1[0],last1[1]-SNAKE_WIDTH]) else: snake_list.append([last1[0],last1[1]+SNAKE_WIDTH]) else: # 橫著的兩段 if last2[0]>last1[0]: # 朝右 snake_list.append([last1[0]-SNAKE_WIDTH,last1[1]]) else: snake_list.append([last1[0]+SNAKE_WIDTH,last1[1]]) def check_food(): # 頭與食物 first = snake_list[0] snake_head_rect = (first[0]-SNAKE_WIDTH/2,first[1]-SNAKE_WIDTH/2,SNAKE_WIDTH,SNAKE_HEIGHT) for i in range(len(food_list)): xyz = food_list[i] food_rect = (xyz[0]-FOOD_WIDTH/2,xyz[1]-FOOD_WIDTH/2,FOOD_WIDTH,FOOD_HEIGHT) if rect_cover(snake_head_rect,food_rect): add_body(xyz[2]) del food_list[i] return True return False def check_dead(): first = snake_list[0] snake_head_rect = (first[0]-SNAKE_WIDTH/2,first[1]-SNAKE_WIDTH/2,SNAKE_WIDTH,SNAKE_HEIGHT) # 頭與邊緣 if first[0] < 0 or first[0] > GAME_SIZE[0] or first[1] < 0 or first[1] > GAME_SIZE[1]: return True # 頭與牆壁 for xy in wall_list: wall_rect = (xy[0]-WALL_WIDTH/2,xy[1]-WALL_WIDTH/2,WALL_WIDTH,WALL_HEIGHT) if rect_cover(snake_head_rect,wall_rect): return True # 頭與自身 for xy in snake_list[1:]: body_rect = (xy[0]-SNAKE_WIDTH/2,xy[1]-SNAKE_WIDTH/2,SNAKE_WIDTH,SNAKE_HEIGHT) if rect_cover(snake_head_rect,body_rect): return True return False if __name__ == "__main__": # init pygame pygame.init() # contant GAME_SIZE = [900,900] SIZE = [GAME_SIZE[0],GAME_SIZE[1]+100] FONT_S = pygame.font.SysFont('Times', 50) FONT_M = pygame.font.SysFont('Times', 90) DIRECTION = ['up','right','down','left'] X_LIST = [x for x in range(GAME_SIZE[0])] Y_LIST = [y for y in range(GAME_SIZE[1])] FOOD_COLORS = ((46,139,87),(199,21,133),(25,25,112),(255,215,0)) # wall wall_list = [[100,200],[600,500],[350,200],[500,800]] WALL_WIDTH,WALL_HEIGHT = 30,30 # food food_list = [(150,200,1),(300,500,1),(740,542,1),(300,600,1),(700,600,1)] FOOD_WIDTH,FOOD_HEIGHT = 14,14 # create screen 500*500 screen = pygame.display.set_mode(SIZE) # variable parameter snake_list = [[100+12*4,100],[100+12*3,100],[100+12*2,100],[100+12*1,100],[100,100]] SNAKE_WIDTH,SNAKE_HEIGHT = 12,12 snake_v = 0 count_time = 0 # level frame = 0.05 level = 1 # main loop running = True pause = False dead = False head = 'right' while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False break elif event.type == pygame.MOUSEBUTTONDOWN: pause = not pause elif event.type == pygame.KEYUP: if event.key == K_LEFT: if head in ['up','down']: head = 'left' elif event.key == K_RIGHT: if head in ['up','down']: head = 'right' elif event.key == K_UP: if head in ['left','right']: head = 'up' elif event.key == K_DOWN: if head in ['left','right']: head = 'down' # update data if not pause and not dead: count_time += frame*level first = snake_list[0] snake_list[1:] = snake_list[:-1] if head == 'up': snake_list[0] = [first[0],first[1]-SNAKE_WIDTH] elif head == 'down': snake_list[0] = [first[0],first[1]+SNAKE_WIDTH] elif head == 'left': snake_list[0] = [first[0]-SNAKE_WIDTH,first[1]] elif head == 'right': snake_list[0] = [first[0]+SNAKE_WIDTH,first[1]] # background draw_background() # tunnel draw_wall() # choose item draw_snake() # food draw_food() # point draw_context() # pause if not dead and pause: draw_pause() # dead if dead: draw_dead() # flip pygame.display.flip() # pause 20ms pygame.time.delay(int(frame/level*1000)) # check win or not dead = check_dead() if check_food(): add_food() pygame.quit() ``` ## 再貼一下這個倉庫的連結 [小遊戲集合倉庫](https://github.com/NemoHoHaloAi/Game) ## 最後 大家可以到我的Github上看看有沒有其他需要的東西,目前主要是自己做的機器學習專案、Python各種指令碼工具、有意思的小專案以及Follow的大佬、Fork的專案等: https://github.com/NemoHoHaloAi