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

更新於 發佈於 閱讀時間約 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
現代社會跟以前不同了,人人都有一支手機,只要打開就可以獲得各種資訊。過去想要辦卡或是開戶就要跑一趟銀行,然而如今科技快速發展之下,金融App無聲無息地進到你生活中。但同樣的,每一家銀行都有自己的App時,我們又該如何選擇呢?(本文係由國泰世華銀行邀約) 今天我會用不同角度帶大家看這款國泰世華CUB
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
河內塔的遊戲描述 有三個柱子A柱,B柱,C柱。 A柱上有 N 個 (N>1) 穿孔圓盤,盤的尺寸由下到上依次變小。 要求按下列規則透過合法移動,將所有圓盤移至 C 柱: 1. 每次只能移動頂端的一個圓盤; 2. 大圓盤不能疊在小圓盤上面。
Thumbnail
今天要實作和體驗的是拼單字的小遊戲,類似小時候在報紙、英文童書、或著電子辭典的小遊戲,一開始都是空白,隨著使用者拼對而逐漸顯示原本的單字樣貌,直到整個單字拼出來為止。 場景: 電腦隨機從單字庫裡面撈一個單字出來。 讓使用者扮演玩家去玩拼單字的遊戲。
Thumbnail
相信大家小時候都有和朋友或玩伴玩過一個猜數字的小遊戲,一個人先在1~100裡面設定一個隱藏數字,其他的人去猜,看誰是最後一個猜中的就算輸,或者看誰最快猜中就算贏。 今天要示範如何用Python寫一個猜數字遊戲, 並且會從上層的思考邏輯開始,一步步構建出這個猜數字的小遊戲。
Thumbnail
閱讀與桌遊 讀動物農莊,三隻小豬 玩,養豬趣 滿滿的了大豬小豬 「養豬趣」是台灣人發明設計的桌遊。 . 遊戲分春夏秋冬進行, 回合數分別是三春四夏四秋四冬。 而每個回合時玩家將有四個行動可以選擇。 大家一起暗選一個後,一次打開自己的行動牌, 如有多個人將會按照人數評
Thumbnail
嗨嗨打給賀!挖系Serpens Spirit Studio ㄉ蛇靈~~ 蛇靈的最終目標是想製作出自己的遊戲,所以來和大家分享我的遊戲遊玩觀察&研究小筆記! 【攻擊提示&UI介面明顯】 音樂聲提醒敵人來了 固定顏色(遊戲中是黃色)提示玩家可以運用這裡通關 兩個角色的座標顏色固定,媽媽(木頭玩
tzu在這個月踏上了學習之路,主要學習了Python、Azure服務和身份存取管理等領域,以及制定了短期目標。本文將分享她的學習進度和未來計劃。
Thumbnail
本文介紹一款體驗遊戲,從STEAM商店獲得。 好玩一直玩,長時間不建議,休閒沒壓力最讚 歡迎一起玩合作性遊戲!
Thumbnail
臺北萬華的忍者主題密室挑戰,不僅引用了日本傳奇故事,還提供了更多忍者的物理小道具去操作謎題,讓整體的氛圍更貼近忍者的樸實無華感。值得注意的是,在解謎的過程中,要隨時觀察隊友的操作,以避免出現困難。除此之外,遊戲中還有很多模擬忍者操作,讓人沈浸其中的操作感。
Thumbnail
這篇文章分享了一個研究所的遊戲專案,是關於以作者家的貓為主題的遊戲,概念企劃書內容請見PPT。作者雖表示專案進度緩慢,但仍對遊戲的潛力充滿信心,並邀請有興趣的人一同參與。
Thumbnail
這段時間我一直分享我在霍格華茲世界裡的過程,今天就來轉換一下遊戲! 最近寵物島昨天剛剛過完全主題復刻一天,因為只有一天時間,再加上目前現有主題中還有許多快結束的主題我還沒抽完,昨天的復刻只有抽兩次而已,不過很幸運我抽到一顆樹啦! 而現在寵物島迎來新寵物「水神大蛇」。這條蛇蛇實在是太可愛啦~(尖叫
Thumbnail
現代社會跟以前不同了,人人都有一支手機,只要打開就可以獲得各種資訊。過去想要辦卡或是開戶就要跑一趟銀行,然而如今科技快速發展之下,金融App無聲無息地進到你生活中。但同樣的,每一家銀行都有自己的App時,我們又該如何選擇呢?(本文係由國泰世華銀行邀約) 今天我會用不同角度帶大家看這款國泰世華CUB
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
河內塔的遊戲描述 有三個柱子A柱,B柱,C柱。 A柱上有 N 個 (N>1) 穿孔圓盤,盤的尺寸由下到上依次變小。 要求按下列規則透過合法移動,將所有圓盤移至 C 柱: 1. 每次只能移動頂端的一個圓盤; 2. 大圓盤不能疊在小圓盤上面。
Thumbnail
今天要實作和體驗的是拼單字的小遊戲,類似小時候在報紙、英文童書、或著電子辭典的小遊戲,一開始都是空白,隨著使用者拼對而逐漸顯示原本的單字樣貌,直到整個單字拼出來為止。 場景: 電腦隨機從單字庫裡面撈一個單字出來。 讓使用者扮演玩家去玩拼單字的遊戲。
Thumbnail
相信大家小時候都有和朋友或玩伴玩過一個猜數字的小遊戲,一個人先在1~100裡面設定一個隱藏數字,其他的人去猜,看誰是最後一個猜中的就算輸,或者看誰最快猜中就算贏。 今天要示範如何用Python寫一個猜數字遊戲, 並且會從上層的思考邏輯開始,一步步構建出這個猜數字的小遊戲。
Thumbnail
閱讀與桌遊 讀動物農莊,三隻小豬 玩,養豬趣 滿滿的了大豬小豬 「養豬趣」是台灣人發明設計的桌遊。 . 遊戲分春夏秋冬進行, 回合數分別是三春四夏四秋四冬。 而每個回合時玩家將有四個行動可以選擇。 大家一起暗選一個後,一次打開自己的行動牌, 如有多個人將會按照人數評
Thumbnail
嗨嗨打給賀!挖系Serpens Spirit Studio ㄉ蛇靈~~ 蛇靈的最終目標是想製作出自己的遊戲,所以來和大家分享我的遊戲遊玩觀察&研究小筆記! 【攻擊提示&UI介面明顯】 音樂聲提醒敵人來了 固定顏色(遊戲中是黃色)提示玩家可以運用這裡通關 兩個角色的座標顏色固定,媽媽(木頭玩
tzu在這個月踏上了學習之路,主要學習了Python、Azure服務和身份存取管理等領域,以及制定了短期目標。本文將分享她的學習進度和未來計劃。
Thumbnail
本文介紹一款體驗遊戲,從STEAM商店獲得。 好玩一直玩,長時間不建議,休閒沒壓力最讚 歡迎一起玩合作性遊戲!
Thumbnail
臺北萬華的忍者主題密室挑戰,不僅引用了日本傳奇故事,還提供了更多忍者的物理小道具去操作謎題,讓整體的氛圍更貼近忍者的樸實無華感。值得注意的是,在解謎的過程中,要隨時觀察隊友的操作,以避免出現困難。除此之外,遊戲中還有很多模擬忍者操作,讓人沈浸其中的操作感。
Thumbnail
這篇文章分享了一個研究所的遊戲專案,是關於以作者家的貓為主題的遊戲,概念企劃書內容請見PPT。作者雖表示專案進度緩慢,但仍對遊戲的潛力充滿信心,並邀請有興趣的人一同參與。
Thumbnail
這段時間我一直分享我在霍格華茲世界裡的過程,今天就來轉換一下遊戲! 最近寵物島昨天剛剛過完全主題復刻一天,因為只有一天時間,再加上目前現有主題中還有許多快結束的主題我還沒抽完,昨天的復刻只有抽兩次而已,不過很幸運我抽到一顆樹啦! 而現在寵物島迎來新寵物「水神大蛇」。這條蛇蛇實在是太可愛啦~(尖叫