[MoocPython课程]Turtlr库绘图之“富士山下”

找到一个挺漂亮的图片,我们试着用python把它画出来。

在这里插入图片描述
打算的构图:
1.富士山 2.花田 3.樱花树 4.樱花雨
第一步,导入绘图库,建立画布,找准坐标,做到心中有数

import turtle as t
t.setup(800,600,0,0)

画布中心为(0,0),左右边界(-400,400)上下边界(-300,300)
第二步 1,填充背景色
https://tool.oschina.net/commons?type=3
在网络上选择一个RGB颜色对照表

t.bgcolor('Thistle')  # 背景色
	2.画富士山
	选择富士山的颜色:深蓝色
t.fillcolor('RoyalBlue3')
t.begin_fill()
t.seth(15)
t.circle(800,15)
print('雪山左标记点:',t.position())
t.circle(800,15)

在这里之所以不一次性把弧形画完,是因为想找出这个点,方便后面画山上的积雪。
用到turtle.position()调出此刻的坐标。

t.seth(-15)
t.circle(250,30)

这是山顶的弧线

t.seth(-50)
t.circle(800,15)
print('雪山右标记点:', t.position())
t.circle(800, 15)

山右侧的弧线

t.end_fill()

结束山体颜色(深蓝色)填充
3.画积雪

t.fillcolor('Snow2')
t.begin_fill()
jumpTo(-207.06,79.92)#左标记点
t.seth(30)
t.circle(800, 15)#左半弧
t.seth(-15)
t.circle(250, 30)#上弧
t.seth(-50) 
t.circle(800, 15) #右弧
t.seth(-142)
t.circle(-350,80) #下弧
t.end_fill()

跳至刚才的标记点圈出积雪范围,填充挑选和的颜色
3.花田,大体方法同雪山,其实比雪山更简单

地面

def land():
    jumpTo(-400,0)
    t.pencolor('DarkViolet')
    t.fillcolor('DarkViolet')
    t.begin_fill()
    t.goto(-400,-150)
    t.seth(0)
    t.circle(600,39.5)
    t.goto(-400,0)
    t.end_fill()
    t.pencolor('Plum')
    t.fillcolor('Plum')
    t.begin_fill()
    jumpTo(-400, 0)
    t.goto(-400, -150)
    t.seth(0)
    t.circle(600, 39.5)
    t.goto(400,-22)
    t.goto(400,-300)
    t.goto(-400,-300)
    t.goto(-400,0)
    t.end_fill()
4.樱树

用到了递归的思想,
假设,只有一层树的话,(落笔,画枝,抬笔,返回),若多层的话就需要判断层树并转角度画枝。
樱树1.0

import turtle as t
def tree(n):
    t.pd()
    t.fd(50)
    if n>0:
        t.right(30)
        tree(n-1)
        t.left(30+30)
        tree(n-1)
        t.right(30)
    t.pu()
    t.backward(50)

t.setup(800,600,0,0)
t.seth(90)
tree(3)
t.done()

效果:
在这里插入图片描述
存在问题:

  1. 树干树枝长度相同,使樱树不够逼真,应将其设置成变量,在递归过程中长度递减
  2. 树枝偏转角度过于死板,应加入随机数使得树枝更仿生
  3. 树干树枝粗细、颜色都相同,也应改进为递减的
  4. 没有樱花,当递归至最后一层应画上樱花
    樱树2.0
def sTree(x,y,n,l):
    jumpTo(x,y)
    t.seth(90)
    sakuraT(n,l)

def sakuraT(n,l):
    t.pd()
    # 树干颜色的渐变
    tt = math.cos(math.radians(t.heading() + 45)) / 8 + 0.25
    t.pencolor(tt, tt, tt)
    t.pensize(n*2)
    # 树干粗细的渐变
    t.forward(l)
    if n>0:
        b = random.random() * 15 + 10  # 右分支偏转角度
        c = random.random() * 15 + 10  # 左分支偏转角度
        d = l * (random.random() * 0.25 + 0.7)  # 下一个树枝的长度
        t.right(b)
        sakuraT(n-1,d)
        t.left(b+c)
        sakuraT(n-1,d)
        t.right(c)
    else:
        t.right(90)
        t.pencolor('DeepPink')
        t.circle(3)
        t.left(90)
    t.pu()
    t.backward(l)

效果:
在这里插入图片描述
5.樱花雨
创建一个颜色列表,每场雪50个雪花,所谓雪花即画一个圈,在选定范围用随机函数random.randint()选取(x,y)的坐标,再用random.choice()从颜色列表中随机选取雪花的颜色。

雪花

def snow(x,y,r):
    jumpTo(x,y)
    t.circle(r)

def snowS():
    colorList = ['Orchid1','Orchid2','Orchid3','Orchid4']
    for i in range(50):
        x=random.randint(-400,400)
        y=random.randint(1,300)
        r=random.randint(1,10)
        c=random.choice(colorList)
        t.pencolor(c)
        t.fillcolor(c)
        t.begin_fill()
        snow(x,y,r)
        t.end_fill()

