ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Python turtle库画皮卡丘:从坐标拆解到完整项目实战

Python turtle库画皮卡丘:从坐标拆解到完整项目实战 我敢说每个学 Python 的人画图第一站基本是turtle 库而用 turtle 库画一个皮卡丘几乎是新手阶段最有成就感的入门项目之一。它跟写爬虫、做数据分析不一样不需要安装第三方库不涉及网络请求唯一的难点是怎么把一个黄色电老鼠拆成一组圆、椭圆、三角形和折线然后用坐标摆到正确的位置。这篇文章把我自己画皮卡丘的完整过程写出来包括坐标规划思路、图层顺序、每一段代码在干什么、实测中踩过的坑以及最后怎么把代码改造成“可复用的函数”。适合刚学完 Python 基础语法、想在 turtle 上找个综合项目练手的人也适合老师拿来当课堂案例。不需要你有美术基础只要会读坐标就能把这个项目抄下来跑通。先提醒一句这篇不是给你一个代码直接复制就完事的教程那样下次换个角色还是不会画。真正值钱的是“怎么把一张图拆成几何形状再翻译成 turtle 指令”这套思路。1. 先把环境摆平标准库、tkinter 与画布初始化的那点事很多人兴冲冲地写了个import turtle结果一运行直接报红或者窗口一闪而过于是开始怀疑人生。其实 turtle 本身是 Python 标准库正常情况下不需要pip install真正容易出问题的是它依赖的图形后端。1.1 很多人的第一个坑turtle 不见了turtle 库底层依赖的是 tkinter而 tkinter 在某些精简版 Python 或者 Linux 系统默认安装里并不存在。最常见的报错是ModuleNotFoundError: No module named tkinter看到这行字问题不在 turtle而在系统里缺少 tcl/tk 支持。Windows 用户一般不会遇到这个问题前提是你安装 Python 时用的是官网安装包并且没有手动去掉 tcl/tk 组件macOS 官方安装包也自带了 tkinter。最容易中招的是 Linux 用户比如你用apt install python3之后直接跑大概率会缺 tkinter需要额外装一个系统包sudo apt install python3-tk如果你用的是 conda 环境对应的操作是conda install tk还有一个隐蔽的坑有些在线 Python 编辑器或者网页版环境不支持弹窗运行 turtle 代码要么白屏要么直接报 “cannot connect to display” 之类的错误。这种环境下别死磕 turtle换个支持图形窗口的本地方案或者用专门支持 turtle 的在线模拟器。1.2 画布上的“自动驾驶”坐标系、角度和 circle 的转向环境跑通之后真正需要花时间理解的是 turtle 的坐标和方向模型。turtle 默认的窗口是一个平面直角坐标系原点在窗口正中央x 轴向右为正y 轴向上为正。海龟出场时位于原点头朝右也就是朝向 0 度。新手最容易绕晕的是circle()方法的参数方向。我的理解方法是把 turtle 想象成一辆车circle(r, extent)中的圆心在这辆车前进方向的左侧距离为 r 的位置extent为正表示沿着正常转向画弧为负则反向。比如t.circle(50, 90)意思是让海龟以左侧 50 像素为圆心画 90 度的弧。如果你想让弧线向下弯就把半径取负或者换一个初始朝向。很多人在画嘴巴、画耳朵时觉得 turtle 不听话其实就是没搞清楚“圆心在左侧”这个底层逻辑。另外left()和right()是原地转向setheading()是直接指定绝对朝向。画图项目中setheading(0)表示让海龟重新朝右setheading(90)朝上。每次画之前明确设置方向可以省掉大量“海龟现在到底朝哪边”的脑力消耗。1.3 建议的画布初始化配置我画这类完整角色时习惯在开头固定一套初始化配置避免画到一半发现窗口太小或颜色模式不对。import turtle t turtle.Turtle() t.speed(0) # 0 是最高速度省去等待 t.pensize(3) # 描边粗细皮卡丘要有卡通轮廓线 turtle.colormode(255) # 允许用 RGB 元组设置颜色 turtle.setup(900, 800) # 窗口大小防止图形被边缘截断 turtle.title(turtle 皮卡丘) turtle.bgcolor(white)speed(0)意思是“不表演动画直接快速画完”如果想让别人看绘制过程可以改成speed(5)或者更低。setup(900, 800)把窗口放大画到接近边缘的耳朵和尾巴时不会被裁掉。colormode(255)开了之后可以用(255, 213, 57)这样的 RGB 元组精确控制颜色比内置的yellow更接近皮卡丘的官方配色。2. 画之前先拆图皮卡丘坐标草图和图层顺序很多新手拿到 turtle 就恨不得马上开始左转右转结果画到一半发现形状对不上改坐标改到崩溃。我的习惯是先把目标图拆成几何图形在纸上或者脑内标出“先画什么、后画什么、每个形状的中心/起点在哪”再动笔写代码。2.1 为什么顺序是脚→身体→尾巴→手→耳朵→头皮卡丘整体上是几个大色块的叠加黄色的身体、黄色的头、黄色的耳朵、黑色的耳朵尖、红色的脸颊。turtle 没有橡皮擦也没有图层面板想要做出“叠加”效果唯一的方法就是控制绘制顺序先画会被遮住的部分再画盖在上面的部分。我定的顺序是脚先画因为身体下半部分会压住脚的上边缘。身体画一个大椭圆盖住脚的一部分。尾巴画在身体右侧贴住身体边缘。手画在身体左右两侧。耳朵画在头的后面头部画完自然盖住耳朵根部。头盖在耳朵根部之上形成“耳朵从头后面长出来”的效果。五官眼睛、高光、红脸颊、鼻子、嘴巴最后画在最上层。这个顺序不是唯一的但有一条经验凡是根部要被遮挡的形状一律先画。如果你先画了一个完整的头再往上堆耳朵交界处就会出现两条交叉的黑线要花很多功夫去补还不如一开始就把顺序排对。2.2 我的坐标规划表我把皮卡丘拆成下面这些基本部件计算好大致尺寸和位置。注意这里的坐标不是一比一还原动画原画而是让整个形象在窗口里比例协调、看起来一眼能认出是皮卡丘。部位形状关键坐标 / 尺寸绘制时机脚圆半径 24圆心约 (±55, -186)第 1 层身体椭圆约 156×200椭圆起点 (0, -210)第 2 层尾巴锯齿折线闪电起点 (75, -145)向右上延伸第 3 层手圆半径 22圆心约 (±102, -68)第 4 层耳朵三角形 黑色尖角左耳三顶点 (-55,150)、(-110,280)、(-35,230)第 5 层头部椭圆约 236×210椭圆起点 (0, -45)第 6 层眼睛椭圆约 36×56起点约 (±42, 60)第 7 层高光白点直径 10(±48, 95)第 8 层红脸颊椭圆约 32×24起点约 (±62, 22)第 9 层鼻子小圆点(0, 52)第 10 层嘴巴黑色折线从 (±24, 28) 向中间折第 11 层这张表不用背画的时候打开一个坐标系网格心态就行。重点是先确定头部中心再围绕头部定五官最后补身体和四肢。我的头部中心放在 (0, 60)因为皮卡丘耳朵向上伸出整体画面会显得偏高头部中心略微上移能让整只皮卡丘在窗口里更居中。2.3 配色把官方的黄和腮红换成 RGBturtle 默认颜色名有限皮卡丘那种黄色如果用yellow画出来会非常刺眼。我习惯用 RGB 元组三个关键颜色如下用途颜色RGB 值身体、头、耳朵的主色皮卡丘黄(255, 213, 57)腮红粉红(223, 76, 76)轮廓线和五官深黑(20, 20, 20)设置颜色时要注意 turtle 的语法t.color(BLACK, YELLOW)表示黑色描边、黄色填充。如果只传一个参数比如t.color(BLACK)那描边和填充都是黑色。画不同色块时反复切换填充色是最容易漏掉的操作。3. 核心绘制代码逐段拆解下面开始上代码。我没有把代码写成“一个大方法从头画到尾”而是按部件拆开方便你理解每一段在做什么也方便以后改成其他角色。3.1 两个基础函数move 和 ellipse我几乎每个 turtle 项目都会定义这两个小工具def move(x, y): t.penup() t.goto(x, y) t.pendown() def ellipse(rx, ry): t.setheading(0) for _ in range(2): t.circle(rx, 90) t.circle(ry, 90)move()很好理解抬笔、移动、落笔避免在移动过程中留下杂线。ellipse()需要单独解释。turtle 没有直接画椭圆的 API这个函数是用两个半径值交替画四分之一圆弧拼出一个接近椭圆的封闭图形。rx控制横向“胖瘦”ry控制纵向“高矮”。我用它画身体、头部、眼睛和脸颊。画之前强制setheading(0)保证每次画出来的都是“横着的椭圆”不会因为海龟之前朝向乱七八糟而歪掉。3.2 脚、身体和手圆和椭圆的基本用法先画脚和身体# 脚 t.color(BLACK, YELLOW) for x in (-55, 55): move(x, -186) t.begin_fill() t.circle(24) t.end_fill() # 身体 move(0, -210) t.begin_fill() ellipse(78, 100) t.end_fill()画脚用的是circle(24)因为脚就是一个圆。begin_fill()和end_fill()之间画出的封闭图形会被填充成当前填充色。注意circle(24)画完后会回到起点所以不会出现“圆合不拢”的问题。身体用ellipse(78, 100)相当于横向约 156 像素、纵向约 200 像素的椭圆。我让椭圆起点落在 (0, -210)也就是身体底部这样从底部开始向上长身体上半部分会自然被后续的头部覆盖一小段形成“脑袋压着身子”的层次感。接下来画手# 手 for x in (-102, 102): move(x, -68) t.begin_fill() t.circle(22) t.end_fill()手的中心放在 (±102, -68)正好贴在身体中上方的两侧。皮卡丘的手比较短用半径 22 的圆就够了。如果想让手更偏向“椭球形”可以把这行的circle换成ellipse(18, 24)但正圆简单不出错。3.3 尾巴用折线填充闪电皮卡丘的尾巴是标志性的闪电形状。turtle 画这种不规则形状最快的方式是直接给出折线顶点让填充自动闭合# 尾巴 move(75, -145) t.begin_fill() t.goto(155, -105) t.goto(105, -45) t.goto(165, -25) t.goto(95, 55) t.goto(65, -15) t.goto(80, -55) t.goto(60, -100) t.end_fill()这段代码从身体右侧出发向右上、再向左上、再向右上形成锯齿状的闪电轮廓最后自动折回起点。坐标看起来多其实思路很简单交替往右、往左折逐步抬高最后回到身体附近闭合。闪电尖端的最高点大概在 (95, 55)比肩膀高出一截。尾巴主体都在身体右侧外部不会被身体挡住太多视觉上很清晰。3.4 耳朵三角路径加黑色耳尖耳朵是皮卡丘除了尾巴之外最标致的特征。我先画左耳# 左耳黄色轮廓 黑色耳尖 move(-55, 150) t.begin_fill() t.goto(-110, 280) t.goto(-35, 230) t.end_fill() move(-110, 280) t.color(BLACK, BLACK) t.begin_fill() t.goto(-118, 255) t.goto(-82, 255) t.end_fill()这里用了一个非常朴素的三角形起点在头部内部偏上位置 (-55, 150)拉向左上方的耳尖 (-110, 280)再回到 (-35, 230)填充黄色。头部画完之后起点附近会被头盖住露出来的就是从左上方到右下方的一个尖耳轮廓。黑色耳尖更好理解坐标移到耳尖 (-110, 280)画一个倒三角形两个底角在 y255形成一小块黑色覆盖在黄色耳朵尖上。右耳完全镜像# 右耳黄色轮廓 黑色耳尖 t.color(BLACK, YELLOW) move(55, 150) t.begin_fill() t.goto(110, 280) t.goto(35, 230) t.end_fill() move(110, 280) t.color(BLACK, BLACK) t.begin_fill() t.goto(118, 255) t.goto(82, 255) t.end_fill()注意左右耳共用了 y 轴坐标只把 x 方向做了正负镜像。这个做法在你以后画其他对称角色时也适用同一个形状只写一次用循环变量或者正负号切换左右。3.5 头部和五官覆盖顺序、眼睛高光、腮红与嘴型头部的椭圆起点放在 (0, -45)这样头的下缘会盖住身体顶部t.color(BLACK, YELLOW) move(0, -45) t.begin_fill() ellipse(118, 105) t.end_fill()ellipse(118, 105)是一个横向略宽的大椭圆中心大约在 (0, 60)和我的设计一致。这个宽度足够把耳朵根部遮住看起来耳朵是从头后面伸出来的。五官部分眼睛用黑色竖椭圆t.color(BLACK, BLACK) for x in (-42, 42): move(x, 60) t.begin_fill() ellipse(18, 28) t.end_fill()椭圆起点在 (±42, 60)整个眼睛中心大概在 (±42, 88)。眼睛稍微偏上符合皮卡丘的可爱比例。眼睛里的高光不能少否则会变成两颗纯黑大圆点非常呆滞for x in (-48, 48): move(x, 95) t.dot(10, WHITE)dot()是 turtle 里画实心点的方法比用circle填充简单而且不受线条粗细影响。两个小白点落在眼睛左上方皮卡丘的眼神一下就活了。红脸颊t.color(BLACK, RED) for x in (-62, 62): move(x, 22) t.begin_fill() ellipse(16, 12) t.end_fill()脸颊中心大概在 (±62, 34)比眼睛低很多正好在脸的侧下方。用ellipse(16, 12)画扁椭圆更接近腮红贴在脸上的感觉。鼻子和嘴巴# 鼻子 move(0, 52) t.dot(7, BLACK) # 嘴巴 t.penup() t.goto(-24, 28) t.pendown() t.pencolor(BLACK) t.goto(-10, 18) t.goto(0, 28) t.goto(10, 18) t.goto(24, 28)鼻子用一个小黑点搞定。嘴巴我用一条折线画成“w”形中间高、两边低嘴角微微上翘。如果你想要更复杂的嘴巴可以用两条弧线去拼但对新手来说折线是最不容易翻车、也最容易后续微调坐标的方案。3.6 完整可运行代码我把上面所有段落的代码整合成一个文件直接复制保存为.py文件运行即可import turtle t turtle.Turtle() t.speed(0) t.pensize(3) turtle.colormode(255) turtle.setup(900, 800) turtle.title(turtle 皮卡丘) turtle.bgcolor(white) YELLOW (255, 213, 57) RED (223, 76, 76) BLACK (20, 20, 20) WHITE (255, 255, 255) def move(x, y): t.penup() t.goto(x, y) t.pendown() def ellipse(rx, ry): t.setheading(0) for _ in range(2): t.circle(rx, 90) t.circle(ry, 90) # 脚 t.color(BLACK, YELLOW) for x in (-55, 55): move(x, -186) t.begin_fill() t.circle(24) t.end_fill() # 身体 move(0, -210) t.begin_fill() ellipse(78, 100) t.end_fill() # 尾巴 move(75, -145) t.begin_fill() t.goto(155, -105) t.goto(105, -45) t.goto(165, -25) t.goto(95, 55) t.goto(65, -15) t.goto(80, -55) t.goto(60, -100) t.end_fill() # 手 for x in (-102, 102): move(x, -68) t.begin_fill() t.circle(22) t.end_fill() # 左耳黄色轮廓 黑色耳尖 move(-55, 150) t.begin_fill() t.goto(-110, 280) t.goto(-35, 230) t.end_fill() move(-110, 280) t.color(BLACK, BLACK) t.begin_fill() t.goto(-118, 255) t.goto(-82, 255) t.end_fill() # 右耳黄色轮廓 黑色耳尖 t.color(BLACK, YELLOW) move(55, 150) t.begin_fill() t.goto(110, 280) t.goto(35, 230) t.end_fill() move(110, 280) t.color(BLACK, BLACK) t.begin_fill() t.goto(118, 255) t.goto(82, 255) t.end_fill() # 头部 t.color(BLACK, YELLOW) move(0, -45) t.begin_fill() ellipse(118, 105) t.end_fill() # 眼睛 t.color(BLACK, BLACK) for x in (-42, 42): move(x, 60) t.begin_fill() ellipse(18, 28) t.end_fill() # 眼睛高光 for x in (-48, 48): move(x, 95) t.dot(10, WHITE) # 红脸颊 t.color(BLACK, RED) for x in (-62, 62): move(x, 22) t.begin_fill() ellipse(16, 12) t.end_fill() # 鼻子 move(0, 52) t.dot(7, BLACK) # 嘴巴 t.penup() t.goto(-24, 28) t.pendown() t.pencolor(BLACK) t.goto(-10, 18) t.goto(0, 28) t.goto(10, 18) t.goto(24, 28) t.hideturtle() turtle.done()运行之后窗口会保持打开看到一只黄澄澄的皮卡丘站在画面中央。4. 实测最容易翻车的四个地方排查思路与解决记录代码能跑通是好事但我敢说十个跑这个项目的人里至少有三四个第一次运行会遇到下面某个问题。我把这些坑单独列出来因为每个我都踩过直接给排查思路。4.1 ModuleNotFoundError: No module named tkinter这个前面已经提过再补充一点排查顺序确认你运行代码的 Python 环境是系统 Python 还是 conda 虚拟环境。在终端执行python -c import tkinter看是否报错。如果报错Windows 用户重新安装官方 Python安装时保证 tcl/tk 组件被勾选Linux 用户执行sudo apt install python3-tkconda 用户执行conda install tk。如果 import 正常但仍然画不出窗口检查你是否在无图形界面的环境里运行比如纯命令行的远程服务器。这个问题的本质是 turtle 的画布基于 tkinter没有 tkinter 就没有画布代码会直接死在导入阶段。4.2 窗口一闪而过或画面纹丝不动我在脚本里最后写了turtle.done()它的作用是进入主循环让窗口保持打开。很多人双击运行代码时发现窗口瞬间关闭原因就是脚本末尾没有这一行程序执行完直接退出画布也一起销毁了。如果你用的是turtle.exitonclick()效果是“点击窗口后关闭”更像交互式演示。我个人更推荐turtle.done()因为不需要额外操作窗口会保持到你手动关闭。还有一种情况窗口一直黑屏或者没反应。先把t.speed(0)改成t.speed(3)看看是不是海龟在慢慢画但你没察觉。如果是画得快导致看不到过程是正常的如果是卡住检查代码里是不是用了死循环比如while True或者无限递归。4.3 图形错位和填充“漏缝”怎么快速定位错位是最常见的问题。想要快速定位我提供一个笨但极有效的办法把t.speed(0)改成t.speed(1)让海龟慢慢爬。你会清楚地看到每一条线是往哪个方向走的哪里多走了一段哪里少走了一段。如果出现填充区域出现一条细细的空白缝多半是begin_fill()到end_fill()之间的路径没有闭合。turtle 的填充规则是填充时会把路径的终点和起点自动连接看起来是闭合的但如果路径里包含了一个反向的弧线连接点就会出现瑕疵。另一个原因是circle()画弧过程中海龟方向变了导致后面接的线段方向不对。遇到这种情况我的排查思路是先单独注释掉其余部分只画有问题的那个形状一两个坐标地调整。4.4 边缘截断、运行太慢与在线编辑器限制皮卡丘的耳朵尖最高到 y280如果窗口默认只有 500×500这个高度已经逼近窗口顶部视觉上会被截一部分。我在初始化里用turtle.setup(900, 800)放大窗口就是提前规避这个问题。如果觉得画得太慢除了t.speed(0)还可以在代码开头加一个turtle.tracer(0)这个命令会关闭逐帧动画。全部画完后手动调用turtle.update()让画面一次性刷新。比如我的完整代码里把t.hideturtle()改成turtle.update()也能达到瞬间完成的效果。但要注意开了tracer(0)之后绘制过程是完全不可见的适合追求最终成品时使用想看过程就别开。在线编辑器的问题前面提过很多网站运行 turtle 代码不会弹出图形窗口。如果你需要在线演示找支持 turtle 的专用模拟器自己练习还是建议直接装个本地 Python 环境。5. 让这个项目从“画出来”变成“改得动”参数化扩展画完一个静态皮卡丘只是第一步。真正有用的能力是让这个皮卡丘能放大缩小、能换表情、能改配色。5.1 用 scale 参数整体放大缩小我最常做的改造是把所有坐标和半径统一乘上一个scale系数。举个耳朵部分的例子def draw_ear(direction, scale1.0): move(-55 * direction * scale, 150 * scale) t.begin_fill() t.goto(-110 * direction * scale, 280 * scale) t.goto(-35 * direction * scale, 230 * scale) t.end_fill() move(-110 * direction * scale, 280 * scale) t.color(BLACK, BLACK) t.begin_fill() t.goto(-118 * direction * scale, 255 * scale) t.goto(-82 * direction * scale, 255 * scale) t.end_fill()调用时draw_ear(1, 0.8)表示左耳、缩小到 0.8 倍draw_ear(-1, 0.8)表示右耳。这样改造以后你只需要改一个参数就能把整套皮卡丘缩小成头像或者放大成海报。画笔粗细也可以跟着缩放t.pensize(3 * scale)这样缩小后描边不会显得过粗。5.2 换表情、换配色的小改造五官是最容易定制的部分。比如想让皮卡丘显得生气可以把嘴巴折线改成一条下弯的弧线或者把嘴的端点往下拉t.penup() t.goto(-18, 20) t.pendown() t.goto(0, 12) t.goto(18, 20)这是把原来的“w”形嘴角压低表情立刻变得不高兴。想让皮卡丘更呆萌可以把眼睛的高光点调大或者把红脸颊的椭圆画大一圈。配色方面turtle 支持的颜色字符串很多如果你不想用 RGB 元组也可以试试t.color(gold, khaki)但效果不如精准的 RGB 接近原版。你想做一个异色版本的皮卡丘直接改YELLOW这一个变量就可以比如换成白色就是“阿罗拉形态”换成棕色就是“巧克力皮卡丘”。5.3 接下来可以继续玩的 turtle 方向画完皮卡丘之后turtle 还有几个非常值得玩的进阶方向递归分形用递归画树、雪花、谢尔宾斯基三角形锻炼函数思维。多个海龟协同创建多个 Turtle 对象模拟赛跑或者画队形。键盘交互绑定键盘事件做一个用方向键控制海龟移动的小游戏。逐帧动画配合ontimer()定时器做简单的动画效果。如果继续画角色建议从“对称角色”入手比如哆啦A梦的蓝脸、小熊的圆耳朵这些都可以复用今天讲的椭圆函数和“先画底层再画顶层”的思路。画多了你会发现turtle 项目的难点从来不是 Python 语法而是能不能把心里那个画面翻译成一个又一个具体的坐标和半径。我自己的体会是一开始别追求画得一模一样先把比例画准再慢慢调细节。第一次跑完看到一只比例不协调但一眼能认出的皮卡丘时那种成就感是刷一百道练习题都给不了的。如果你也画出来了试着把那几个坐标改着玩很快就能摸到 turtle 这门“几何编程语言”的脾气。
返回列表