不間斷 Python 挑戰 Day 25 - 專題:貪食蛇(上)

更新於 2022/11/10閱讀時間約 13 分鐘
接下來我們會運用之前所學過的各種觀念,包括Turtle 模組繼承等等,來製作這個大家都熟知的小遊戲-貪食蛇。完成品會長得像下圖這樣,包括可以設定難度(速度)、使用鍵盤的上、下、左、右鍵來移動貪食蛇的移動方向來吃到食物並加長蛇身、以及記分板等。

遊戲架構

這個遊戲到目前為止算是一個稍微複雜的程式,將程式的邏輯拆解成一些較簡單的功能,再將這些功能組合起來,會比較利於遊戲設計的進行,以免不知道從何下手。這篇文章會以以下的流程來說明:
  1. 建立遊戲進行的畫布
  2. 建立遊戲難度設定視窗
  3. 畫出遊戲開始時的貪食蛇身體
  4. 畫出圍牆
  5. 隨機產生食物
  6. 移動蛇身
  7. 控制方向
  8. 檢查是否吃到食物
  9. 建立記分板
  10. 檢查是否撞到牆
  11. 檢查是否撞到蛇身
  12. 結束遊戲

建立遊戲進行的畫布

從Turtle模組載入Screen類別,建立一個600*600大小的畫布,並設定標題與背景顏色,這個畫布就是讓遊戲進行的區域。tracer()方法的目的是暫停畫布的更新,讓後續在畫布上所改變的內容可使用update()方法一次更新,以減少視覺上的延遲感。
# 主程式
from turtle import Screen
# 遊戲參數
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 600
SCREEN_COLOR = "black"
SCREEN_TITLE = "貪食蛇"
# 建立Screen物件
snake_screen = Screen()
# 遊戲畫面設定
snake_screen.setup(width=SCREEN_WIDTH, height=SCREEN_HEIGHT)
snake_screen.bgcolor(SCREEN_COLOR)
snake_screen.title(SCREEN_TITLE)
snake_screen.tracer(0)
# 畫面暫停
snake_screen.exitonclick()

建立遊戲難度設定視窗

在這裡我們要讓使用者輸入遊戲的難度,所以必須另開一個對話視窗和使用者互動,並把輸入的內容做為參數傳入程式。在Screen類別中,可以使用textinput()方法來達成這個目標,用法如下:
turtle.textinput(title, prompt)
  • title – 對話視窗的標題
  • prompt – 對話視窗內顯示的文字
在這裡我們以1到9來代表遊戲的難度,並把輸入的內容存入變數,換算成畫面更新的時間間隔,接著就可以建立主程式的while迴圈,根據難度所換算出來的固定時間間隔更新畫面。
# 主程式
import time
# 遊戲難度
level = snake_screen.textinput(title="貪食蛇-遊戲難度", prompt="請選擇遊戲難度:1(簡單) ~ 9(困難)")
time_delay = (10 - float(level)) * 0.05
# 遊戲主程式
is_game_on = True
while is_game_on:
  # 遊戲畫面更新
  snake_screen.update()
  time.sleep(time_delay)

畫出遊戲開始時的貪食蛇身體

為了簡潔起見,我們在主程式所在的目錄底下建立一個snake資料夾,把所有和這個專題相關的檔案都放在這個資料夾中,在主程式中導入。
蛇身的屬性和操作可以視為一個功能單位,因此首先在snake資料夾中新增一個snake.py檔案,在其中建立一個Snake類別,在初始化中定義三個Turtle物件做為蛇身,並適當設定三個物件的距離,讓蛇身可以連在一起。
# snake.py
from turtle import Turtle
START_POSITION = [(0, 0), (-20, 0), (-40, 0)]
class Snake:
  def __init__(self):
    self.snake_body = []
    self.create_snake()
    self.head = self.snake_body[0]
    self.move_angle_list = []
  def create_snake(self):
    for position in START_POSITION:
      self.add_snake_body(position)
  def add_snake_body(self, position):
    body_seg = Turtle(shape="square")
    body_seg.color("Green")
    body_seg.penup()
    body_seg.goto(position)
    self.snake_body.append(body_seg)
