200字
用 Python turtle 画一个漂亮的小夜空
2026-05-02
2026-05-02
  • 用 Python turtle 画一个漂亮的小夜空
    • 一、创作目标
    • 二、核心实现思路
      • 1)先搭画布,再关动画刷新
      • 2)渐变夜空怎么做
      • 3)月牙怎么做
      • 4)星空层次怎么做
      • 5)远山与流星
    • 三、代码结构建议
    • 四、适合教学的拓展题
    • 五、结语
    • 六、完整代码

用 Python turtle 画一个漂亮的小夜空

如果你想给孩子做一个“看得见、马上有成就感”的 Python 小项目,turtle 是很棒的起点。
这次我们画一个小夜空:有渐变天空、月亮、星星、流星和远山。

image-zMlS.png

一、创作目标

我们希望这幅图具备三个特点:

  • 简单可读:函数拆分清晰,初学者能看懂。
  • 视觉好看:不是简单几何图,而是有层次的场景。
  • 容易扩展:后续可以继续加动画和新元素。

二、核心实现思路

1)先搭画布,再关动画刷新

通过 screen.tracer(False) 暂停逐帧刷新,全部画完再 update(),可以减少绘制闪烁,让效果更“完整”。

2)渐变夜空怎么做

turtle 没有直接的渐变 API,我们用“很多条横线”模拟渐变:

  • 从上到下循环 y 坐标;
  • 每一行根据比例计算 RGB;
  • 画一条横线覆盖整屏宽度。

这样就能得到从深色到浅色的天空变化。

3)月牙怎么做

步骤非常直观:

  1. 先画一个浅黄色圆(满月)。
  2. 再在偏右位置画一个深色圆覆盖。
  3. 两圆交叠后,视觉上就得到弯月。

4)星空层次怎么做

我们混合两类元素:

  • 五角星:有造型感,数量适中。
  • 小亮点:使用 dot() 快速点缀,增加“密度感”。

这比只画一种星星更自然。

5)远山与流星

  • 远山用多边形填充,并分两层深浅来制造景深。
  • 流星画一条斜线,并逐段降低亮度,形成“拖尾”感觉。

三、代码结构建议

把每个画面元素拆成函数:

  • draw_gradient_sky()
  • draw_moon()
  • draw_stars()
  • draw_hills()
  • draw_shooting_star()

主函数 main() 只负责组织顺序,这样代码更容易维护。

四、适合教学的拓展题

  • 让星星随机闪烁(定时刷新 + 重绘)。
  • 加入一排小房子,点亮窗户。
  • 流星改成随机位置和随机长度。
  • 增加“名字签名”和日期,做成专属作品。

五、结语

turtle 的魅力就在于:几行代码就能把想象变成画面。
从这个小夜空开始,孩子会更容易建立“编程 = 创造”的正反馈。

六、完整代码

import math
import random
import turtle


WIDTH = 900
HEIGHT = 650


def setup_screen() -> turtle.Screen:
    screen = turtle.Screen()
    screen.setup(WIDTH, HEIGHT)
    screen.title("Turtle 小夜空")
    screen.bgcolor("#04081a")
    screen.tracer(False)
    return screen


def make_pen(hidden: bool = True, speed: int = 0) -> turtle.Turtle:
    pen = turtle.Turtle(visible=not hidden)
    pen.hideturtle() if hidden else None
    pen.speed(speed)
    pen.up()
    return pen