主函数:
把画笔速度提高一些,雪花和数后画,因为再视野前面
并且选择先画树再画雪再画树,这样更逼真

t.speed(0)
fjmountain()
land()
for i in range(2):
    sTree(random.randint(-300,300),random.randint(-300,-150),7,100)
    snowS()
t.done()

注:
我们经常用到的跳跃函数是自己包装好的

跳跃函数

def jumpTo(x,y):
    t.penup()
    t.goto(x,y)
    t.pendown()

最终效果:
在这里插入图片描述
补充:
引发一个思考,能不能把填充颜色这个功能包装起来,然后循环一次性填充完呢?

第一次尝试,把颜色放入colorlist列表中,函数放入functionlist列表中,然后循环

colorList = [ 'DarkViolet','Plum','RoyalBlue3','Snow2']
functionList = [land0(),land1(),fjmountain(),snowOnM()]

for i in range(4):
    t.fillcolor(colorList[i])
    t.pencolor(colorList[i])
    t.begin_fill()
    functionList[i]
    t.end_fill()

结果发现,运行代码,只画线,不填色。
在这里插入图片描述
问题究竟出在哪里呢?是函数不能作为对象存储在列表中吗?
并不是的,在python中,任何对象都被认为是可以存储在列表中的
但错就错在,列表中应该存放函数名,而不是直接function()
加了括号,那就直接调用了,换句话说,我之前的函数都没有返回值,那列表中就是很多个空值,调用出来也没什么效果,自然无法填充,函数名不加括号(),才代表的是这个函数,加括号就是执行这个函数!!!!!
最终改动代码如下:

import turtle as t
import math
import random
t.setup(800,600,0,0)
# 跳跃函数
def jumpTo(x,y):
    t.penup()
    t.goto(x,y)
    t.pendown()
# 富士山
def fjmountain():
    jumpTo(-400,0)
    t.seth(15)
    t.circle(800,15)
    # print('雪山左标记点:',t.position())
    t.circle(800,15)
    # print('雪山左顶点:', t.position())
    t.seth(-15)
    t.circle(250,30)
    t.seth(-50)
    t.circle(800,15)
    # print('雪山右标记点:', t.position())
    t.circle(800, 15)
    # print('雪山右顶点:', t.position())
    print(t.position())

def snowOnM():
    jumpTo(-207.06, 79.92)
    t.seth(30)
    t.circle(800, 15)
    t.seth(-15)
    t.circle(250, 30)
    t.seth(-50)
    t.circle(800, 15)
    t.seth(-142)
    t.circle(-350, 80)

# 雪花
def snow(x,y,r):
    jumpTo(x,y)
    t.circle(r)

def snowS():
    colorList = ['Orchid1','Orchid2','Orchid3','Orchid4']
    for i in range(50):
        x=random.randint(-400,400)
        y=random.randint(1,300)
        r=random.randint(1,10)
        c=random.choice(colorList)
        t.pencolor(c)
        t.fillcolor(c)
        t.begin_fill()
        snow(x,y,r)
        t.end_fill()

def sTree(x,y,n,l):
    jumpTo(x,y)
    t.seth(90)
    sakuraT(n,l)

def sakuraT(n,l):
    t.pd()

    # 阴影效果
    tt = math.cos(math.radians(t.heading() + 45)) / 8 + 0.25
    t.pencolor(tt, tt, tt)
    t.pensize(n*2)
    t.forward(l)

    if n>0:
        b = random.random() * 15 + 10  # 右分支偏转角度
        c = random.random() * 15 + 10  # 左分支偏转角度
        d = l * (random.random() * 0.25 + 0.7)  # 下一个分支的长度
        t.right(b)
        sakuraT(n-1,d)
        t.left(b+c)
        sakuraT(n-1,d)
        t.right(c)
    else:
        t.right(90)
        t.pencolor('DeepPink')
        t.circle(3)
        t.left(90)
    t.pu()
    t.backward(l)
# 地面
def land0():
    jumpTo(-400, 0)
    t.goto(-400, -300)
    t.goto(400,-300)
    t.goto(400, -22)
    t.goto(-400, 0)

def land1():
    jumpTo(-400, 0)
    t.goto(-400, -150)
    t.seth(0)
    t.circle(600, 39.5)
    t.goto(-400, 0)

t.bgcolor('Thistle')  # 背景色
t.speed(0)

colorList = [ 'DarkViolet','Plum','RoyalBlue3','Snow2']
functionList = [land0,land1,fjmountain,snowOnM]

for i in range(4):
    t.fillcolor(colorList[i])
    t.pencolor(colorList[i])
    t.begin_fill()
    functionList[i]()
    t.end_fill()




for i in range(2):
    sTree(random.randint(-300,300),random.randint(-300,-150),7,100)
    snowS()
    pass
t.done()
posted @ 2020-02-24 14:04  刘生伟  阅读(41)  评论(0编辑  收藏  举报