網站首頁 編程語言 正文
1. 前言
turtle?(小海龜) 是?Python?內置的一個繪圖模塊,其實它不僅可以用來繪圖,還可以制作簡單的小游戲,甚至可以當成簡易的?GUI?模塊,編寫簡單的?GUI程序。
本文使用?turtle?模塊編寫一個簡單的小游戲,通過此程序的編寫過程聊一聊對?turtle?模塊的感悟。
編寫游戲,如果要做專業的、趣味性高的,還是請找?pygame,本文用?turtle?編寫游戲的目的是為了深度理解?turtle?的功能。
turtle?模塊的使用相對而言較簡單,對于基礎方法不做講解。只聊?turtle?模塊中稍難或大家忽視的地方。
2. 需求描述
程序運行時,畫布上會出現一個紅色的小球和很多綠色、藍色的小球。
剛開始紅色的小球會朝某一個方向移動,使用者可以通過按下上、下、左、右方向鍵控制紅色小球的運動方向。
綠色、藍色小球以初始的默認方向在畫布上移動。
當紅色的小球碰到綠色小球時,紅色小球球體會變大,當紅色小球碰到藍色小球時,紅色球體會變小。
當紅色小球球體縮小到某一個閾值時,游戲結束。
3. 制作流程
3.1 初始化變量
本程序需要使用到?turtle、random、math?模塊,使用之前,先導入。
import turtle import random import math ''' 初始化游戲界面大小 ''' # 游戲區域的寬度 game_wid = 600 # 游戲區域的高度 game_hei = 400 # 磚塊的大小,以及每一個小球初始大小 cell = 20 # 紅球初始大小 red_size = cell # 紅色小球 red_ball = None # 存儲綠色小球的列表 green_balls = [] # 存儲藍色小球的列表 blue_balls = [] # 紅色小球的方向 當前方向 0 向右,90 向上 180 向左 -90 向下 dir = 0
上述代碼說明:
紅色小球只有一個,由變量?red_ball
?保存,紅色小球在運動過程中可以改大小,red_size
?保存其大小。
綠色和藍色小球會有很多,這里使用?green_balls
?和?blue_balls
?2 個列表存儲。
3.2 通用函數
隨機位置計算函數:?為小球們隨機生成剛開始出現的位置。
''' 隨機位置計算函數 ''' def rand_pos(): # 水平有 30 個單元格,垂直有 20 個單元格 x = random.randint(-14, 14) y = random.randint(-9, 9) return x * cell, y * cell
繪制指定填充顏色的小正方形:?在游戲里有一個虛擬區域,四周使用很多小正方形圍起來。
''' 繪制一個指定填充顏色的正方形 填充顏色可以不指定 ''' def draw_square(color): if color is not None: # 的顏色就填充 turtle.fillcolor(color) turtle.begin_fill() for i in range(4): turtle.fd(cell) turtle.left(90) if color is not None: turtle.end_fill()
自定義畫筆形狀:
使用?turtle?制作游戲的底層思想:
當我們導入?turtle
?模塊時,意味著我們有了一支可以在畫布上畫畫的畫筆,畫筆的默認形狀是一個小海龜。
本文稱這支默認畫筆叫主畫筆,可以使用?turtle
?模塊中的?turtle.Turtle()
?類創建更多畫筆 ,并且可以使用 ``turtle模塊提供的
turtle.register_shape(name, shape)` 方法為每一支畫筆定制畫筆形狀。
如上所述,是使用?turtle
?設計游戲的關鍵。
強調一下:
通過主畫筆創建更多的畫筆,以及為每一支畫筆設置不同的形狀。是編寫游戲的關鍵,游戲中的每一個角色,其本質是一支支畫筆,我們只是在控制畫筆在畫布上按我們設計好的軌跡移動。
本游戲中紅、綠、藍 3 種顏色的小球就是形狀為圓形的畫筆。
畫筆清單:
紅色小球畫筆一支。
綠色小球畫筆 n 支。
藍色小球畫筆 n 支。
''' 自定義畫筆形狀 name:畫筆名稱 color:可選項 ''' def custom_shape(name, size): turtle.begin_poly() turtle.penup() turtle.circle(size) turtle.end_poly() cs = turtle.get_poly() turtle.register_shape(name, cs)
turtle.register_shape(name, shape)
?方法參數說明:
- name:?自定義形狀的名稱。
- shape:?由開發者繪制的形狀。
開發者繪制的哪一部分圖形用來充當畫筆形狀?
由?turtle.begin_poly()?記錄的第一點到由?turtle.end_poly()?記錄的最后一點之間的圖形作為畫筆形狀。
cs = turtle.get_poly()
?可以理解為獲取到剛繪制的圖形,然后使用?turtle.register_shape(name, cs)
?注冊畫筆形狀,以后就可以隨時使用此形狀。
如上代碼記錄了一個圓的繪制過程,也就是創建了一個圓形的畫筆形狀。
移動到某個位置函數:
此函數用來讓某一支畫筆移到指定位置,不留下移動過程中的軌跡。
''' 移到某點 ''' def move_pos(pen, pos): pen.penup() pen.goto(pos) pen.pendown()
參數說明:
-
pen
?: 畫筆對象。 -
pos
:要移到的目標地。
注冊鍵盤事件函數:
使用者可以通過鍵盤上的方向鍵更改紅色小球的方向。
turtle
?模塊提供有很多事件,可以以交互式的方式使用turtle
。turtle
?模塊中主要有 2 類事件:鍵盤事件、點擊事件。因?turtle
?的工作重點還是繪制靜態圖案上,其動畫繪制比較弱,所以它的事件少而簡單。
''' 改變紅色小球 4 方向的函數, 這些函數只有當使用者觸發按鍵后方可調用,故這些函數也稱為回調函數。 ''' def dir_right(): global dir dir = 0 def dir_left(): global dir dir = 180 def dir_up(): global dir dir = 90 def dir_down(): global dir dir = -90 ''' 注冊鍵盤響應事件,用來改變紅球的方向 ''' def register_event(): for key, f in {"Up": dir_up, "Down": dir_down, "Left": dir_left, "Right": dir_right}.items(): turtle.onkey(f, key) turtle.listen() ''' 當紅色小球遇到墻體后,也要修改方向 ''' def is_meet_qt(): global dir if red_ball.xcor() < -220: dir = 0 if red_ball.xcor() > 240: dir = 180 if red_ball.ycor() > 140: dir = -90 if red_ball.ycor() < -120: dir = 90
紅色的小球在 2 個時間點需要改變方向,一是使用者按下了方向鍵,一是碰到了墻體。
3.3 游戲角色函數
繪制墻體函數:
墻體是游戲中的虛擬區域,用來限制小球的活動范圍。
Tips:?墻體由主畫筆繪制。
''' 繪制四面的墻體 ''' def draw_blocks(): # 隱藏畫筆 turtle.hideturtle() # 上下各30個單元格,左右各 20 個單元格 for j in [30, 20, 30, 20]: for i in range(j): # 調用前面繪制正方形的函數 draw_square('gray') turtle.fd(cell) turtle.right(90) turtle.fd(-cell) # 回到原點 move_pos(turtle, (0, 0))
創建小球畫筆:?此函數用來創建新畫筆。本程序中的紅色、藍色、綠色小球都是由此函數創建的畫筆,且外觀形狀是圓。
def init_ball(pos, color, shape): # 由主畫筆創建新畫筆 ball = turtle.Turtle() ball.color(color) # 指定新畫筆的形狀,如果不指定,則為默認形狀 ball.shape(shape) # 移到隨機位置 move_pos(ball, pos) # 移動過程要不顯示任何軌跡 ball.penup() return ball
參數說明:
-
pos
:?創建畫筆后畫筆移動的位置。 -
color
:指定畫筆和填充顏色。 -
shape
:?已經定義好的畫筆形狀名稱。
創建綠色、藍色小球:
def ran_gb_ball(balls, color): # 隨機創建藍色、綠色小球的頻率, # 也就是說,不是調用此函數就一定會創建小球,概率大概是調用 5 次其中會有一次創建 ran = random.randint(1, 5) # 隨機一個角度 a = random.randint(0, 360) # 1/5 的概率 if ran == 5: turtle.tracer(False) # 每一個小球就是一只畫筆 ball = init_ball(rand_pos(), color, 'ball') ball.seth(a) # 添加到列表中 balls.append(ball) turtle.tracer(True)
為什么要設置一個概率值?
適當控制藍色、綠色小球的數量。
turtle.tracer(False)
?方法的作用:是否顯示畫筆繪制過程中的動畫。False
?關閉動畫效果,True
?打開動畫效果。
這里設置為?False
?的原因是不希望用戶看到新畫筆創建過程。
藍色、綠色小球的移動函數:
藍色、綠色小球被創建后會移到一個隨機位置,然后按默認方向移動。
def gb_ball_m(balls): s = 20 a = random.randint(0, 360) r = random.randint(0, 10) for b in balls: b.fd(s) if b.xcor() < -220 or b.xcor() > 240 or b.ycor() > 140 or b.ycor() < -120: b.goto(rand_pos())
當小球碰到墻體后讓其再隨機移到墻體內部(簡單粗粗暴?。。?。
紅色球是否碰到了藍色或綠色小球:
此函數邏輯不復雜,計算小球相互之間的坐標,判斷坐標是否重疊。
''' 紅球是否碰到綠、藍球 ''' def r_g_b_meet(): global red_size # 紅色小球的坐標 s_x, s_y = red_ball.pos() # 迭代綠色小球,藍色小球列表 for bs in [green_balls, blue_balls]: for b in bs: # 計算藍色或綠色小球坐標 f_x, f_y = b.pos() # 計算和紅色球之間的距離 x_ = math.fabs(s_x - f_x) y_ = math.fabs(s_y - f_y) # 碰撞距離:兩個球的半徑之和 h = cell + red_size if 0 <= x_ <= h and y_ >= 0 and y_ <= h: if b in green_balls: # 遇到綠色球紅球變大 red_size += 2 if b in blue_balls: # 遇到藍色球紅球變大 red_size -= 2 # 關鍵代碼 custom_shape('red', red_size) return True return False
上述代碼整體邏輯不復雜。而?custom_shape('red', red_size)
?是關鍵代碼,因紅色小球的半徑發生了變化,所以需要重新定制紅色小球的外觀形狀,這樣才能在畫布上看到半徑變化的紅色小球。
3.4 讓小球動起來
怎樣讓小球動起來?
每隔一定時間,讓小球重新移動。?turtle.ontimer(ball_move, 100)
?是讓小球動起來的核心邏輯,每隔一定時間,重新移動紅、藍、綠外觀如圓形狀的小球。
def ball_move(): red_ball.seth(dir) red_ball.fd(40) # 檢查紅球是否碰到墻體 is_meet_qt() # 隨機創建綠色小球 ran_gb_ball(green_balls, 'green') # 隨機創建藍色小球 ran_gb_ball(blue_balls, 'blue') # 讓綠色小球移動 gb_ball_m(green_balls) # 讓藍色小球移動 gb_ball_m(blue_balls) # 檢查紅球是否碰到藍色、綠色小球 r_g_b_meet() # 定時器 turtle.ontimer(ball_move, 100)
主方法:
if __name__ == "__main__": # 關閉動畫效果 turtle.tracer(False) # 注冊事件 register_event() # 定制 2 種畫筆形狀 for name in ['red', 'ball']: custom_shape(name, cell) # 主畫筆移動墻體的左上角 move_pos(turtle, (-300, 200)) # 繪制墻體 draw_blocks() red_ball = init_ball(rand_pos(), 'red', 'red') turtle.tracer(True) # 讓紅球移動起來 ball_move() # turtle.done()
以上為此游戲程序中的每一個函數講解。
運行后,可以控制紅色小球,當遇到綠色球和藍色球時,紅色球體會變大或變小。
4. 總結
使用?turtle
?模塊的過程說明了一個道理,沒有所謂簡單的知識,如果你認為簡單,那是因為你對它的認知太淺。只是學到了大家都學到的內容。
如果要真正悟透知識點的內核,需要多查閱官方文檔,把所有內容吃透,并試著把這些知識向更高層面拔高。
原文鏈接:https://www.cnblogs.com/guo-ke/p/16079327.html
相關推薦
- 2022-05-24 SQL?Server表空間碎片化回收的實現_MsSql
- 2022-05-24 C++中的Qt?QTableView詳解_C 語言
- 2022-05-05 Python+OpenCV實現角度測量的示例代碼_python
- 2023-02-01 python?multiply()與dot使用示例講解_python
- 2022-11-03 Python?頁面解析Beautiful?Soup庫的使用方法_python
- 2023-07-02 如何遠程使用服務器上的Jupyter?notebook_python
- 2022-04-18 C#實現在窗體上的統計圖效果_C#教程
- 2022-10-22 Python基礎Lists和tuple實例詳解_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支