def draw_gradient_sky(pen: turtle.Turtle) -> None:
    top = (3, 7, 25)
    bottom = (28, 44, 94)
    step = HEIGHT // 2
    y_start = HEIGHT // 2
    for i in range(step):
        ratio = i / step
        r = int(top[0] + (bottom[0] - top[0]) * ratio)
        g = int(top[1] + (bottom[1] - top[1]) * ratio)
        b = int(top[2] + (bottom[2] - top[2]) * ratio)
        pen.color((r / 255, g / 255, b / 255))
        y = y_start - i
        pen.goto(-WIDTH // 2, y)
        pen.down()
        pen.goto(WIDTH // 2, y)
        pen.up()


def draw_moon(pen: turtle.Turtle, x: int, y: int, radius: int) -> None:
    pen.goto(x, y - radius)
    pen.color("#fff2b3")
    pen.begin_fill()
    pen.down()
    pen.circle(radius)
    pen.end_fill()
    pen.up()

    # 用同色偏暗圆形覆盖,营造月牙效果
    pen.goto(x + radius * 0.35, y - radius * 0.9)
    pen.color("#0b1231")
    pen.begin_fill()
    pen.down()
    pen.circle(radius * 0.95)
    pen.end_fill()
    pen.up()


def draw_star(pen: turtle.Turtle, x: int, y: int, size: float) -> None:
    pen.goto(x, y)
    pen.setheading(random.randint(0, 360))
    pen.color("#fff8cf")
    pen.down()
    for _ in range(5):
        pen.forward(size)
        pen.right(144)
    pen.up()


def init_stars(count: int = 150) -> list[dict]:
    stars = []
    for _ in range(count):
        stars.append(
            {
                "x": random.randint(-WIDTH // 2 + 10, WIDTH // 2 - 10),
                "y": random.randint(-50, HEIGHT // 2 - 15),
                "size": random.uniform(1.5, 4.5),
                "speed": random.uniform(0.05, 0.14),
                "phase": random.uniform(0, math.tau),
            }
        )
    return stars


def render_twinkle_stars(pen: turtle.Turtle, stars: list[dict], tick: int) -> None:
    pen.clear()
    for star in stars:
        brightness = 0.35 + 0.65 * (
            0.5 + 0.5 * math.sin(tick * star["speed"] + star["phase"])
        )
        color = (
            0.7 + 0.3 * brightness,
            0.78 + 0.22 * brightness,
            0.86 + 0.14 * brightness,
        )
        pen.color(color)
        pen.goto(star["x"], star["y"])
        pen.dot(star["size"] + 2 * brightness)


def draw_hills(pen: turtle.Turtle) -> None:
    pen.goto(-WIDTH // 2, -120)
    pen.color("#0d1838")
    pen.begin_fill()
    pen.down()
    pen.goto(-380, -30)
    pen.goto(-260, -90)
    pen.goto(-90, 10)
    pen.goto(120, -70)
    pen.goto(280, 5)
    pen.goto(420, -65)
    pen.goto(WIDTH // 2, -80)
    pen.goto(WIDTH // 2, -HEIGHT // 2)
    pen.goto(-WIDTH // 2, -HEIGHT // 2)
    pen.goto(-WIDTH // 2, -120)
    pen.end_fill()
    pen.up()

    pen.goto(-WIDTH // 2, -180)
    pen.color("#081029")
    pen.begin_fill()
    pen.down()
    pen.goto(-300, -120)
    pen.goto(-120, -175)
    pen.goto(50, -110)
    pen.goto(230, -170)
    pen.goto(370, -110)
    pen.goto(WIDTH // 2, -150)
    pen.goto(WIDTH // 2, -HEIGHT // 2)
    pen.goto(-WIDTH // 2, -HEIGHT // 2)
    pen.goto(-WIDTH // 2, -180)
    pen.end_fill()
    pen.up()


def draw_shooting_star(pen: turtle.Turtle, x: int, y: int, length: int = 120) -> None:
    pen.goto(x, y)
    pen.setheading(-25)
    pen.pensize(2)
    for i in range(7):
        alpha = max(0.15, 1 - i * 0.14)
        color = (1.0, 1.0, 1.0 * alpha)
        pen.color(color)
        pen.down()
        pen.forward(length / 7)
    pen.up()
    pen.pensize(1)


def main() -> None:
    turtle.colormode(1.0)
    screen = setup_screen()
    pen = make_pen()  # 静态层:天空、月亮、远山
    star_pen = make_pen()  # 动态层:闪烁星星
    stars = init_stars()
    tick = 0

    draw_gradient_sky(pen)
    draw_moon(pen, x=220, y=180, radius=55)
    draw_shooting_star(pen, x=-250, y=200)
    draw_hills(pen)

    def animate() -> None:
        nonlocal tick
        tick += 1
        render_twinkle_stars(star_pen, stars, tick)
        screen.update()
        screen.ontimer(animate, 60)

    animate()
    screen.update()
    screen.mainloop()


if __name__ == "__main__":
    main()
用 Python turtle 画一个漂亮的小夜空
作者
一晌小贪欢
发表于
2026-05-02
License
CC BY-NC-SA 4.0

评论