1. 程式人生 > >【程式設計6】貪吃蛇遊戲(python+pygame)

【程式設計6】貪吃蛇遊戲(python+pygame)

效果圖~新鮮出爐

  • 開始介面
    在這裡插入圖片描述
  • 遊戲中
    在這裡插入圖片描述
  • 結束介面
    在這裡插入圖片描述

一、pygame模組概覽

模組名稱 功能
pygame.cdrom 訪問光碟機
pygame.cursors 載入游標
pygame.display 訪問顯示裝置
pygame.draw 繪製形狀、線和點
pygame.event 管理事件
pygame.font 使用字型
pygame.image 載入和儲存圖片
pygame.joystick 使用遊戲手柄或類似的東西
pygame.key 讀取鍵盤按鍵
pygame.mixer 聲音
pygame.mouse 滑鼠
pygame.movie 播放視訊
pygame.music 播放音訊
pygame.overlay 訪問高階視訊疊加
pygame 目前學習的
pygame.rect 管理矩形區域
pygame.sndarray 操作聲音資料
pygame.sprite 操作移動影象
pygame.surface 管理影象和螢幕
pygame.surfarray 管理點陣影象資料
pygame.time 管理時間和幀資訊
pygame.transform 縮放和移動影象

二、核心程式碼

思路

  1. 首頁面:會涉及圖片和文字提示的顯示,進入(任意鍵)或退出(ESC)遊戲;
  2. 遊戲頁面:主要涉及食物的建立繪製,蛇的移動和顯示,蛇是否吃到食物或者是否撞到邊界或自身,再者就是音效的實現(背景音樂+gameover音效);
  3. 結束頁面:會涉及圖片和文字提示的顯示,重來(任意鍵)或退出(ESC)遊戲。

核心程式碼

  • 主函式
def main():
    pygame.init()
    # 建立Pygame時鐘物件,控制每個迴圈多長時間執行一次。
    # 例如:snake_speed_clock(60)代表每秒內迴圈要執行的 60 次
    # 每秒60個迴圈(或幀)時,每個迴圈需要1000/60=16.66ms(大約17ms)如果迴圈中的程式碼執行時間超過17ms,
    # 在clock指出下一次迴圈時當前迴圈將無法完成。
    snake_speed_clock = pygame.time.Clock()
    screen = pygame.display.set_mode((windows_width, windows_height))
    screen.fill(white)

    pygame.display.set_caption("貪吃蛇~")
    show_start_info(screen)
    while True:
        music()
        running_game(screen, snake_speed_clock)
        show_end_info(screen)
  • 遊戲執行程式碼
def running_game(screen,snake_speed_clock):
    start_x = random.randint(3, map_width - 8) #開始位置
    start_y = random.randint(3, map_height - 8)
    snake_coords = [{'x': start_x, 'y': start_y},  #初始貪吃蛇
                  {'x': start_x - 1, 'y': start_y},
                  {'x': start_x - 2, 'y': start_y}]

    direction = RIGHT       #  開始時向右移動

    food = get_random_location()     #實物隨機位置

    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                terminate()
            elif event.type == KEYDOWN:
                if (event.key == K_LEFT or event.key == K_a) and direction != RIGHT:
                    direction = LEFT
                elif (event.key == K_RIGHT or event.key == K_d) and direction != LEFT:
                    direction = RIGHT
                elif (event.key == K_UP or event.key == K_w) and direction != DOWN:
                    direction = UP
                elif (event.key == K_DOWN or event.key == K_s) and direction != UP:
                    direction = DOWN
                elif event.key == K_ESCAPE:
                    terminate()

        move_snake(direction, snake_coords) #移動蛇

        ret = snake_is_alive(snake_coords)
        if not ret:
            gameover_music()
            break     #蛇死了. 遊戲結束
        snake_is_eat_food(snake_coords, food) #判斷蛇是否吃到食物

        screen.fill(BG_COLOR)
        draw_snake(screen, snake_coords)
        draw_food(screen, food)
        show_score(screen, len(snake_coords) - 3)
        pygame.display.update()
        snake_speed_clock.tick(snake_speed) #控制fps
  • 食物繪製
def draw_food(screen, food):
    x = food['x'] * cell_size
    y = food['y'] * cell_size
    appleRect = pygame.Rect(x, y, cell_size, cell_size)
    pygame.draw.rect(screen, red, appleRect)
  • 貪吃蛇繪製
