、函數(shù)與配色實戰(zhàn))
簡介利用Python turtle繪制中國龍形象的完整源代碼項目適合Python初學(xué)者、圖形編程愛好者及對傳統(tǒng)文化題材感興趣的學(xué)習(xí)者。項目中包含4個文件壓縮包約720KB主體為帶詳細注釋的draw_dragon.py源碼另配有效果示意圖png、動態(tài)演示gif及說明文檔md可直觀對照運行結(jié)果與繪圖邏輯。turtle模塊作為Python標(biāo)準庫代碼通過海龜移動控制繪制龍的頭身四肢與尾巴并利用循環(huán)、函數(shù)和參數(shù)調(diào)整實現(xiàn)不同顏色與線條樣式注釋細致到每個函數(shù)與邏輯段便于逐行理解畫法組織方式。已有1158人學(xué)習(xí)/下載適合作為教學(xué)案例或節(jié)日創(chuàng)意編程參考。通過這份資料讀者既能演練圖形繪制與代碼組織技巧也能體會中國龍符號的視覺化表達是一份兼具趣味與講解深度的入門實踐資源。 第一次把這條龍跑出來的時候屏幕上那根金色描邊從左側(cè)滑到右側(cè)紅色塊跟著一裹一條腦袋頂著兩只角的龍就立在深藍色背景上了。用Python畫中國龍聽起來像節(jié)日整活其實特別適合練手turtle是Python自帶的標(biāo)準庫不需要裝第三方依賴源代碼邏輯足夠清晰稍微加點注釋就能當(dāng)教材。這個項目的核心不是“背代碼”而是搞懂坐標(biāo)、填充、循環(huán)和函數(shù)封裝這幾件事。我建議兩類人來抄作業(yè)第一種是剛學(xué)Python不久、想找個有成就感項目的新手第二種是已經(jīng)會基礎(chǔ)語法、想練代碼組織和注釋規(guī)范的開發(fā)者。1. 這個項目到底在畫什么需求拆解與整體思路1.1 為什么是turtle而不是pygame很多人一看到“畫龍”這兩個字第一反應(yīng)是用pygame或者matplotlib。其實都不太合適。pygame能力很強但它是做游戲和交互的畫一張靜態(tài)吉祥物你要處理窗口事件、surface對象、圖像加載這屬于殺雞用牛刀matplotlib擅長數(shù)據(jù)可視化畫出來是圖表思維顏色和線條控制起來也別扭。turtle的定位恰好是“用腳本控制一支筆”你讓它抬筆、落筆、換顏色、畫圓、寫文字它就在畫布上一筆一筆給你畫。它不需要第三方庫Python安裝好就能用這在教學(xué)和分享場景里是極大的優(yōu)勢。另外turtle還有一個隱性好處你能親眼看到繪制過程。龍身先出現(xiàn)然后是龍頭、眼睛、鱗片一層層疊上去這種“從無到有”的過程本身就是視覺反饋。寫代碼最怕沒有反饋turtle把每一行代碼的效果直接擺在屏幕上對初學(xué)者來說這種即時成就感比任何IDE的“語法高亮”都管用。1.2 中國龍的視覺結(jié)構(gòu)拆解一條龍能不能被一眼認出來取決于四個核心細節(jié)。第一是龍身必須有起伏流線不能是一根直棍常見做法是帶波峰的折線或曲線越自然越有神。第二是鱗片龍身上整齊錯開的半圓或小橢圓負責(zé)質(zhì)感和層次感沒有鱗片的龍看起來更像蛇。第三是龍頭眼睛、須、角是記憶點畫好這三樣辨識度立刻上來。第四是背景氛圍深色底、紅日、祥云、文字把畫面從“圖形”變成“吉祥物”。這些細節(jié)不是一次性畫完的而是分層次疊加的。我見過很多初學(xué)者一上來就盯著龍頭的胡須調(diào)坐標(biāo)結(jié)果龍身還沒畫畫面重心已經(jīng)偏了。正確思路是先保證大結(jié)構(gòu)成立再慢慢加小元素最后用背景把整體氣氛撐起來。1.3 繪圖順序從背景到細節(jié)我的固定順序是先鋪背景底色再畫龍身主體然后補頭尾細節(jié)最后加鱗片和裝飾。背景色定了后面所有顏色才能跟著協(xié)調(diào)主體輪廓先落地頭尾的位置才有參考小小的鱗片和大面積的裝飾最后放不容易破壞整體構(gòu)圖。這就跟裝修先刷墻再擺家具一個道理。turtle畫布默認是白色白色背景下紅色龍的視覺效果會弱很多所以我第一件事就是把畫布改成深色。深色背景還有一個好處金色描邊會被襯得很亮整體畫風(fēng)立刻向“國潮海報”靠攏。2. 核心代碼模塊解析初始化、函數(shù)與龍身龍鱗2.1 初始化海龜和兩個核心公共函數(shù)turtle默認狀態(tài)是落筆、初始方向朝右、坐標(biāo)原點在屏幕中心。如果每個部件都從頭寫penup/goto/pendown代碼會又亂又容易漏。我習(xí)慣把最基礎(chǔ)的兩件事封裝成公共函數(shù)import turtle t turtle.Turtle() t.screen.setup(900, 600) # 窗口寬900、高600 t.screen.bgcolor(#1B1B3A) # 深藍背景襯托紅金色 t.speed(8) t.hideturtle() def move(x, y): t.penup() t.goto(x, y) t.pendown() def polygon(points, fill, outline): t.pencolor(outline) t.fillcolor(fill) t.begin_fill() for x, y in points: t.goto(x, y) t.goto(points[0]) t.end_fill()move函數(shù)負責(zé)抬筆移動避免海龜在畫布上拖出一條長線polygon函數(shù)接受一個坐標(biāo)點列表畫一個閉合多邊形并填充顏色。這兩件事是整個項目的基石后面畫龍身、龍頭、龍尾全都要用到。注意turtle內(nèi)部有兩條顏色通道pencolor是線條顏色fillcolor是填充顏色很多人一開始搞混畫出來發(fā)現(xiàn)描邊顏色跟填充完全對不上。2.2 龍身輪廓數(shù)學(xué)曲線和坐標(biāo)點兩條路線龍身是整條龍視覺占比最大的部分畫法有兩條路線。第一條是數(shù)學(xué)曲線路線用for循環(huán)遍歷x坐標(biāo)用正弦函數(shù)算出對應(yīng)的y坐標(biāo)import math # 沿著x坐標(biāo)用正弦函數(shù)算y步長越小曲線越順 for x in range(-300, 301, 6): y 80 * math.sin(x * 0.015) t.goto(x, y)這條路線的好處是曲線連續(xù)平滑改一個振幅參數(shù)就能調(diào)整身體起伏壞處是調(diào)起來不直觀你盯著公式想象半天不如肉眼直接看效果。第二條路線是手工坐標(biāo)點列表直接把幾個關(guān)鍵轉(zhuǎn)折點寫到數(shù)組里例如[(-320, 20), (-230, 75), (-130, 95), ...]然后用polygon函數(shù)連線填充。這條路線的優(yōu)勢是“所見即所得”哪個點高了、低了改數(shù)字就能看到效果適合手工調(diào)造型。我的建議是新手先用坐標(biāo)點列表把大形打出來再看情況用曲線函數(shù)替換其中某一段。純坐標(biāo)列表雖然一開始畫出來歪歪扭扭但它能讓你充分理解“每個點都決定形狀”這件事這個手感比任何理論都重要。2.3 鱗片、龍角和其他裝飾的繪制邏輯鱗片是龍身能不能“立起來”的關(guān)鍵。實現(xiàn)邏輯不復(fù)雜就是循環(huán)畫半圓def scales(points, size7): for x, y in points: t.penup() t.goto(x, y) t.setheading(90) t.pendown() t.pencolor(#F1C40F) t.fillcolor(#F39C12) t.begin_fill() t.circle(size, 180) t.end_fill()size通常控制在6到9之間小于6鱗片遠看像麻點大于9鱗片會把身體輪廓整個蓋住層次就糊了。每一行鱗片要錯開半格像屋頂?shù)耐咂粯诱R中又帶一點節(jié)奏。半圓的凸起方向由setheading控制想換方向就把90改成270試一次這種“改一個數(shù)看一次效果”的調(diào)試方式就是turtle最核心的玩法。龍角和龍須也是同樣思路不需要專門的庫。龍角用兩三條短折線模擬分叉龍須用t.circle(半徑, 角度)截一段弧線視覺上比直線柔和很多。這些全是基礎(chǔ)圖形的組合你只要記住一個原則復(fù)雜造型一定是由若干個簡單圖形疊加出來的。2.4 代碼注釋怎么寫才不算白寫很多初學(xué)者寫turtle代碼從頭到尾只有變量名和數(shù)字過一天自己都看不懂。注釋不是把代碼翻譯成中文而是回答三個問題這段在做什么、為什么這么做、改動哪里會受影響。舉個例子下面這條注釋就比“#畫龍身”有用得多# 身體坐標(biāo)點x從左到右y控制起伏 # 改第3個點之前先看會不會和后面的臉重疊 body [(-320, 20), (-230, 75), (-130, 95), (-40, 65), ...] # size控制在6~9小于6鱗片看不清大于9會蓋住身體輪廓 def scales(points, size7):好的注釋是在給“未來的自己”留線索。尤其是那種“踩過坑才知道”的參數(shù)坑一定要寫在對應(yīng)代碼旁邊否則三個月后你回來看只會問自己“這個7到底是什么意思”。3. 從空畫布到成品完整實操演示3.1 運行前要檢查的3個點在跑代碼之前先確認三件事。第一Python環(huán)境正常命令行輸入python --version能輸出版本號turtle不需要額外安裝但如果你用的是某些精簡版或嵌入式Python環(huán)境可能缺失tkinter模塊提示No module named turtle這種情況建議安裝官方完整版PythonLinux用戶還需要關(guān)注python3-tk這個系統(tǒng)包。第二代碼文件名不要起成turtle.py以前有人把腳本保存成turtle.py結(jié)果import進來的變成自己各種詭異報錯。第三代碼末尾一定要有t.screen.mainloop()否則程序跑完窗口直接關(guān)閉你只能看到屏幕閃一下。3.2 簡化版源碼一次跑通的骨架下面這段代碼可以直接復(fù)制保存成dragon.py運行。它沒有做到像素級精修但足以讓你看清整條龍的繪制順序也方便你在這個基礎(chǔ)上改坐標(biāo)、改顏色。import turtle # ---------- 初始化 ---------- t turtle.Turtle() t.screen.setup(900, 600) t.screen.bgcolor(#1B1B3A) t.speed(8) t.hideturtle() def move(x, y): t.penup() t.goto(x, y) t.pendown() def polygon(points, fill, outline): t.pencolor(outline) t.fillcolor(fill) t.begin_fill() for x, y in points: t.goto(x, y) t.goto(points[0]) t.end_fill() # ---------- 龍身 ---------- body [(-320, 20), (-230, 75), (-130, 95), (-40, 65), (60, 105), (160, 125), (260, 75), (330, 15), (280, -25), (180, -10), (80, 15), (-30, -10), (-140, -35), (-240, -45), (-310, -15)] polygon(body, #C8102E, #F1C40F) # ---------- 龍尾 ---------- tail [(330, 15), (390, -10), (360, -45), (410, -55), (340, -60)] polygon(tail, #C8102E, #F1C40F) # ---------- 龍頭 ---------- face [(-85, 85), (-25, 130), (55, 105), (75, 15), (0, -15), (-70, 25)] polygon(face, #C8102E, #F1C40F) # 眼睛左 move(-20, 75) t.color(white) t.begin_fill() t.circle(12) t.end_fill() move(-12, 75) t.color(black) t.begin_fill() t.circle(5) t.end_fill() # 眼睛右 move(45, 75) t.color(white) t.begin_fill() t.circle(12) t.end_fill() move(53, 75) t.color(black) t.begin_fill() t.circle(5) t.end_fill() # ---------- 龍角 ---------- move(-55, 105) t.setheading(160) t.pencolor(#F1C40F) t.pensize(4) t.forward(35) t.right(30) t.forward(20) t.penup() move(-55, 105) t.setheading(140) t.pendown() t.forward(28) t.penup() move(45, 120) t.setheading(20) t.pendown() t.forward(35) t.left(30) t.forward(20) t.penup() # ---------- 龍鱗 ---------- def scales(points, size7): for x, y in points: t.penup() t.goto(x, y) t.setheading(90) t.pendown() t.pencolor(#F1C40F) t.fillcolor(#F39C12) t.begin_fill() t.circle(size, 180) t.end_fill() scales([(-270, 40), (-190, 62), (-110, 72), (-10, 50), (85, 62), (180, 62)]) scales([(-210, 10), (-120, 30), (-30, 15), (60, 28)]) scales([(-150, -25), (-60, -20), (20, -8)]) # ---------- 紅日和文字 ---------- move(280, 180) t.color(#E74C3C) t.begin_fill() t.circle(50) t.end_fill() move(-80, -160) t.color(white) t.write(龍年大吉, aligncenter, font(楷體, 36, bold)) t.screen.mainloop()跑起來以后你會看到深藍畫布上先出現(xiàn)金邊紅身然后龍頭、眼睛、角依次出現(xiàn)最后鱗片一格一格地鋪上去像在貼瓷磚。這條龍不算精致但骨架結(jié)構(gòu)已經(jīng)完整接下來就是純調(diào)參階段了。3.3 用配色和層次把“骨架龍”變“節(jié)日龍”第一次跑通后別急著分享先改三個地方感受參數(shù)變化。把背景色從#1B1B3A換成#5D1A1A整條龍會立刻變成“國潮紅”畫風(fēng)把scales(points, size7)里的size改成9鱗片瞬間變大視覺沖擊力強很多把文字從“龍年大吉”改成你自己想寫的話就成了定制賀卡。我整理了一份常用配色表直接照著用就行用途顏色值使用場景建議背景#1B1B3A深藍夜空突出紅金色龍身主體#C8102E正紅色節(jié)日主視覺描邊#F1C40F金色線條提亮整體鱗片#F39C12橙金色與描邊區(qū)分紅日#E74C3C圓形裝飾增加年味文字#FFFFFF白色字體不搶主體如果你想加祥云可以用幾個大小不一的半圓拼出來想加燈籠紅色圓加黃色短線就能解決。記住一個原則主色控制在三種以內(nèi)點綴色最多再加兩種顏色一多必亂。4. 高頻問題排查實錄窗口、坐標(biāo)和顏色4.1 畫到一半窗口閃退或卡住初學(xué)者最常遇到的坑是代碼明明沒有報錯圖形一閃就沒了。原因多半是程序跑完P(guān)ython進程退出畫布跟著關(guān)了。解法是在代碼最后加t.mainloop()或者t.screen.exitonclick()前者保持窗口打開后者點擊窗口時退出。還有一種情況是窗口一直卡著不動通常是因為代碼里死循環(huán)了比如for循環(huán)步長寫成0或者坐標(biāo)列表里有重復(fù)點導(dǎo)致海龜在兩點之間反復(fù)橫跳。遇到卡頓直接關(guān)掉窗口看控制臺報錯Python會把錯誤位置和原因打在屏幕上照著提示找那一行就行。4.2 線斷了、坐標(biāo)對不上、疊圈位置不對圖形歪七扭八、部件之間對不上幾乎都是坐標(biāo)問題。turtle的坐標(biāo)原點默認在窗口中心x向右為正、y向上為正。寫坐標(biāo)前先在腦子里把畫布分成大致的網(wǎng)格龍頭在哪個區(qū)間龍身從哪個點繞回來龍尾朝哪個方向翹。所有部件都用move()抬筆移動不用move的話海龜會從上一個位置直接畫線過來出現(xiàn)莫名其妙的“拉絲”現(xiàn)象。坐標(biāo)問題有個很有效的排查方法把對應(yīng)部件的points列表打印出來或者臨時把填充顏色設(shè)成半透明看每個多邊形實際落在什么位置再逐一修正。4.3 顏色臟、層次亂根本原因是這三點龍為什么看著廉價多數(shù)是顏色太多、明度相近的紅橙混在一起缺少對比。我的習(xí)慣是整幅畫只保留三種主色深色背景、一種主體色、一種描邊色點綴色最多再加兩種。紅配金配深藍就是經(jīng)典搭配比十幾種顏色“炫彩”效果干凈得多。第二個原因是描邊顏色和填充顏色太接近龍身紅配紅邊輪廓就糊了一定要讓描邊明顯比填充亮或比填充暗。第三個原因是元素堆疊亂鱗片、祥云、文字互相遮擋。處理辦法是畫完一層再畫下一層大面積的元素永遠先畫小元素后畫保證后畫的不會被大面積色塊蓋住。5. 這套代碼還能怎么玩擴展方向與個人經(jīng)驗5.1 讓龍動起來turtle雖然不擅長復(fù)雜游戲但做簡單動畫完全夠用。你可以把龍身坐標(biāo)整體存成一個列表綁定鍵盤事件按方向鍵修改一個基準偏移量然后調(diào)用t.clear()清除畫布用新坐標(biāo)重新繪制。核心思路是不要在事件回調(diào)里寫一長串繪制邏輯而是先更新數(shù)據(jù)再統(tǒng)一重繪。這個“數(shù)據(jù)與繪制分離”的思想等你以后寫pygame或者其他圖形程序時會反復(fù)用到。5.2 拿來當(dāng)節(jié)日賀卡或教學(xué)案例把write函數(shù)里的文字改一改背景換成淺色系再畫兩個燈籠就是一張可分享的節(jié)日賀卡。教學(xué)場景更好玩把這份源碼的注釋刪掉把坐標(biāo)點順序打亂讓學(xué)生自己恢復(fù)圖形原貌。這個任務(wù)同時練到了坐標(biāo)理解、列表操作、函數(shù)封裝和代碼注釋四件事比單獨做選擇題有意思得多。每次分享這套代碼我都會讓人先跑起來。跑通之后改三個參數(shù)感受一下背景色換中國紅鱗片size調(diào)到9龍身整體上移40像素。光是這三個改動畫風(fēng)就會完全不同。畫一條龍從來不是目的真正有用的是你開始調(diào)第一個參數(shù)時養(yǎng)成的“拆解問題、定位參數(shù)、驗證效果”的習(xí)慣。這個習(xí)慣才是這條龍送你的禮物。本文還有配套的精品資源點擊獲取