爱心树——turtle库(python代码)

一、整体结构

        我们先来设计一下大概的框架,后面再逐步完善他,在这篇文章最后会有完整的代码给大家。我在前面介绍过turtle函数,在这里我就不重复介绍了,但是还是会点到他的基本操作的。

import turtle
import random

def love(x, y):  # 定义画爱心的函数
    # ...

def tree(branchLen, t):  # 定义递归画树的函数
    # ...

# 主程序
myWin = turtle.Screen()  # 创建窗口
t = turtle.Turtle()      # 创建主画笔
# 初始化设置...
tree(100, t)             # 开始画树
myWin.exitonclick()      # 点击关闭窗口

        在这里大家可能会好奇random函数是什么?其实random 是 Python 内置的随机数生成模块,用于生成各种随机数据。可以生成随机整数、随机小数、随机选择元素,甚至打乱列表顺序等。后面我还是会单独说一下andom函数的,请大家放心。

二、逐步进行完善

1、我们先完善love函数,但是怕大家看不懂,我们还是一步一步来完善吧!

功能:在指定坐标 (x, y) 处绘制一个爱心,并写上文字 "love"。

(1) 创建画笔
lv = turtle.Turtle()  # 想象你拿到一支新画笔
lv.hideturtle()       # 隐藏画笔的笔尖图标(只显示画的图形)
lv.up()               # 抬起画笔(移动时不画线)
lv.goto(x, y)         # 把画笔移动到指定的(x,y)坐标位置
  • 类比:就像你画画前拿起一支新笔,调整位置但不留下痕迹。

(2) 定义画圆弧的辅助函数

def curvemove():    # 定义一个画圆弧的动作
    for i in range(20):
        lv.right(10)   # 画笔向右转10度
        lv.forward(2)   # 向前画2像素
  • 作用:通过多次“右转 + 前移”画出一个圆弧。

  • 类比:像用圆规画弧,每次转一点角度,走一小段。

(3) 设置画笔属性
def curvemove():    # 定义一个画圆弧的动作
    for i in range(20):
        lv.right(10)   # 画笔向右转10度
        lv.forward(2)   # 向前画2像素
(4) 绘制爱心主体
lv.down()        # 落下画笔开始画图
lv.begin_fill()  # 开始填充颜色(后续闭合图形会被填充粉色)

lv.left(140)     # 向左转140度(调整起始方向)
lv.forward(22)   # 向前画22像素(爱心左侧的直线部分)
curvemove()      # 调用之前定义的圆弧函数(画左半边的弧)
lv.left(120)     # 再向左转120度(调整方向画右半边)
curvemove()      # 再画一个圆弧(右半边的弧)
lv.forward(22)   # 向前画22像素(爱心右侧的直线部分)

lv.write("YZ", font=("Arial", 12, "normal"), align="center")  # 在中心写字
lv.left(140)     # 转回初始方向(让画笔复位)
lv.end_fill()    # 结束填充(闭合区域被填满粉色)

(5)爱心绘制流程

想象你按以下步骤手动绘制:

  • (1)笔尖移动到起始点
  • (2)向左转140度,画一条向左上方的线
  • (3)向右连续小幅度转20次,每次画一小段,形成一个左半圆弧
  • (4)再向左转120度,重复画右半圆弧
  • (5)最后闭合图形,形成爱心形状

(6)可视化步骤

        左转140°
        ↗
       / \
      /   \← 左转120°后的右半圆弧
     /     \
   直线22px 曲线

(7)关键点总结

代码部分作用类比
lv = turtle.Turtle()创建新画笔拿一支新彩笔
lv.goto(x, y)定位到坐标点把笔尖移到纸的某个位置
curvemove()画圆弧的重复动作用圆规画弧
begin_fill()/end_fill()填充闭合区域颜色用彩笔涂满封闭区域

(8)love函数的整体完善如下:

​
def love(x, y):
    lv = turtle.Turtle()  # 创建一个新的海龟对象(专门用来画爱心)
    lv.hideturtle()       # 隐藏海龟图标
    lv.up()               # 抬起画笔(移动时不画线)
    lv.goto(x, y)         # 移动到指定坐标

    # 定义内部函数:画圆弧
    def curvemove():
        for i in range(20):
            lv.right(10)   # 右转10度
            lv.forward(2)  # 画2像素

    # 设置画笔属性
    lv.color('red', 'pink')  # 边框红色,填充粉色
    lv.speed(10000000)       # 最快速度
    lv.pensize(1)            # 线条粗细

    # 开始绘制爱心
    lv.down()            # 落下画笔
    lv.begin_fill()      # 开始填充颜色
    lv.left(140)         # 左转140度
    lv.forward(22)       # 画直线22像素
    curvemove()          # 画左侧圆弧
    lv.left(120)         # 左转120度
    curvemove()          # 画右侧圆弧
    lv.forward(22)       # 画直线22像素
    lv.write("love", font=("Arial", 12, "normal"), align="center")  # 在爱心中心写文字
    lv.left(140)         # 复位方向
    lv.end_fill()        # 结束填充

