找到一个挺漂亮的图片,我们试着用python把它画出来。
打算的构图:
1.富士山 2.花田 3.樱花树 4.樱花雨
第一步,导入绘图库,建立画布,找准坐标,做到心中有数
import turtle as t
t.setup(800,600,0,0)
画布中心为(0,0),左右边界(-400,400)上下边界(-300,300)
第二步 1,填充背景色
在网络上选择一个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()
效果:
存在问题:
- 树干树枝长度相同,使樱树不够逼真,应将其设置成变量,在递归过程中长度递减
- 树枝偏转角度过于死板,应加入随机数使得树枝更仿生
- 树干树枝粗细、颜色都相同,也应改进为递减的
- 没有樱花,当递归至最后一层应画上樱花
樱树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()