首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >200行Python代码实现贪吃蛇

200行Python代码实现贪吃蛇

作者头像
HoLoong
发布2020-09-21 18:52:59
1.4K0
发布2020-09-21 18:52:59
举报
文章被收录于专栏:尼莫的AI小站尼莫的AI小站

200行Python代码实现贪吃蛇

话不多说,最后会给出全部的代码,也可以从这里Fork,正文开始;

目前实现的功能列表:

  1. 贪吃蛇的控制,通过上下左右方向键;
  2. 触碰到边缘、墙壁、自身则游戏结束;
  3. 接触到食物则食物消失,同时根据食物类型身体会变长;
  4. 目前长度显示;
  5. 暂停、死亡界面;

运行动图

代码片段分析

各个部分绘制的代码

# 游戏背景以及最下方用于显示文字的背景
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 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

更新食物以及增加蛇的身体长度

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]])

蛇的自动移动

# 通过按键判断当前蛇的朝向
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]]

全部代码

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()

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-04-07 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 200行Python代码实现贪吃蛇
    • 运行动图
      • 代码片段分析
        • 各个部分绘制的代码
        • 死亡与食物的碰撞检查
        • 更新食物以及增加蛇的身体长度
        • 蛇的自动移动
      • 全部代码
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档