​

2、现在我们来逐步完善tree 函数

功能:递归绘制树枝,当树枝较短时在末端画爱心。

(1) 终止条件:树枝太短就停止生长

if branchLen > 5:  # 如果树枝长度>5才继续
    # 后续代码...
else:
    return  # 停止生长
  • 类比:就像真实树枝不可能无限变细,当树枝太短(≤5像素)时停止分叉。

(2) 短树枝末端画爱心
if branchLen < 20:  # 短树枝(嫩枝)
    t.color("green")               # 嫩枝设为绿色
    t.pensize(...)                 # 随机粗细(模拟自然变化)
    t.forward(branchLen)           # 画这段树枝
    love(t.xcor(), t.ycor())       # 在末端画爱心(开花)
    t.backward(branchLen)          # 退回原点(回到分叉点)
    return                         # 结束当前分支的生长
  • 类比:树枝末端长出一朵花(爱心),之后不再分叉。

(3) 长树枝分叉逻辑
# 画当前树枝
t.pensize(...)           # 随机粗细
t.forward(branchLen)     # 向前画主树枝

# 向右分叉
ang = random.uniform(15, 45)  # 随机右转角度(15~45度之间)
t.right(ang)                  # 右转
tree(branchLen - 随机减少长度, t)  # 画右侧更短的树枝(递归调用自己)

# 向左分叉
t.left(2 * ang)               # 左转两倍角度(回到原点后左转)
tree(branchLen - 随机减少长度, t)  # 画左侧更短的树枝

# 复位
t.right(ang)           # 转回原来的方向
t.backward(branchLen)  # 退回分叉起点
  • 类比

    • 先画一段主树枝。

    • 向右随机转一个角度,分叉出一根更短的树枝。

    • 再向左转更大的角度,分叉出另一根短树枝。

    • 回到分叉点,准备画其他分支。

(4)递归过程图解

假设初始 branchLen=100

第1层:画100长的树枝
  右转30度 → 第2层:画85长的树枝(100-15)
    右转25度 → 第3层:画70长的树枝
      ...
      直到长度<20时画爱心
  左转60度 → 第2层:画80长的树枝(100-20)
    右转40度 → 第3层:画65长的树枝
      ...

(5)关键点总结

代码部分作用类比
tree(branchLen - ..., t)递归生成更短的分支树枝分叉后变细变短
ang = random.uniform(15,45)随机分叉角度自然生长的树枝角度不规则
t.right(ang) 和 t.left(2*ang)先右转分叉,再左转更大的角度分叉左右对称分叉
backward(branchLen)退回分叉起点画完分支后回到主干

(6)tree 函数函数具体完善如下:

def tree(branchLen, t):
    if branchLen > 5:  # 递归终止条件:树枝长度≤5时停止
        if branchLen < 20:  # 短树枝末端画爱心
            t.color("green")               # 短树枝设为绿色
            t.pensize(random.uniform((branchLen +5)/4-2, (branchLen+6)/4+5))  # 随机粗细
            t.down()                        # 落下画笔
            t.forward(branchLen)            # 画短树枝
            love(t.xcor(), t.ycor())        # 在当前位置画爱心
            t.up()                          # 抬起画笔
            t.backward(branchLen)           # 退回原位
            t.color("brown")                # 恢复树枝颜色
            return                          # 结束递归

        # 长树枝逻辑
        t.pensize(random.uniform(...))  # 随机设置粗细
        t.down()
        t.forward(branchLen)            # 画当前树枝

        # 递归生成分支
        ang = random.uniform(15, 45)     # 随机分支角度
        t.right(ang)                     # 右转随机角度
        tree(branchLen - random.uniform(12, 16), t)  # 画右侧分支(长度随机减少)
        t.left(2 * ang)                  # 左转两倍角度
        tree(branchLen - random.uniform(12, 16), t)  # 画左侧分支
        t.right(ang)                     # 复位方向
        t.up()                           # 抬起画笔
        t.backward(branchLen)            # 退回原位

3、我们来完善主程序吧!

(1)创建窗口和画笔

myWin = turtle.Screen()  # 创建一张画布(想象拿出一张白纸)
t = turtle.Turtle()      # 创建一支画笔(笔尖默认在画布中心)
t.hideturtle()           # 隐藏笔尖图标(只显示画出的图形)
  • 效果:你有了画布和一支看不见笔尖的“魔法笔”。

(2)画笔初始设置

t.speed(1000)    # 设置画笔移动速度为最快(避免绘制动画卡顿)
t.left(90)       # 笔尖向左转90度(默认朝右→转后朝上,像竖直方向)

  • 类比:把笔竖直立起来,准备从上往下画树。