def draw_snake(screen, snake_coords):
    for coord in snake_coords:
        x = coord['x'] * cell_size
        y = coord['y'] * cell_size
        wormSegmentRect = pygame.Rect(x,y,cell_size,cell_size)
        pygame.draw.rect(screen, dark_blue, wormSegmentRect)
        wormInnerSegmentRect = pygame.Rect(x+4,y+4,cell_size - 8, cell_size - 8)
        pygame.draw.rect(screen, blue, wormInnerSegmentRect)
  • 移動貪吃蛇
def move_snake(direction, snake_coords):
    if direction == UP:
        newHead = {'x':snake_coords[HEAD]['x'], 'y':snake_coords[HEAD]['y'] - 1}
    elif direction == DOWN:
        newHead = {'x':snake_coords[HEAD]['x'], 'y':snake_coords[HEAD]['y'] + 1}
    elif direction == LEFT:
        newHead = {'x':snake_coords[HEAD]['x'] - 1, 'y':snake_coords[HEAD]['y']}
    elif direction == RIGHT:
        newHead = {'x':snake_coords[HEAD]['x'] + 1, 'y':snake_coords[HEAD]['y']}
    snake_coords.insert(0, newHead)
  • 判斷蛇死沒有死
def snake_is_alive(snake_coords):
    tag = True
    # 頭座標超出地圖範圍
    if(snake_coords[HEAD]['x'] == -1 \
            or snake_coords[HEAD]['x'] == map_width \
            or snake_coords[HEAD]['y'] == -1 \
            or snake_coords[HEAD]['y'] == map_height):
        tag = False
    # 頭座標等於身體某節座標
    for snake_body in snake_coords[1:]:
        if snake_body['x'] == snake_coords[HEAD]['x'] and snake_body['y'] == snake_coords[HEAD]['y']:
            tag = False
    return tag
  • 判斷蛇是否吃到食物
def snake_is_eat_food(snake_coords, food):
    if(snake_coords[HEAD]['x'] == food['x'] and snake_coords[HEAD]['y'] == food['y']):
        ## 重新生成食物
        food['x'] = random.randint(0, map_width - 1)
        food['y'] = random.randint(0, map_height - 1)
    else:
        # 如果沒有吃到實物, 就向前移動, 那麼尾部一格刪掉
        del snake_coords[-1]
  • 隨機生成食物
def get_random_location():
    return {'x':random.randint(0, map_width - 1),'y':random.randint(0, map_height - 1)}
  • 開始資訊顯示
def show_start_info(screen):
    # 建立Font字型物件,使用render方法寫字
    font = pygame.font.Font("simsun.ttc", 40)
    tip = font.render('按任意鍵開始遊戲', True,(65,105,255))
    # 載入圖片
    gamestart = pygame.image.load('startlogo.jpg').convert()
    # 通過blit方法輸出在螢幕上
    screen.blit(gamestart,(140, 30))
    screen.blit(tip,(240, 550))
    ## 重新整理螢幕
    pygame.display.update()

    while True:  # 監聽鍵盤
        for event in pygame.event.get():
            if event.type == QUIT:
                terminate()
            elif event.type == KEYDOWN:  # 任意鍵按下
                return
                if (event.key == K_ESCAPE):  # 若為ESC,則終止程式
                    terminate()
                else:
                    return
  • 聲音設定
def music():
    pygame.mixer.init()
    pygame.mixer.music.load('111.mp3')
    pygame.mixer.music.play(1, 0)

def gameover_music():
    pygame.mixer.init()
    pygame.mixer.music.load('gameover.mp3')
    pygame.mixer.music.play(1,0)
  • 結束資訊顯示
def show_end_info(screen):
    font = pygame.font.Font("simsun.ttc", 40)
    tip = font.render("按ESC退出遊戲,按任意鍵重新開始遊戲",True,(65,105,255))
    # gamestart = pygame.image.load('gameover.png')
    # screen.blit(gamestart,(60, 0))
    screen.blit(tip,(80, 300))
    pygame.display.update()

    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                terminate()
            elif event.type == KEYDOWN:
                if event.key == K_ESCAPE:
                    terminate()
                else:
                    return
  • 成績資訊顯示
def show_score(screen, score):
    font = pygame.font.Font("simsun.ttc", 30)
    scoreSurf = font.render("得分:%s" % score, True, green)
    scoreRect = scoreSurf.get_rect()
    scoreRect.topleft = (windows_width - 120, 10)
    screen.blit(scoreSurf,scoreRect)
  • 程式終止
def terminate():
    pygame.quit()
    sys.exit()