在Snake類別中特別把add_snake_body()獨立成一個方法,因為之後在延長蛇身時會重覆使用同一段程式碼。在主程式中載入Snake類別,並建立一個Snake物件。
# 主程式
from snake.snake import Snake
# 建立遊戲相關物件
snake = Snake()
執行後,可以在畫布上看到一段遊戲開始時的小蛇。

畫出圍牆

圍牆同樣也具有獨立的屬性與功能,它在遊戲一開始建立後就不會再更動,目的是要讓蛇頭碰觸到圍牆後即觸發遊戲結束,因此圍牆的範圍需要考慮畫布的大小。我們同樣在snake資料夾中新增一個wall.py檔案,在其中建立Wall類別,讓它繼承自Turtle模組,以方便使用Turtle模組的所有功能,不須額外新增Turtle物件。Wall類別在初始化時從主程式傳入畫布的大小,以畫筆在畫布的四周圈出一個長方形的區域,這個區域即是貪食蛇可以在其中自由移動的範圍,注意上方預留了較大的空間,是顯示記分板文字的位置。
# wall.py
from turtle import Turtle
WALL_COLOR = "BlueViolet"
WALL_PEN_SIZE = 10
class Wall(Turtle):
  def __init__(self, width, height):
    super().__init__()
    self.hideturtle()
    self.pensize(WALL_PEN_SIZE)
    self.color(WALL_COLOR)
    self.speed("fastest")
    self.screen_width = width
    self.screen_height = height
    self.draw()
  def draw(self):
    self.penup()
    self.goto(-(self.screen_width / 2 - 25), self.screen_height / 2 - 45)
    self.pendown()
    self.forward(self.screen_width - 50)
    self.setheading(270)
    self.forward(self.screen_height - 70)
    self.setheading(180)
    self.forward(self.screen_width - 50)
    self.setheading(90)
    self.forward(self.screen_width - 70)
主程式中建立Wall類別的物件,即可在畫布四周畫出圍牆。
# 主程式
from snake.wall import Wall
# 建立遊戲相關物件
wall = Wall(SCREEN_WIDTH, SCREEN_HEIGHT)

隨機產生食物

食物必須隨機在圍牆內產生,由前一小節圍牆的設定可知,畫筆在四個頂點的座標分別為:左上(-275, 255)、右上(275, 255)、左下(-275, -275)、右下(275, -275),畫筆的寬度為10,所以圍牆內緣的座標為:左上(-270, 250)、右上(270, 250)、左下(-270, -270)、右下(270, -270),每一個蛇身的物件距離為20,因此產生食物的範圍必須再內縮10(蛇身的一半),也就是x座標在[-260, 260]、y座標在[-260, 240]這個區間內產生食物。此外,為了之後配合貪食蛇每次行走的距離,也就是一個蛇身的長度20,讓蛇身和食物可以對齊,我們利用一個ALIGNMENT_FACTOR讓出現食物的座標皆為20的整數倍。
# food.py
import random
from turtle import Turtle
FOOD_SHAPE = "circle"
FOOD_COLOR = "gold"
ALIGNMENT_FACTOR = 20
class Food(Turtle):
  def __init__(self, width, height):
    super().__init__()
    self.shape(FOOD_SHAPE)
    self.penup()
    self.color(FOOD_COLOR)
    self.speed("fastest")
    self.screen_width = width
    self.screen_height = height
    self.random_food()
  def random_food(self):
    random_x = random.randint(-(self.screen_width / 2 - 40), (self.screen_width / 2 - 40))
    random_x = ALIGNMENT_FACTOR * round(random_x / ALIGNMENT_FACTOR)
    random_y = random.randint(-(self.screen_height / 2 - 40), (self.screen_width / 2 - 60))
    random_y = ALIGNMENT_FACTOR * round(random_y / ALIGNMENT_FACTOR)
    self.goto(random_x, random_y)
主程式中建立Food類別的物件,即可隨機出現第一個食物。
# 主程式
from snake.food import Food
# 建立遊戲相關物件
food = Food(SCREEN_WIDTH, SCREEN_HEIGHT)

移動蛇身