(3)定位到树干起点

t.up()           # 抬起笔尖(移动时不画线)
t.backward(200)  # 笔尖向下移动200像素(从中心下移,到树干底部)
t.down()         # 落下笔尖(开始画线)
  • 类比:把笔竖直立起来,准备从上往下画树。

  • 操作流程
  1. 抬笔 → 避免移动时画线

  2. 向下移动 → 到树干起点

  3. 落笔 → 准备画树干

(4)绘制树干

t.color("brown")  # 设置颜色为棕色(像树干的颜色)
t.pensize(32)     # 设置笔触粗细32像素(粗树干)
t.forward(60)     # 向上画60像素(树干高度)
  • 效果:在画布下方画出一段粗壮的棕色树干。

(5)开始画树枝

tree(100, t)  # 调用tree函数,从树干顶端开始画树枝(初始长度100)

(6)保持窗口显示

myWin.exitonclick()  # 点击画布任意位置关闭窗口
  • 作用:防止程序运行完自动关闭窗口,保持图形显示。

(7)完整流程示意图

1. 创建画布和笔
2. 笔朝上,抬笔移动到下方(树干起点)
3. 落笔画棕色粗树干
   │
   ↑ 60像素
4. 在树干顶端调用 tree(100) 开始递归分叉
   ├─右分支
   └─左分支
      ...
5. 点击关闭窗口

(8)参数调整建议

参数修改示例效果变化
t.backward(200) → t.backward(300)树干起点更低整棵树位置更靠下
t.pensize(32) → t.pensize(50)树干更粗更粗壮的树干
t.forward(60) → t.forward(100)树干更高更长的主干
tree(100, t) → tree(150, t)初始树枝更长树冠更茂密

(9)主程序完整代码如下:

myWin = turtle.Screen()  # 创建绘图窗口
t = turtle.Turtle()      # 创建主画笔对象
t.hideturtle()           # 隐藏海龟图标
t.speed(1000)            # 最快绘制速度
t.left(90)               # 初始方向朝上(默认向右)
t.up()                   # 抬起画笔
t.backward(200)          # 向下移动200像素(从底部开始画树干)
t.down()                 # 落下画笔
t.color("brown")         # 树干颜色
t.pensize(32)            # 树干粗细
t.forward(60)            # 画树干(高度60像素)
tree(100, t)             # 开始递归画树枝(初始长度100)
myWin.exitonclick()      # 点击窗口关闭

4、执行流程

  • 初始化窗口和画笔。

  • 绘制棕色树干。

  • 递归绘制树枝:

    • 长树枝:分左右两支,随机角度和长度。

    • 短树枝:末端画绿色并添加爱心。

  • 点击窗口关闭。

三、完整代码如下:

import turtle
import random


def love(x, y):  # 定义画爱心的函数
    lv = turtle.Turtle()
    lv.hideturtle()
    lv.up()
    lv.goto(x, y)  # 定位到(x,y)

    # 定义内部函数:画圆弧
    def curvemove():  # 画圆弧
        for i in range(20):
            lv.right(10)
            lv.forward(2)

    # 设置画笔属性
    lv.color('red', 'pink')
    lv.speed(10000000)
    lv.pensize(1)

    # 开始绘制爱心
    lv.down()
    lv.begin_fill()
    lv.left(140)
    lv.forward(22)
    curvemove()
    lv.left(120)
    curvemove()
    lv.forward(22)
    lv.write("love", font=("Arial", 12, "normal"), align="center")  # 写上表白的人的名字
    lv.left(140)  # 画完复位
    lv.end_fill()


def tree(branchLen, t):
    if branchLen > 5:  # 剩余树枝太少要结束递归
        if branchLen < 20:  # 如果树枝剩余长度较短则变绿
            t.color("green")
            t.pensize(random.uniform((branchLen + 5) / 4 - 2, (branchLen + 6) / 4 + 5))
            t.down()
            t.forward(branchLen)
            love(t.xcor(), t.ycor())  # 传输现在turtle的坐标
            t.up()
            t.backward(branchLen)
            t.color("brown")
            return
        t.pensize(random.uniform((branchLen + 5) / 4 - 2, (branchLen + 6) / 4 + 5))
        t.down()
        t.forward(branchLen)
        # 以下递归
        ang = random.uniform(15, 45)
        t.right(ang)
        tree(branchLen - random.uniform(12, 16), t)  # 随机决定减小长度
        t.left(2 * ang)
        tree(branchLen - random.uniform(12, 16), t)  # 随机决定减小长度
        t.right(ang)
        t.up()
        t.backward(branchLen)


myWin = turtle.Screen()
t = turtle.Turtle()
t.hideturtle()
t.speed(1000)
t.left(90)
t.up()
t.backward(200)
t.down()
t.color("brown")
t.pensize(32)
t.forward(60)
tree(100, t)
myWin.exitonclick()

运行结果如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值