# 從Scratch到Python之角色與造型
>繼續講解通過python turtle從積木編程過渡到代碼編程的技巧.角色是scratch中很重要的主角,每個角色可以更換不同的造型或者音效,堆疊不同的積木.如果把角色比做人,造型就是人物外觀或者動作的變化,比如穿著運動服,打棒球或者走路等不同的造型.接下來我可能會很少截圖,**因為如果你看我文章的時候也跟著做了,那么還需要我截圖么?**
## 新增角色或者造型
Scratch中新增角色或者造型有以下四種方法

* 從角色庫中選擇角色
* 繪制新的角色或者給角色繪制新的造型
* 上傳電腦繪畫作品
* 利用攝像頭拍照
以上四種角色在Python turtle中也是有的
### 從"角色庫中選擇"


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)
```


#### 增加角色
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導入程序,然后運行.這個過程就像是我們單擊
然后倒入圖像一樣的.

### 自行繪制
Python turtle中沒有繪圖編輯器,所以你可以自己在別的軟件中繪制造型,然后保存成gif圖像,當然你也可以利用程序繪制一些圖形作為角色,當然這個就比較復雜了.
### 通過攝像頭拍照
強大的Python當然可以讀取攝像頭數據,然后生成gif圖像,通過對應的庫即可,而且Python強大的功能還可以對數據進行分析和處理,比如進行人臉識別,只把人臉加進來,不適合新手.
## 角色信息

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)
```

## Scratch中的節目介紹于Python turtle對應的實現
因為Python turtle中沒有綠色的旗子所以沒有當綠旗被點擊.
### 偵測鍵盤
Scratch有當按下鍵盤按鍵執行某事,Python turtle對這個的支持是很強大的,比如我們來實現當空格鍵被按的時候,角色向右移動10個單位

```
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()
```
猜測這個程序運行后是什么樣子?
>___________________________________________________________________________________________________________________________________________________________________________________________________________________________

### 多媒體功能
scratch可以偵測音量的大小,當然讀取的是電腦麥克風的音量;計時器的值;和視頻偵測.
不得不承認的是,scratch在這方面封裝的很棒,但也僅止于此了;Python turtle是基于Python開發的,Python在多媒體處理,計算機視覺方面的功能十分強大,配合OpenCVC庫,絕對的神兵利器,但是在這里,作為Python代表的Python turtle不能夠發揮Python的水準,真是虎落平陽被犬欺啊.不過Scratch也是MIT媒體實驗室經過10年的開發猜到現在這個樣子而且主打多媒體故事,游戲以及互動故事的制作,而Python turtle在面向孩子編程方面并沒有關注這方面,因為能夠用Python turtle開發熟練程序的孩子最后去學習正兒八經的Python編程了,不再用積木塊這種小兒科的東西了.
### 切換背景或者當角色被單擊
#### 背景切換

在python turtle中切換背景是很簡單的,需要用到```bgpic()```命令,不過需要圖片是gif格式.
```
from turtle import *
bgpic('b.gif') # 把程序背景切換成b.gif
```

雖然切換背景很容易,但是Python turtle并非像Scratch一樣專門為多媒體而設計所以在這些方面功能有點不足,這樣比對Python對Python turtle是不公平的.不過Python有很多庫可以解決這個問題,比如```pygame```和```pyglet```
>改進點:背景切換以及背景切換偵測事件
#### 當角色被單擊

這個很簡單要用到```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編程書里的設計模式給我留下了深刻的印象.

Python turtle只實現了有限的鼠標,鍵盤和時間事件,自定義事件功能較弱需要完善.
>改進點:事件機制
## 控制模塊
Scratch中的控制模塊實際上對應了編程中的順序,循環和分支三大程序結構,下面我們來一一講解
### 控制等待時間
#### 等待多少秒

在Python涉及到時間的操作需要用到time模塊,所以如果你仔細的話會發現我之前導入了```time```模塊,其中就包含了讓程序等待的```sleep()```命令
```
from turtle import *
from time import *
while True:
shape('turtle')
sleep(0.1)
shape('circle')
sleep(0.1)
```
實現間隔一秒,角色改變造型的動畫.
#### 等待直到條件成立

上面的例子```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中是

在Python中則是
```
from turtle import *
from time import *
for i in range(10):
print('hello!',i)
sleep(0.1)
print('Hmm...')
```
當然實際上Scratch和Python的程序不是對應的,如果想要結果一致,如何修改Scratch程序呢?
#### 重復執行
以上是重復指定的次數,如果是不停的重復呢
舉個Scratch的例子:


舉個之前的例子:
```
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的例子:

>改進點:鼠標滑過事件,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中創造分身會用到克隆


而Python中也有的
```
from turtle import *
from time import *
for x in range(10):
t = clone()
t.goto(x * 10, 0)
```
比如上面的代碼就生成了10個箭頭,每個箭頭向右移動10個坐標

```
from turtle import *
register_shape('c.gif')
shape('c.gif')
for x in range(10):
t = clone()
t.goto(x * 10, 0)
```
上面這個導入了造型,并移動的可能更加明顯一些