- 用 Python turtle 画一个漂亮的小夜空
- 一、创作目标
- 二、核心实现思路
- 1)先搭画布,再关动画刷新
- 2)渐变夜空怎么做
- 3)月牙怎么做
- 4)星空层次怎么做
- 5)远山与流星
- 三、代码结构建议
- 四、适合教学的拓展题
- 五、结语
- 六、完整代码
用 Python turtle 画一个漂亮的小夜空
如果你想给孩子做一个“看得见、马上有成就感”的 Python 小项目,turtle 是很棒的起点。
这次我们画一个小夜空:有渐变天空、月亮、星星、流星和远山。

一、创作目标
我们希望这幅图具备三个特点:
- 简单可读:函数拆分清晰,初学者能看懂。
- 视觉好看:不是简单几何图,而是有层次的场景。
- 容易扩展:后续可以继续加动画和新元素。
二、核心实现思路
1)先搭画布,再关动画刷新
通过 screen.tracer(False) 暂停逐帧刷新,全部画完再 update(),可以减少绘制闪烁,让效果更“完整”。
2)渐变夜空怎么做
turtle 没有直接的渐变 API,我们用“很多条横线”模拟渐变:
- 从上到下循环 y 坐标;
- 每一行根据比例计算 RGB;
- 画一条横线覆盖整屏宽度。
这样就能得到从深色到浅色的天空变化。
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()