返回博客

46. 海龟绘图 turtle:用代码画画

46. 海龟绘图 turtle:用代码画画

前言

turtle(海龟绘图) 是 Python 内置的图形库,它模拟一只海龟在画布上爬行,通过移动留下轨迹来绘制图案。虽然是教学工具,但 turtle 能创作出令人惊叹的艺术作品!本文从基础操作到复杂图形,系统讲解 turtle 绘图技巧。

入门基础

第一个海龟程序

import turtle

# 创建窗口和画笔
screen = turtle.Screen()
screen.title("我的第一个海龟程序")
screen.bgcolor("white")

pen = turtle.Turtle()
pen.shape("turtle")   # 让画笔变成海龟形状
pen.color("blue")
pen.pensize(3)

# 画一个正方形
for _ in range(4):
    pen.forward(100)   # 前进 100 像素
    pen.right(90)      # 右转 90 度

pen.hideturtle()       # 隐藏海龟
screen.mainloop()      # 保持窗口打开

基本命令速查

命令 说明
forward(n) / fd(n) 向前移动 n 像素
backward(n) / bk(n) 向后移动 n 像素
right(angle) / rt(angle) 向右旋转 angle 度
left(angle) / lt(angle) 向左旋转 angle 度
goto(x, y) / setpos(x, y) 移动到指定坐标
circle(radius, extent) 画圆弧(extent 为角度)
dot(size, color) 画点
pensize(width) 设置画笔粗细
pencolor(color) 设置画笔颜色
fillcolor(color) 设置填充颜色
begin_fill() / end_fill() 开始/结束填充
undo() 撤销上一步
reset() 重置海龟状态

基础图形绘制

画螺旋线

import turtle

def draw_spiral():
    screen = turtle.Screen()
    screen.title("螺旋线")
    screen.bgcolor("black")
    
    pen = turtle.Turtle()
    pen.speed(0)        # 最快速度
    pen.pensize(2)
    
    colors = ["red", "yellow", "green", "cyan", "magenta", "orange"]
    length = 5
    
    for i in range(200):
        pen.pencolor(colors[i % len(colors)])
        pen.forward(length)
        pen.left(91)  # 稍大于 90° 产生螺旋效果
        length += 2
    
    pen.hideturtle()
    screen.mainloop()

draw_spiral()

对称几何图案

import turtle