先不考慮方向,若要讓蛇身往前移動,以目前的三節身體來說,就是讓第三節的身體往第二節身體移動、第二節身體往蛇頭移動、蛇頭往前移動一個單位,更多節的身體也可以以此類推,因此在Snake類別中新增move()方法實現以上邏輯。
# snake.py
MOVE_DISTANCE = 20
class Snake:
  def move(self):
    # 往前移動
    for body_seg in range(len(self.snake_body) - 1, 0, -1):
      new_x = self.snake_body[body_seg - 1].xcor()
      new_y = self.snake_body[body_seg - 1].ycor()
      self.snake_body[body_seg].goto(new_x, new_y)
    self.head.forward(MOVE_DISTANCE)
在主程式的while迴圈中呼叫Snake類別的move()方法,執行後可以看到三節的小蛇一路往前移動到超出畫布範圍。
# 主程式
# 遊戲主程式
is_game_on = True
while is_game_on:
  # 遊戲畫面更新
  snake_screen.update()
  time.sleep(time_delay)
  snake.move()
接著還有六個步驟,留待下篇文章說明!
為什麼會看到廣告
avatar-img
47會員
36內容數
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
Wei-Jie Weng的沙龍 的其他內容
Turtle Graphic的前身是一種設計給小朋友學習的簡易繪圖程式,最初來自於Wally Feurzeig、Seymour Papert和Cynthia Solomon於1967年所創造的Logo編程語言,它是Python內建的繪圖函式庫,我們可以根據函式庫裡面的指令,操控一隻或多隻「小烏龜」在
「繼承」顧名思義就是有一個或多個類別延續了某個類別的特性,就如同在人類社會裡,兒女接收了父母的財產、承襲了上代的技能、延續了前一輩的事業。在Python的語言裡,能夠繼承的特性為類別的屬性與方法,繼承的類別稱為子類別(child class / subclass)或衍伸類別(derived clas
在類別一節中,我們可以用Student類別的實體來存取類別中的name變數、score字典、以及其中的所有方法,這些可以被類別以外的程式碼所直接存取的屬性稱為公有屬性(public attribute)、可以被類別以外的程式碼所直接呼叫的方法稱為公有方法(public method)。
大型程式的開發通常不會由一個人獨力完成,而是將程式依功能拆分成不同的函數或是類別,由不同人協力開發成各個模組,最後再將這些模組導入主程式,或是直接套用現有的模組。模組依來源可以分成三大類: Python內建的模組 外部模組,需從第三方的軟體儲存庫(如PyPI)並安裝使用 程式開發者自行開發的模組
全球公衛教授和公共教育家漢斯.羅斯林(Hans Rosling)在其著名的暢銷書「真確」中,提出了13個關於全球貧富、人口、出生/死亡率、教育、公衛等的「留意認知落差測驗」,回答的人不乏受過良好教育的專業人士,結果顯示,受測者在前12題平均只答對2題,遠不如隨機亂選的黑猩猩(如果黑猩猩會回答問題的話
到目前為止,我們所學習的都是程序性的程式設計(procedural programming),也就是程式碼是透過一連串的指令組成的程序或函數,由上而下依序執行不同的程序或是呼叫函數來完成程式的功能。 Python其實是一種物件導向的程式(object oriented programming, 簡稱
Turtle Graphic的前身是一種設計給小朋友學習的簡易繪圖程式,最初來自於Wally Feurzeig、Seymour Papert和Cynthia Solomon於1967年所創造的Logo編程語言,它是Python內建的繪圖函式庫,我們可以根據函式庫裡面的指令,操控一隻或多隻「小烏龜」在
「繼承」顧名思義就是有一個或多個類別延續了某個類別的特性,就如同在人類社會裡,兒女接收了父母的財產、承襲了上代的技能、延續了前一輩的事業。在Python的語言裡,能夠繼承的特性為類別的屬性與方法,繼承的類別稱為子類別(child class / subclass)或衍伸類別(derived clas
在類別一節中,我們可以用Student類別的實體來存取類別中的name變數、score字典、以及其中的所有方法,這些可以被類別以外的程式碼所直接存取的屬性稱為公有屬性(public attribute)、可以被類別以外的程式碼所直接呼叫的方法稱為公有方法(public method)。
大型程式的開發通常不會由一個人獨力完成,而是將程式依功能拆分成不同的函數或是類別,由不同人協力開發成各個模組,最後再將這些模組導入主程式,或是直接套用現有的模組。模組依來源可以分成三大類: Python內建的模組 外部模組,需從第三方的軟體儲存庫(如PyPI)並安裝使用 程式開發者自行開發的模組
全球公衛教授和公共教育家漢斯.羅斯林(Hans Rosling)在其著名的暢銷書「真確」中,提出了13個關於全球貧富、人口、出生/死亡率、教育、公衛等的「留意認知落差測驗」,回答的人不乏受過良好教育的專業人士,結果顯示,受測者在前12題平均只答對2題,遠不如隨機亂選的黑猩猩(如果黑猩猩會回答問題的話
到目前為止,我們所學習的都是程序性的程式設計(procedural programming),也就是程式碼是透過一連串的指令組成的程序或函數,由上而下依序執行不同的程序或是呼叫函數來完成程式的功能。 Python其實是一種物件導向的程式(object oriented programming, 簡稱
你可能也想看
Google News 追蹤
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
十年前,我跟小悟參加了台南政府所舉辦的 24 小時不間斷進食比賽,當年,我以兩分之差,沒擠進金榜。在挑戰時間內,來不及吃狀元糕跟芋頭八寶冰,以致失掉食物王的頭銜。十年後,小悟說,要不要再來回味當年勇?我知道,年輕的我胃袋能撐船,可逝去的青春,最先反映在食慾上。我笑著說不了......
Thumbnail
持著前作的風格,《蜘蛛人:穿越新宇宙》在色彩或畫面的呈現上依舊大膽、前衛,並且嘗試藉由多重宇宙的「優勢」,在成長動畫的既有敘事上,嘗試更多不同的可能性。精彩的安排讓觀看這部作品讓成為十足的享受,並賦予了觀眾再次進場支持的充分動機。
Thumbnail
節目這邊聽 📎錄製時間: 2023.10 汪汪隊立大功! MRT(Mission Readiness Test)是難度最高的國際搜救犬認證! 但是我們有兩位英雄(一人一汪)順利通過這次的認證,拿到了優良的成績! 讓我們歡迎領犬員羅浩芳!就讓她帶著小編、江小姐還有各位聽眾,一起了解這次搜救犬
Thumbnail
這一陣子不少投資標的都在上漲 連成長性沒有科技股強的食品股也在慢慢上升中 今天記錄一下自己食品股大成的最新績效 身為雞肉雙雄的其中一雄 除了飼料、雞肉、雞蛋以外,還跨足了沙拉油、豬肉、海鮮、餐廳等事業體 幾乎可說是一檔食品ETF(還不用付管理費),進去它的官網就可以看到許多不同的事業體
Thumbnail
你現在也許單一個句子可以說得溜,但持續說話覺得尷尬的原因在於:缺乏連接詞。好的連接詞會讓口語表達更精確有力,讓韓國人聽到你說的話不需要猜測意思或重新思考,表達能力也就跟著上升!
Thumbnail
喜歡音樂的羅小咩,不定期將在周六中午12:00與你聊聊戲劇中的音樂,還有音樂中的戲劇。本次介紹:惡作劇之吻、慶餘年、Good Casting、溫柔時光、鋼之鍊金術師這五個戲劇作品的主題曲。
Thumbnail
喜歡音樂的羅小咩,不定期將在周六中午12:00與你聊聊戲劇中的音樂,還有音樂中的戲劇。本次介紹:必娶女人、kill me heal me、錦衣之下、101次求婚、灌籃高手這五個戲劇作品的主題曲。
近期許多地方受到洪水以及颱風的侵襲 但包你發的線路及網路穩定度完全不受到影響 大家可以放心,我們是24小時全年無休不間斷 就算你半夜三點要玩包你發也完全OK 不會像有些系統只在白天開放 而同樣的穩定度也是一大考驗 在這種供電不穩定的情況 也有可能導致其他遊戲斷線 但包你發機房穩定、有備用電源 完全不
Thumbnail
疫情長時間帶來了減少開放性的社交機會,最直接的影響莫過於情緒勒索造成的封閉性失調,感謝國立台灣戲曲學院傑出校友,為身心障礙的大寶寶們帶來一系列精彩的演出,透過精心策劃的舞蹈及雜耍表演,帶給住民體驗了跟以往不同的志工服務內容,見到了久違住民
Thumbnail
每一次TDCA的關愛陪伴,都讓受贈的服務對象感受到滿滿的幸福感,一起協力完成手作皮革鑰匙圈,每一針每一線都在訓練孩子們手眼協調的肢體,透過不同花色皮革來搭配,不僅訓練孩子對色彩的辨識能力,同時也在培養眼界裡的審美觀噢!
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
十年前,我跟小悟參加了台南政府所舉辦的 24 小時不間斷進食比賽,當年,我以兩分之差,沒擠進金榜。在挑戰時間內,來不及吃狀元糕跟芋頭八寶冰,以致失掉食物王的頭銜。十年後,小悟說,要不要再來回味當年勇?我知道,年輕的我胃袋能撐船,可逝去的青春,最先反映在食慾上。我笑著說不了......
Thumbnail
持著前作的風格,《蜘蛛人:穿越新宇宙》在色彩或畫面的呈現上依舊大膽、前衛,並且嘗試藉由多重宇宙的「優勢」,在成長動畫的既有敘事上,嘗試更多不同的可能性。精彩的安排讓觀看這部作品讓成為十足的享受,並賦予了觀眾再次進場支持的充分動機。
Thumbnail
節目這邊聽 📎錄製時間: 2023.10 汪汪隊立大功! MRT(Mission Readiness Test)是難度最高的國際搜救犬認證! 但是我們有兩位英雄(一人一汪)順利通過這次的認證,拿到了優良的成績! 讓我們歡迎領犬員羅浩芳!就讓她帶著小編、江小姐還有各位聽眾,一起了解這次搜救犬
Thumbnail
這一陣子不少投資標的都在上漲 連成長性沒有科技股強的食品股也在慢慢上升中 今天記錄一下自己食品股大成的最新績效 身為雞肉雙雄的其中一雄 除了飼料、雞肉、雞蛋以外,還跨足了沙拉油、豬肉、海鮮、餐廳等事業體 幾乎可說是一檔食品ETF(還不用付管理費),進去它的官網就可以看到許多不同的事業體
Thumbnail
你現在也許單一個句子可以說得溜,但持續說話覺得尷尬的原因在於:缺乏連接詞。好的連接詞會讓口語表達更精確有力,讓韓國人聽到你說的話不需要猜測意思或重新思考,表達能力也就跟著上升!
Thumbnail
喜歡音樂的羅小咩,不定期將在周六中午12:00與你聊聊戲劇中的音樂,還有音樂中的戲劇。本次介紹:惡作劇之吻、慶餘年、Good Casting、溫柔時光、鋼之鍊金術師這五個戲劇作品的主題曲。
Thumbnail
喜歡音樂的羅小咩,不定期將在周六中午12:00與你聊聊戲劇中的音樂,還有音樂中的戲劇。本次介紹:必娶女人、kill me heal me、錦衣之下、101次求婚、灌籃高手這五個戲劇作品的主題曲。
近期許多地方受到洪水以及颱風的侵襲 但包你發的線路及網路穩定度完全不受到影響 大家可以放心,我們是24小時全年無休不間斷 就算你半夜三點要玩包你發也完全OK 不會像有些系統只在白天開放 而同樣的穩定度也是一大考驗 在這種供電不穩定的情況 也有可能導致其他遊戲斷線 但包你發機房穩定、有備用電源 完全不
Thumbnail
疫情長時間帶來了減少開放性的社交機會,最直接的影響莫過於情緒勒索造成的封閉性失調,感謝國立台灣戲曲學院傑出校友,為身心障礙的大寶寶們帶來一系列精彩的演出,透過精心策劃的舞蹈及雜耍表演,帶給住民體驗了跟以往不同的志工服務內容,見到了久違住民
Thumbnail
每一次TDCA的關愛陪伴,都讓受贈的服務對象感受到滿滿的幸福感,一起協力完成手作皮革鑰匙圈,每一針每一線都在訓練孩子們手眼協調的肢體,透過不同花色皮革來搭配,不僅訓練孩子對色彩的辨識能力,同時也在培養眼界裡的審美觀噢!