【python】10分鐘教你用python打造貪吃蛇超詳細教程

10分鐘教你用python打造貪吃蛇超詳細教程

在家閒着沒妹子約, 恰好最近又學了一下python,據說pygame挺好玩的。今天就在家研究一下, 弄了個貪吃蛇出來。但願你們喜歡。python

先看程序效果:windows

image
image

01 總體框架

平臺:pycharm微信

關於pygame的安裝這裏就不在贅述,你們自行上網找合適本身的版本的安裝便可。關於pygame模塊知識會穿插在下面代碼中介紹,用到什麼就介紹什麼。這裏就不統一介紹了。app

整個程序因爲是調用了大量的pygame裏面的庫函數,因此也很是簡單(臥槽你這不是調包俠嘛)。也就200多行代碼。基於總體怎麼設計的呢?看下面的圖:框架

image

因爲程序沒有多麼複雜,就直接用面向過程的思路寫了。畢竟這麼小的程序不必整一大堆class來爲難本身對吧。dom

程序總體代碼框架:函數

image

pycharm裏面一堆波浪線也是很無奈。oop

02 main主函數-開始工做

此函數也很是簡單。主要承擔一些遊戲窗口的初始化工做,以及調用相關函數運行遊戲。代碼以下:字體

 1#主函數