def draw_symmetric_pattern(sides=6, turns=24):
    """绘制对称几何图案"""
    screen = turtle.Screen()
    screen.title("对称几何图案")
    screen.bgcolor("#1a1a2e")
    
    pen = turtle.Turtle()
    pen.speed(0)
    pen.pensize(2)
    
    colors = ["#e94560", "#f5c518", "#0f3460", "#16c79a", "#ff6b6b"]
    
    for t in range(turns):
        pen.pencolor(colors[t % len(colors)])
        for _ in range(sides):
            pen.forward(80)
            pen.left(360 // sides)
        pen.right(360 // turns)
    
    pen.hideturtle()
    screen.mainloop()

draw_symmetric_pattern(sides=8, turns=36)

多色渐变圆形

import turtle
import math

def draw_gradient_circles(count=36, radius=50):
    """绘制渐变色圆形组合"""
    screen = turtle.Screen()
    screen.title("渐变圆形")
    screen.bgcolor("#0d1b2a")
    screen.setup(600, 600)
    
    pen = turtle.Turtle()
    pen.speed(0)
    pen.ht()
    
    for i in range(count):
        hue = i * 360 / count
        r = int(128 + 127 * math.cos(math.radians(hue)))
        g = int(128 + 127 * math.cos(math.radians(hue - 120)))
        b = int(128 + 127 * math.cos(math.radians(hue - 240)))
        color = f"#{r:02x}{g:02x}{b:02x}"
        
        pen.pencolor(color)
        pen.fillcolor(color)
        pen.begin_fill()
        pen.circle(radius)
        pen.end_fill()
        pen.rt(360 / count)
    
    screen.mainloop()

draw_gradient_circles(36, 60)

分形图形

科赫雪花(Koch Snowflake)

import turtle

def koch_curve(t, order, size):
    """递归绘制科赫曲线"""
    if order == 0:
        t.forward(size)
        return
    
    segment_size = size / 3
    
    # 第一部分
    koch_curve(t, order - 1, segment_size)
    t.left(60)
    
    # 凸起部分
    koch_curve(t, order - 1, segment_size)
    t.right(120)
    
    # 中间部分
    koch_curve(t, order - 1, segment_size)
    t.left(60)
    
    # 第三部分
    koch_curve(t, order - 1, segment_size)

def draw_koch_snowflake(order=3, size=200):
    """绘制科赫雪花"""
    screen = turtle.Screen()
    screen.title(f"科赫雪花 (阶数={order})")
    screen.bgcolor("white")
    
    pen = turtle.Turtle()
    pen.speed(0)
    pen.pensize(2)
    pen.pencolor("#2c3e50")
    pen.penup()
    pen.goto(-size/2, -size/(2 * 1.732))
    pen.pendown()
    
    for _ in range(3):
        koch_curve(pen, order, size)
        pen.right(120)
    
    pen.hideturtle()
    screen.mainloop()

draw_koch_snowflake(order=3, size=240)

谢尔宾斯基三角形

import turtle

def draw_triangle(t, size, depth):
    """递归绘制谢尔宾斯基三角形"""
    if depth == 0:
        t.fillcolor("#e74c3c")
        t.begin_fill()
        for _ in range(3):
            t.forward(size)
            t.left(120)
        t.end_fill()
        return
    
    new_size = size / 2
    
    # 顶部子三角形
    draw_triangle(t, new_size, depth - 1)
    t.penup()
    t.forward(new_size)
    t.pendown()
    
    # 左下子三角形
    t.left(120)
    t.forward(new_size)
    t.right(120)
    draw_triangle(t, new_size, depth - 1)
    
    # 右上子三角形
    t.left(120)
    t.forward(new_size)
    t.right(60)
    t.forward(new_size)
    t.left(60)
    draw_triangle(t, new_size, depth - 1)
    
    # 回到原点
    t.penup()
    t.backward(new_size)
    t.left(60)
    t.backward(new_size)
    t.right(60)
    t.pendown()

def draw_sierpinski(depth=4):
    """绘制谢尔宾斯基三角形"""
    screen = turtle.Screen()
    screen.title(f"谢尔宾斯基三角形 (深度={depth})")
    screen.bgcolor("white")
    
    pen = turtle.Turtle()
    pen.speed(0)
    pen.pensize(1)
    pen.penup()
    pen.goto(0, -150)
    pen.pendown()
    
    draw_triangle(pen, 300, depth)
    
    pen.hideturtle()
    screen.mainloop()

draw_sierpinski(depth=4)

分形树

import turtle
import random

def draw_fractal_tree(branch_length, angle, reduction, depth, pen):
    """递归绘制分形树"""
    if depth <= 0 or branch_length < 5:
        return
    
    length_variation = random.uniform(0.85, 1.15)
    actual_length = branch_length * length_variation
    
    pen.pensize(max(1, depth // 2))
    pen.forward(actual_length)
    
    # 左分支
    left_angle = angle + random.uniform(-5, 5)
    pen.left(left_angle)
    draw_fractal_tree(actual_length * reduction, angle, reduction, depth - 1, pen)
    
    # 右分支
    right_angle = angle + random.uniform(-5, 5)
    pen.right(right_angle)
    draw_fractal_tree(actual_length * reduction, angle, reduction, depth - 1, pen)
    
    # 回到原位
    pen.left(left_angle)
    pen.backward(actual_length)

def draw_tree(depth=9, angle=25):
    """绘制分形树"""
    screen = turtle.Screen()
    screen.title("分形树")
    screen.bgcolor("lightblue")
    
    pen = turtle.Turtle()
    pen.speed(0)
    pen.pencolor("#5d4037")
    pen.penup()
    pen.goto(0, -200)
    pen.setheading(90)
    pen.pendown()
    
    draw_fractal_tree(120, angle, 0.7, depth, pen)
    
    pen.hideturtle()
    screen.mainloop()

draw_tree(depth=10, angle=25)

交互与动画

键盘控制海龟

import turtle

class InteractiveTurtle:
    """交互式海龟绘图"""
    
    def __init__(self):
        self.screen = turtle.Screen()
        self.screen.title("交互式海龟")
        self.screen.setup(800, 600)
        self.screen.tracer(False)
        
        self.pen = turtle.Turtle()
        self.pen.shape("turtle")
        self.pen.shapesize(2, 2)
        self.pen.speed(0)
        
        self.colors = ["red", "yellow", "green", "cyan",
                       "magenta", "orange", "purple", "brown"]
        self.color_index = 0
        
        self._setup_keys()
        self._main_loop()
    
    def _setup_keys(self):
        key_map = {
            "Up": lambda: self.pen.forward(20),
            "Down": lambda: self.pen.backward(20),
            "Left": lambda: self.pen.left(15),
            "Right": lambda: self.pen.right(15),
            "space": lambda: self.pen.undo(),
            "c": lambda: self.screen.reset(),
            "r": lambda: setattr(self.pen, "pencolor", self.colors[self.__class__.__dict__]),
        }
        
        for key, callback in key_map.items():
            self.screen.onkey(callback, key)
        
        self.screen.listen()
    
    def _main_loop(self):
        while True:
            self.screen.update()

InteractiveTurtle()

鼠标追踪画图

import turtle

def draw_on_click():
    screen = turtle.Screen()
    screen.title("点击画图")
    screen.bgcolor("white")
    
    pen = turtle.Turtle()
    pen.speed(0)
    pen.shapesize(3)
    
    colors = ["red", "blue", "green", "yellow", "purple", "orange"]
    color_idx = [0]
    
    def on_click(x, y):
        color_idx[0] = (color_idx[0] + 1) % len(colors)
        pen.color(colors[color_idx[0]])
        pen.dot(40)
        pen.write(f"✕ ({x}, {y})", font=("Arial", 10))
    
    screen.onclick(on_click)
    screen.listen()
    screen.mainloop()

draw_on_click()

正弦波动画

import turtle
import math

def animate_sine_wave(periods=2, amplitude=80):
    screen = turtle.Screen()
    screen.title("正弦波动画")
    screen.bgcolor("white")
    screen.setup(800, 400)
    screen.tracer(0)
    
    pen = turtle.Turtle()
    pen.speed(0)
    pen.hideturtle()
    pen.pensize(3)
    
    width = screen.window_width() / 2
    origin_x = -width
    
    pen.color("#ccc")
    pen.penup()
    pen.goto(origin_x, 0)
    pen.pendown()
    pen.forward(width * 2)
    
    pen.color("#2196F3")
    pen.penup()
    pen.goto(origin_x, 0)
    pen.pendown()
    
    for x in range(int(origin_x), int(origin_x + width * 2)):
        angle = math.radians((x - origin_x) / width * periods * 360)
        y = amplitude * math.sin(angle)
        pen.goto(x, y)
    
    screen.update()
    screen.mainloop()

animate_sine_wave(periods=3, amplitude=80)

实用工具函数

随机涂鸦生成器

import turtle
import random

def random_drawings(num_shapes=50, max_size=100):
    screen = turtle.Screen()
    screen.title("随机涂鸦")
    screen.bgcolor("white")
    screen.tracer(False)
    
    pen = turtle.Turtle()
    pen.speed(0)
    pen.pensize(2)
    
    shapes = ["circle", "square", "triangle", "hexagon", "star"]
    positions = []
    
    for _ in range(num_shapes):
        x = random.randint(-350, 350)
        y = random.randint(-250, 250)
        
        overlaps = any(abs(px - x) < 50 and abs(py - y) < 50 for px, py in positions)
        if overlaps:
            continue
        
        positions.append((x, y))
        shape = random.choice(shapes)
        size = random.randint(10, max_size)
        
        pen.penup()
        pen.goto(x, y)
        pen.setheading(random.randint(0, 360))
        pen.pendown()
        
        color = f"#{random.randint(0,255):02x}{random.randint(0,255):02x}{random.randint(0,255):02x}"
        pen.pencolor(color)
        pen.fillcolor(color)
        pen.begin_fill()
        
        if shape == "circle":
            pen.circle(size)
        elif shape == "square":
            for _ in range(4):
                pen.forward(size)
                pen.left(90)
        elif shape == "triangle":
            for _ in range(3):
                pen.forward(size)
                pen.left(120)
        elif shape == "hexagon":
            for _ in range(6):
                pen.forward(size / 1.5)
                pen.left(60)
        elif shape == "star":
            for _ in range(5):
                pen.forward(size * 1.5)
                pen.right(144)
        
        pen.end_fill()
    
    screen.update()
    pen.hideturtle()
    screen.mainloop()

random_drawings(30, 80)

总结

本文系统讲解了 turtle 海龟绘图的核心技能:

  1. 基础操作 — forward/right/left/goto/circle 等核心命令
  2. 几何图案 — 螺旋线、对称图案、渐变圆形
  3. 分形图形 — 科赫雪花、谢尔宾斯基三角形、分形树
  4. 交互控制 — 键盘输入、鼠标点击、实时响应
  5. 动画效果 — 正弦波动画、自动绘制
  6. 创意编程 — 随机涂鸦生成器

turtle 虽简单却强大,适合学习编程思维、创作艺术图案、制作教育演示。


本文是 Python 教程系列的第四十六篇。