# 从Scratch到Python之角色与造型
>继续讲解通过python turtle从积木编程过渡到代码编程的技巧.角色是scratch中很重要的主角,每个角色可以更换不同的造型或者音效,堆叠不同的积木.如果把角色比做人,造型就是人物外观或者动作的变化,比如穿着运动服,打棒球或者走路等不同的造型.接下来我可能会很少截图,**因为如果你看我文章的时候也跟着做了,那么还需要我截图么?**
## 新增角色或者造型
Scratch中新增角色或者造型有以下四种方法
![新建角色的四中方法](http://upload-images.jianshu.io/upload_images/1108512-1f600ddc95f86f23.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
* 从角色库中选择角色
* 绘制新的角色或者给角色绘制新的造型
* 上传电脑绘画作品
* 利用摄像头拍照
以上四种角色在Python turtle中也是有的
### 从"角色库中选择"
![Scratch改变角色造型的代码块](http://upload-images.jianshu.io/upload_images/1108512-870beb52c71eb2ff.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![某个角色在Scratch的造型](http://upload-images.jianshu.io/upload_images/1108512-1142cb73e843d84b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
Python turtle中,默认的角色是小乌龟,小乌龟默认有以下几种形状:
* 箭头
* 乌龟
* 圆
* 方块
* 三角形
* 经典形状
相比于Scratch,Python turtle在默认角色这方面真的是木有优势,被吊打啊,比较少.
以上只能看做是同一个角色的造型,更改造型需要用到```shape()```命令,
```
>>> turtle.shape()
'arrow'
>>> turtle.shape("turtle")
>>> turtle.shape()
'turtle'
```
我们通过上述方法来改变角色的造型,如果想做动画,可以这样写
```
for i in range(2):
shape('turtle')
sleep(0.1)
shape('circle')
sleep(0.1)
```
通过循环,不停的切换shape,就都达到了角色造型动画的效果,类似于scratch中的下一个造型
完整的Python程序如下
```
from turtle import *
from time import *
def movitation():
for i in range(2):
shape('turtle')
sleep(0.1)
shape('circle')
sleep(0.1)
for i in range(10):
movitation()
forward(10)
```
![改变外观](http://upload-images.jianshu.io/upload_images/1108512-a9673d61187738c9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![改变外观](http://upload-images.jianshu.io/upload_images/1108512-34614446bf3462e0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
#### 增加角色
Python turtle增加角色要比scratch简单的多,只需要用turtle命令就可以了
```
newSprite = Turtle();
```
通过以上方式我们就利用默认的模版新建了一个名字是newSprite的角色.
然后我们可以用上述方式改变角色的造型了.
### 上传图片的方式新建角色或者造型
在scratch中通过上传图片新建角色或者造型很容易,在Python turtle中也不难.
需要注意的是在Python turtle中,所有的角色都是通过```Turtle()```命令生成的,但是我们可以通过改变shape来形成不同的角色和造型.
要通过自定义图片来新建角色造型,我们首先要由图片,但是Python只支持gif格式的图片,同时大家最好设置的是**背景透明的gif图片**效果才好的.
这里要用到的是**```register_shape()```**命令.
步骤如下
* 生成一个叫c.gif的gif图像并且与py文件在相同目录
* 写代码导入
```
from turtle import *
from time import *
register_shape('c.gif')
shape('c.gif')
```
通过以上代码,把造型c.gif导入程序,然后运行.这个过程就像是我们单击
![](http://upload-images.jianshu.io/upload_images/1108512-d223273216ca64a7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)然后倒入图像一样的.
![Python turtle改变角色外观](http://upload-images.jianshu.io/upload_images/1108512-4365a8855ddd4ad6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
### 自行绘制
Python turtle中没有绘图编辑器,所以你可以自己在别的软件中绘制造型,然后保存成gif图像,当然你也可以利用程序绘制一些图形作为角色,当然这个就比较复杂了.
### 通过摄像头拍照
强大的Python当然可以读取摄像头数据,然后生成gif图像,通过对应的库即可,而且Python强大的功能还可以对数据进行分析和处理,比如进行人脸识别,只把人脸加进来,不适合新手.
## 角色信息
![角色信息](http://upload-images.jianshu.io/upload_images/1108512-c6f88a0f423dc89e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
Scratch中的角色信息界面可以方便的查看角色的信息,在Python turtle中也是如此:
### 角色属性
角色的名字,Python turtle中的名字是通过调用```Turtle()```后返回给指定名称的变量名,这个就是变量的名字
```
spriteName = Turtle()
```
其他的比如
```
hideturtle() # 隐藏乌龟
showturtle() # 显示乌龟
right(90) # 乌龟右旋90°
left(90) # 乌龟左旋90°
ondrag() # 处理乌龟的拖拽时间
xcor() # 乌龟的x坐标
ycor() # 乌龟的y坐标
```
以下是交互式命令行执行的结果
```
>>> from turtle import *
>>> forward(10)
>>> hideturtle()
>>> showturtle()
>>> right(90)
>>> left(90)
>>> xcor()
10.0
>>> ycor()
0.0
>>>
```
### 复制角色
当然Python也是可以克隆的,比如以下代码所显示的:
```
>>> t = Turtle()
>>> 6
6
>>> t
<turtle.Turtle object at 0x000002B3BACD6EF0>
>>> t2 = t
>>> t2
<turtle.Turtle object at 0x000002B3BACD6EF0>
>>> t
<turtle.Turtle object at 0x000002B3BACD6EF0>
>>> t3 = t.clone()
>>> t3
<turtle.Turtle object at 0x000002B3BAD0A160>
>>> t4 = t2.clone()
>>> t4
<turtle.Turtle object at 0x000002B3BAD0A278>
>>>
```
可以发现t和t2指向同一个Turtle对象,而虽然t和t2指向了同一个对象,t3和t4经过克隆后所指向的代码是不同的.
### 改变角色大小
如果需要改变默认角色的大小则要用到```turtlesize()```命令
但是,似乎对于通过```register_shape()```方法导入的gif图片无法通过这种方式来改变大小,以下是示例代码
```
from turtle import *
from time import *
t = Turtle();
t.turtlesize(2, 2, 1)
t.turtlesize(2, 2, 2)
t.turtlesize(4, 8, 1)
```
![你会发现这根默认的角色箭头形状不一样的](http://upload-images.jianshu.io/upload_images/1108512-8f7471f2da23f363.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
## Scratch中的节目介绍于Python turtle对应的实现
因为Python turtle中没有绿色的旗子所以没有当绿旗被点击.
### 侦测键盘
Scratch有当按下键盘按键执行某事,Python turtle对这个的支持是很强大的,比如我们来实现当空格键被按的时候,角色向右移动10个单位
![松开空格移动10步](http://upload-images.jianshu.io/upload_images/1108512-594e69b0c5690cec.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
```
from turtle import *
def on_right():
forward(10)
onkey(on_right, 'Right')
```
复杂点像下面的程序
```
from turtle import *
def on_right():
forward(10)
onkey(on_right, 'Right')
cat = Turtle()
def on_space():
cat.forward(10)
onkey(on_space, 'space')
dog = Turtle()
dog.left(90)
def on_up():
dog.forward(10)
onkey(on_up, 'Up')
listen()
```
猜测这个程序运行后是什么样子?
>___________________________________________________________________________________________________________________________________________________________________________________________________________________________
![按键](http://upload-images.jianshu.io/upload_images/1108512-88057ce9973de598.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
### 多媒体功能
scratch可以侦测音量的大小,当然读取的是电脑麦克风的音量;计时器的值;和视频侦测.
不得不承认的是,scratch在这方面封装的很棒,但也仅止于此了;Python turtle是基于Python开发的,Python在多媒体处理,计算机视觉方面的功能十分强大,配合OpenCVC库,绝对的神兵利器,但是在这里,作为Python代表的Python turtle不能够发挥Python的水准,真是虎落平阳被犬欺啊.不过Scratch也是MIT媒体实验室经过10年的开发猜到现在这个样子而且主打多媒体故事,游戏以及互动故事的制作,而Python turtle在面向孩子编程方面并没有关注这方面,因为能够用Python turtle开发熟练程序的孩子最后去学习正儿八经的Python编程了,不再用积木块这种小儿科的东西了.
### 切换背景或者当角色被单击
#### 背景切换
![背景切换](http://upload-images.jianshu.io/upload_images/1108512-6390d061ea1c5e0e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
在python turtle中切换背景是很简单的,需要用到```bgpic()```命令,不过需要图片是gif格式.
```
from turtle import *
bgpic('b.gif') # 把程序背景切换成b.gif
```
![切换背景](http://upload-images.jianshu.io/upload_images/1108512-27f1ec0a01d1ca60.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
虽然切换背景很容易,但是Python turtle并非像Scratch一样专门为多媒体而设计所以在这些方面功能有点不足,这样比对Python对Python turtle是不公平的.不过Python有很多库可以解决这个问题,比如```pygame```和```pyglet```
>改进点:背景切换以及背景切换侦测事件
#### 当角色被单击
![角色被单击](http://upload-images.jianshu.io/upload_images/1108512-5504f8457d28e9f6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
这个很简单要用到```onclick()```命令
```
from turtle import *
def move(x, y): # 注意这里是单击的坐标值
goto(0, -180)
onclick(move)
```
运行代码观察效果,会发现当角色被单击的时候,小箭头向下运动了180个单位
```
from turtle import *
def move(x, y): # 注意这里是单击的坐标值
goto(0, -180)
onclick(move, 3)
```
而以上代码,则因为给```onclick()```加了一个参数,代表是右键,那么只有当右键箭头的时候鼠标才会移动,需要注意的是1代表左键,2代表右键
### 消息广播
Scratch的消息广播实际上是ActionScript 3.0中的事件机制,ActionScript 3.0中提供的事件机制非常强大,在As3中,事件编程是一个相当高级的内容,编写游戏或者大型程序的时候十分有用当年记得清华大学胡登华和章精舍老师的As3编程书里的设计模式给我留下了深刻的印象.
![Scratch的自定义事件机制或者说消息广播机制](http://upload-images.jianshu.io/upload_images/1108512-8450aa717e7c2d06.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
Python turtle只实现了有限的鼠标,键盘和时间事件,自定义事件功能较弱需要完善.
>改进点:事件机制
## 控制模块
Scratch中的控制模块实际上对应了编程中的顺序,循环和分支三大程序结构,下面我们来一一讲解
### 控制等待时间
#### 等待多少秒
![等待1s](http://upload-images.jianshu.io/upload_images/1108512-cbe95791fc4ebe1d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
在Python涉及到时间的操作需要用到time模块,所以如果你仔细的话会发现我之前导入了```time```模块,其中就包含了让程序等待的```sleep()```命令
```
from turtle import *
from time import *
while True:
shape('turtle')
sleep(0.1)
shape('circle')
sleep(0.1)
```
实现间隔一秒,角色改变造型的动画.
#### 等待直到条件成立
![等待直到](http://upload-images.jianshu.io/upload_images/1108512-8419ae6d2d921f52.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
上面的例子```True```的含义是真,意思是这个循环会一直执行,而直到是指一直到条件成立程序才会运行
我们来看下面的例子
```
from turtle import *
from time import *
xinxiandu = 0;
while xinxiandu < 10:
shape('turtle')
sleep(0.1)
shape('circle')
sleep(0.1)
xinxiandu += 1
```
我们让新鲜度开始是0,开始会觉得切换造型新鲜好玩,可是如果一直切换,会造成审美疲劳,所以当新鲜度增加到10的时候,就停止变换造型,当然了,这里每次循环都会改变xinxiandu的值的.
### 控制执行次数
#### 重复执行多少次
比如同样是执行10次代码,在Scratch中是
![重复执行10次](http://upload-images.jianshu.io/upload_images/1108512-12bdd0d5b8e3e3cc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
在Python中则是
```
from turtle import *
from time import *
for i in range(10):
print('hello!',i)
sleep(0.1)
print('Hmm...')
```
当然实际上Scratch和Python的程序不是对应的,如果想要结果一致,如何修改Scratch程序呢?
#### 重复执行
以上是重复指定的次数,如果是不停的重复呢
举个Scratch的例子:
![重复执行](http://upload-images.jianshu.io/upload_images/1108512-f912ed7b78edb753.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![切换角色造型](http://upload-images.jianshu.io/upload_images/1108512-86b2d81dd09c5a5a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
举个之前的例子:
```
from turtle import *
from time import *
while True:
shape('turtle')
sleep(0.1)
shape('circle')
sleep(0.1)
```
这里用到的就是重复执行循环内部的代码永远不停,如何用Python实现Scratch对应的程序,你动手了吗?
>提示:学习程序,哪怕代码真的很简单,一看就会,也要实际运行一下,其实挺好的
```
while True:
print('__________') # 这里写什么才能跟Scatch程序的结果保持一致呢?
```
### 流程控制
# 单一决策执行结果
这种情况下,只要满足某个条件,就执行某件事,当然这个时间一般不是一成不变的一定会改变某个对象的状态
比如Scratch的例子:
![Scratch](http://upload-images.jianshu.io/upload_images/1108512-ed56b3dc1c7afaf3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
>改进点:鼠标滑过事件,Python turtle没有判断鼠标坐标的函数,o(╯□╰)o
```
if 2 > 3:
print('2 > 3')
if 2 > 3:
print('2 > 3')
else:
print('2 <= 3')
if 2 > 3:
print('2 > 3')
elif 2 == 3:
print('2 = 3')
else:
print('2 < 3')
```
>思考:在Scratch中对应以上代码的代码块是什么?
___________________________________________________________________________________________________________________________________________________
### 创造分身
Scratch中创造分身会用到克隆
![Scratch程序](http://upload-images.jianshu.io/upload_images/1108512-31e6a8fb2fd961ea.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![克隆](http://upload-images.jianshu.io/upload_images/1108512-4a223e0506cee164.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
而Python中也有的
```
from turtle import *
from time import *
for x in range(10):
t = clone()
t.goto(x * 10, 0)
```
比如上面的代码就生成了10个箭头,每个箭头向右移动10个坐标
![复制](http://upload-images.jianshu.io/upload_images/1108512-72100214c9a1b011.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
```
from turtle import *
register_shape('c.gif')
shape('c.gif')
for x in range(10):
t = clone()
t.goto(x * 10, 0)
```
上面这个导入了造型,并移动的可能更加明显一些