2def main():
3    pygame.init() # 模塊初始化
4    snake_speed_clock = pygame.time.Clock() # 建立Pygame時鐘對象
5    screen = pygame.display.set_mode((windows_width, windows_height)) #
6    screen.fill(white)
7
8    pygame.display.set_caption("Python 貪吃蛇小遊戲"#設置標題
9    show_start_info(screen)               #歡迎信息
10    while True:
11        running_game(screen, snake_speed_clock)
12        show_gameover_info(screen)

基於以上代碼,我們來作幾點講解:ui

  • pygame.time.Clock()
    控制幀速率。pygame.time.Clock()會控制每一個循環多長時間運行一次。這就比如,有個定時器在控制着時間進程,一到時間就告訴CPU:
    如今該開始循環了!
    如今該開始循環了!

    使用pygame時鐘以前,必須先建立Clock對象的一個實例,這與建立其餘類的實例徹底相同。Clock= Pygame.time.Clock()。而後在主循環體中,只須要告訴時鐘多久「提醒」一次-------也就是說,循環應該多長時間運行一次:clock.tick(60)。

    傳入clock.tick()的數不是一個毫秒數。這是每秒內循環要運行的次數,因此這個循環應當每秒運行60次,在這裏我只是說應當運行,由於循環只能按計算機可以保證的速度運行,每秒60個循環(或幀)時,每一個循環須要1000/60=16.66ms(大約17ms)若是循環中的代碼運行時間超過17ms,在clock指出下一次循環時當前循環將沒法完成。

    再說通俗一點,就是咱們遊戲的fps嘛。每秒多少幀這樣。至於後面在哪clock.tick(),下面會講。
    詳細可參考這篇文章:http://eyehere.net/2011/python-pygame-novice-professional-8/

  • pygame.display.set_mode((windows_width, windows_height))

    生成windows窗口,pygame.display.set_mode(resolution=(0,0),flags=0,depth=0)。返回的是一個surface對象(surface對象是用於表示圖像的圖像,只要指定尺寸,就能夠利用),resolution能夠控制生成windows窗口的大小,flags表明的是擴展選項,depath不推薦設置。

    flags標誌位控制你想要什麼樣的顯示屏,主要有下面幾個,這幾個量至關因而全局的常量,使用的時候能夠from pygame.locals import *導入:

    • pygame.FULLSCREEN,控制全屏,0或者1來控制
    • pygame.HWSURFACE 控制是否進行硬件加速
    • pygame.RESIZABLE 控制窗口是否能夠調節大小
  • screen.fill(white)
    pygame.surface.fill(color)。對surface對象填充某一種顏色,在這裏表現爲窗口背景顏色的填充。

以上講完,而後就是運行咱們遊戲三個函數了。

 

show_start_info(screen)
顯示歡迎信息,最終效果表現爲:

image

固然,怎麼實現,待會說。

 

接着死循環。由於咱們的遊戲設置是,當GameOver之後,咱們能夠按任意鍵從新開始遊戲,或者退出。所以最後不斷循環判斷用戶是否想從新開始遊戲,就這樣而已。

  • 遊戲主體running_game(screen, snake_speed_clock)
    貪吃蛇運行的主體函數。整個程序的精髓所在。

  • show_gameover_info(screen)
    貪吃蛇死了,顯示GameOver,表現爲:

    image怎麼實現,下面說。

03 show_start_info()歡迎進入遊戲

先貼代碼,待會講解。

 1#開始信息顯示
2def show_start_info(screen):
3    font = pygame.font.Font('myfont.ttf'40)
4    tip = font.render('按任意鍵開始遊戲~~~'True, (65105225))
5    gamestart = pygame.image.load('gamestart.png')
6    screen.blit(gamestart, (14030))
7    screen.blit(tip, (240550))
8    pygame.display.update()
9
10    while True:  #鍵盤監聽事件
11        for event in pygame.event.get():  # event handling loop
12            if event.type == QUIT:
13                terminate()     #終止程序
14            elif event.type == KEYDOWN:
15                if (event.key == K_ESCAPE):  #終止程序
16                    terminate() #終止程序
17                else:
18                    return #結束此函數, 開始遊戲
  • 字體顯示
    先建立一個Font對象,用本身的字體。有了Font對象之後, 就能夠用render方法來寫字了,而後經過blit方法blit到屏幕上。
  • 圖像加載
    用 pygame.image.load()加載圖像得到對象,在用blit方法刷到屏幕上。作完以上事件之後,記得要update一下刷新一下屏幕。
  • 監聽鍵盤
    按任意鍵繼續或者ESC退出……

04 running_game-讓咱們開始遊戲吧

running_game(screen, snake_speed_clock)是遊戲主要功能,在這裏給你們慢慢講解。先貼代碼:

 1#遊戲運行主體
2def running_game(screen,snake_speed_clock):
3    startx = random.randint(3, map_width - 8#開始位置
4    starty = random.randint(3, map_height - 8)
5    snake_coords = [{'x': startx, 'y': starty},  #初始貪吃蛇
6                  {'x': startx - 1'y': starty},
7                  {'x': startx - 2'y': starty}]
8
9    direction = RIGHT       #  開始時向右移動
10
11    food = get_random_location()     #實物隨機位置
12
13    while True:
14        for event in pygame.event.get():
15            if event.type == QUIT:
16                terminate()
17            elif event.type == KEYDOWN:
18                if (event.key == K_LEFT or event.key == K_a) and direction != RIGHT:
19                    direction = LEFT
20                elif (event.key == K_RIGHT or event.key == K_d) and direction != LEFT:
21                    direction = RIGHT
22                elif (event.key == K_UP or event.key == K_w) and direction != DOWN:
23                    direction = UP
24                elif (event.key == K_DOWN or event.key == K_s) and direction != UP:
25                    direction = DOWN
26                elif event.key == K_ESCAPE:
27                    terminate()
28
29        move_snake(direction, snake_coords) #移動蛇
30
31        ret = snake_is_alive(snake_coords)
32        if not ret:
33            break #蛇跪了. 遊戲結束
34        snake_is_eat_food(snake_coords, food) #判斷蛇是否吃到食物
35
36        screen.fill(BG_COLOR)
37        #draw_grid(screen)
38        draw_snake(screen, snake_coords)
39        draw_food(screen, food)
40        draw_score(screen, len(snake_coords) - 3)
41        pygame.display.update()
42        snake_speed_clock.tick(snake_speed) #控制fps
  • 關於貪吃蛇
    這裏咱們採用一個元組存儲貪吃蛇身體各個部分的座標(一條貪吃蛇不是由不少節組成的嘛)。最後再寫個方法根據元組座標把貪吃蛇畫出來就行。

  • 關於食物
    一樣作法。存座標,最後畫出來。

  • 關於移動
    監聽鍵盤,根據用戶按鍵,用direction變量記錄移動方向。而後更新貪吃蛇元組裏面的座標(其實每次移動只用更新頭尾就行)。最後統一畫出來。移動作法具體是,咱們把每次頭部移動的新座標插入貪吃蛇元組,而後刪掉尾部一節(注意,刪除尾部咱們放在了另一個函數裏作)。

     1#移動貪吃蛇
    2def move_snake(direction, snake_coords):
    3    if direction == UP:
    4        newHead = {'x': snake_coords[HEAD]['x'], 'y': snake_coords[HEAD]['y'] - 1}
    5    elif direction == DOWN:
    6        newHead = {'x': snake_coords[HEAD]['x'], 'y': snake_coords[HEAD]['y'] + 1}
    7    elif direction == LEFT:
    8        newHead = {'x': snake_coords[HEAD]['x'] - 1'y': snake_coords[HEAD]['y']}
    9    elif direction == RIGHT:
    10        newHead = {'x': snake_coords[HEAD]['x'] + 1'y': snake_coords[HEAD]['y']}
    11    snake_coords.insert(0, newHead)
  • 開始階段
    先把貪吃蛇和食物的座標隨機生成,貪吃蛇一開始3節長,先設置向右移動。

  • 移動咱們的貪吃蛇
    監聽鍵盤,用戶按下鍵盤只是改變direction的值,再用move_snake(direction, snake_coords)函數更新貪吃蛇座標。若是不按,那direction值一直不變,貪吃蛇就一直向前走。

  • 相關判斷
    要判斷貪吃蛇是否掛了,表現爲:

    • 頭座標超出地圖範圍
    • 頭座標等於身體某節座標
     1    #判斷蛇死了沒
    2def snake_is_alive(snake_coords):
    3    tag = True
    4    if snake_coords[HEAD]['x'] == -1 or snake_coords[HEAD]['x'] == map_width or snake_coords[HEAD]['y'] == -1 or \
    5            snake_coords[HEAD]['y'] == map_height:
    6        tag = False # 蛇碰壁啦
    7    for snake_body in snake_coords[1:]:
    8        if snake_body['x'] == snake_coords[HEAD]['x'and snake_body['y'] == snake_coords[HEAD]['y']:
    9            tag = False # 蛇碰到本身身體啦
    10    return tag

    判斷貪吃蛇是否吃到食物,表現爲:

    • 頭座標等於食物座標,那麼吃到食物。這時候注意,咱們就不用刪尾部一節了,由於吃到食物變長了嘛。
    • 若是沒有吃到食物,那麼是正常移動,刪掉尾部一節座標。
    1    #判斷貪吃蛇是否吃到食物
    2def snake_is_eat_food(snake_coords, food):  #若是是列表或字典,那麼函數內修改參數內容,就會影響到函數體外的對象。
    3    if snake_coords[HEAD]['x'] == food['x'and snake_coords[HEAD]['y'] == food['y']:
    4        food['x'] = random.randint(0, map_width - 1)
    5        food['y'] = random.randint(0, map_height - 1# 實物位置從新設置
    6    else:
    7        del snake_coords[-1]  # 若是沒有吃到實物, 就向前移動, 那麼尾部一格刪掉
  • 畫出咱們的遊戲
    最後調用相關函數,講咱們的地圖,貪吃蛇,食物等等通通畫出來。

05 draw_snake-畫出咱們的貪吃蛇

直接看代碼:

1def draw_snake(screen, snake_coords):
2    for coord in snake_coords:
3        x = coord['x'] * cell_size
4        y = coord['y'] * cell_size
5        wormSegmentRect = pygame.Rect(x, y, cell_size, cell_size)
6        pygame.draw.rect(screen, dark_blue, wormSegmentRect)
7        wormInnerSegmentRect = pygame.Rect(                #蛇身子裏面的第二層亮藍色色
8            x + 4, y + 4, cell_size - 8, cell_size - 8)
9        pygame.draw.rect(screen, blue, wormInnerSegmentRect)

代碼很easy,主要是獲取相關座標,最後調用pygame.draw.rect將身體各個部分畫出來便可。不過爲了美觀,咱們選擇再在裏面畫一層不一樣顏色的,表現爲:

image

06 draw_food-畫出咱們的食物

1#將食物畫出來
2def draw_food(screen, food):
3    x = food['x'] * cell_size
4    y = food['y'] * cell_size
5    appleRect = pygame.Rect(x, y, cell_size, cell_size)
6    pygame.draw.rect(screen, Red, appleRect)

更簡單的代碼了,獲取位置,畫矩形。

07 draw_score-畫出咱們的成績

1#畫成績
2def draw_score(screen,score):
3    font = pygame.font.Font('myfont.ttf'30)
4    scoreSurf = font.render('得分: %s' % score, True, Green)
5    scoreRect = scoreSurf.get_rect()
6    scoreRect.topleft = (windows_width - 12010)
7    screen.blit(scoreSurf, scoreRect)

畫成績也比較簡單。得到Font對象之後,render寫字,最後設置位置,在屏幕上blit出來。

08 完整代碼

整個程序大致如上,其餘細枝末節直接看源代碼吧。

 1## 導入相關模塊
2import random
3import pygame
4import sys
5
6from pygame.locals import *
7
8
9snake_speed = 15 #貪吃蛇的速度
10windows_width = 800
11windows_height = 600 #遊戲窗口的大小
12cell_size = 20       #貪吃蛇身體方塊大小,注意身體大小必須能被窗口長寬整除
13
14''' #初始化區
15因爲咱們的貪吃蛇是有大小尺寸的, 所以地圖的實際尺寸是相對於貪吃蛇的大小尺寸而言的
16'''

17map_width = int(windows_width / cell_size)
18map_height = int(windows_height / cell_size)
19
20# 顏色定義
21white = (255255255)
22black = (000)
23gray = (230230230)
24dark_gray = (404040)
25DARKGreen = (01550)
26Green = (02550)
27Red = (25500)
28blue = (00255)
29dark_blue =(0,0139)
30
31
32BG_COLOR = black #遊戲背景顏色
33
34# 定義方向
35UP = 1
36DOWN = 2
37LEFT = 3
38RIGHT = 4
39
40HEAD = 0 #貪吃蛇頭部下標
41
42#主函數
43def main():
44    pygame.init() # 模塊初始化
45    snake_speed_clock = pygame.time.Clock() # 建立Pygame時鐘對象
46    screen = pygame.display.set_mode((windows_width, windows_height)) #
47    screen.fill(white)
48
49    pygame.display.set_caption("Python 貪吃蛇小遊戲"#設置標題
50    show_start_info(screen)               #歡迎信息
51    while True:
52        running_game(screen, snake_speed_clock)
53        show_gameover_info(screen)
54
55
56#遊戲運行主體
57def running_game(screen,snake_speed_clock):
58    startx = random.randint(3, map_width - 8#開始位置
59    starty = random.randint(3, map_height - 8)
60    snake_coords = [{'x': startx, 'y': starty},  #初始貪吃蛇
61                  {'x': startx - 1'y': starty},
62                  {'x': startx - 2'y': starty}]
63
64    direction = RIGHT       #  開始時向右移動
65
66    food = get_random_location()     #實物隨機位置
67
68    while True:
69        for event in pygame.event.get():
70            if event.type == QUIT:
71                terminate()
72            elif event.type == KEYDOWN:
73                if (event.key == K_LEFT or event.key == K_a) and direction != RIGHT:
74                    direction = LEFT
75                elif (event.key == K_RIGHT or event.key == K_d) and direction != LEFT:
76                    direction = RIGHT
77                elif (event.key == K_UP or event.key == K_w) and direction != DOWN:
78                    direction = UP
79                elif (event.key == K_DOWN or event.key == K_s) and direction != UP:
80                    direction = DOWN
81                elif event.key == K_ESCAPE:
82                    terminate()
83
84        move_snake(direction, snake_coords) #移動蛇
85
86        ret = snake_is_alive(snake_coords)
87        if not ret:
88            break #蛇跪了. 遊戲結束
89        snake_is_eat_food(snake_coords, food) #判斷蛇是否吃到食物
90
91        screen.fill(BG_COLOR)
92        #draw_grid(screen)
93        draw_snake(screen, snake_coords)
94        draw_food(screen, food)
95        draw_score(screen, len(snake_coords) - 3)
96        pygame.display.update()
97        snake_speed_clock.tick(snake_speed) #控制fps
98#將食物畫出來
99def draw_food(screen, food):
100    x = food['x'] * cell_size
101    y = food['y'] * cell_size
102    appleRect = pygame.Rect(x, y, cell_size, cell_size)
103    pygame.draw.rect(screen, Red, appleRect)
104#將貪吃蛇畫出來
105def draw_snake(screen, snake_coords):
106    for coord in snake_coords:
107        x = coord['x'] * cell_size
108        y = coord['y'] * cell_size
109        wormSegmentRect = pygame.Rect(x, y, cell_size, cell_size)
110        pygame.draw.rect(screen, dark_blue, wormSegmentRect)
111        wormInnerSegmentRect = pygame.Rect(                #蛇身子裏面的第二層亮綠色
112            x + 4, y + 4, cell_size - 8, cell_size - 8)
113        pygame.draw.rect(screen, blue, wormInnerSegmentRect)
114#畫網格(可選)
115def draw_grid(screen):
116    for x in range(0, windows_width, cell_size):  # draw 水平 lines
117        pygame.draw.line(screen, dark_gray, (x, 0), (x, windows_height))
118    for y in range(0, windows_height, cell_size):  # draw 垂直 lines
119        pygame.draw.line(screen, dark_gray, (0, y), (windows_width, y))
120#移動貪吃蛇
121def move_snake(direction, snake_coords):
122    if direction == UP:
123        newHead = {'x': snake_coords[HEAD]['x'], 'y': snake_coords[HEAD]['y'] - 1}
124    elif direction == DOWN:
125        newHead = {'x': snake_coords[HEAD]['x'], 'y': snake_coords[HEAD]['y'] + 1}
126    elif direction == LEFT:
127        newHead = {'x': snake_coords[HEAD]['x'] - 1'y': snake_coords[HEAD]['y']}
128    elif direction == RIGHT:
129        newHead = {'x': snake_coords[HEAD]['x'] + 1'y': snake_coords[HEAD]['y']}
130
131    snake_coords.insert(0, newHead)
132#判斷蛇死了沒
133def snake_is_alive(snake_coords):
134    tag = True
135    if snake_coords[HEAD]['x'] == -1 or snake_coords[HEAD]['x'] == map_width or snake_coords[HEAD]['y'] == -1 or \
136            snake_coords[HEAD]['y'] == map_height:
137        tag = False # 蛇碰壁啦
138    for snake_body in snake_coords[1:]:
139        if snake_body['x'] == snake_coords[HEAD]['x'and snake_body['y'] == snake_coords[HEAD]['y']:
140            tag = False # 蛇碰到本身身體啦
141    return tag
142#判斷貪吃蛇是否吃到食物
143def snake_is_eat_food(snake_coords, food):  #若是是列表或字典,那麼函數內修改參數內容,就會影響到函數體外的對象。
144    if snake_coords[HEAD]['x'] == food['x'and snake_coords[HEAD]['y'] == food['y']:
145        food['x'] = random.randint(0, map_width - 1)
146        food['y'] = random.randint(0, map_height - 1# 實物位置從新設置
147    else:
148        del snake_coords[-1]  # 若是沒有吃到實物, 就向前移動, 那麼尾部一格刪掉
149#食物隨機生成
150def get_random_location():
151    return {'x': random.randint(0, map_width - 1), 'y': random.randint(0, map_height - 1)}
152#開始信息顯示
153def show_start_info(screen):
154    font = pygame.font.Font('myfont.ttf'40)
155    tip = font.render('按任意鍵開始遊戲~~~'True, (65105225))
156    gamestart = pygame.image.load('gamestart.png')
157    screen.blit(gamestart, (14030))
158    screen.blit(tip, (240550))
159    pygame.display.update()
160
161    while True:  #鍵盤監聽事件
162        for event in pygame.event.get():  # event handling loop
163            if event.type == QUIT:
164                terminate()     #終止程序
165            elif event.type == KEYDOWN:
166                if (event.key == K_ESCAPE):  #終止程序
167                    terminate() #終止程序
168                else:
169                    return #結束此函數, 開始遊戲
170#遊戲結束信息顯示
171def show_gameover_info(screen):
172    font = pygame.font.Font('myfont.ttf'40)
173    tip = font.render('按Q或者ESC退出遊戲, 按任意鍵從新開始遊戲~'True, (65105225))
174    gamestart = pygame.image.load('gameover.png')
175    screen.blit(gamestart, (600))
176    screen.blit(tip, (80300))
177    pygame.display.update()
178
179    while True:  #鍵盤監聽事件
180        for event in pygame.event.get():  # event handling loop
181            if event.type == QUIT:
182                terminate()     #終止程序
183            elif event.type == KEYDOWN:
184                if event.key == K_ESCAPE or event.key == K_q:  #終止程序
185                    terminate() #終止程序
186                else:
187                    return #結束此函數, 從新開始遊戲
188#畫成績
189def draw_score(screen,score):
190    font = pygame.font.Font('myfont.ttf'30)
191    scoreSurf = font.render('得分: %s' % score, True, Green)
192    scoreRect = scoreSurf.get_rect()
193    scoreRect.topleft = (windows_width - 12010)
194    screen.blit(scoreSurf, scoreRect)
195#程序終止
196def terminate():
197    pygame.quit()
198    sys.exit()
199
200
201main()

 

欲獲取代碼,請關注咱們的微信公衆號【程序猿聲】,在後臺回覆:python貪吃蛇。python和貪吃蛇之間不要有空格,不要有空格,不要有空格!!!便可獲取。

  微信公衆號
相關文章
相關標籤/搜索