Pythonの亀をドラッグで動かしたい

#前提

Pythonの亀をドラッグで動かすだけのハナシ

詳しくは[公式ドキュメントの「タートルグラフィックス」](https://docs.python.org/ja/3/library/turtle.html)を見るといいよ！

#まず亀を表示してみる

shape()で"turtle"指定すれば、🐢が表示されるらしい

[公式ドキュメントの「shape()」](https://docs.python.org/ja/3/library/turtle.html#turtle.shape)

## コード

```python:亀を表示するコード
import turtle

kame = turtle.Turtle()
kame.shape("turtle") 
```
## 実行

マジで🐢が表示された！
![実行時の画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348583/5c0f222b-2bc8-c07d-a54e-211b68979120.png)

# 取り合えず動かしてみる

ondragでgotoを呼べば亀が動くらしい

[公式ドキュメントの「ondrag()」](https://docs.python.org/ja/3/library/turtle.html#turtle.ondrag)
[公式ドキュメントの「goto()」](https://docs.python.org/ja/3/library/turtle.html#turtle.ondrag)

## コード

```python:
import turtle

kame = turtle.Turtle()
kame.shape("turtle") 

kame.ondrag(kame.goto)
```

## 結果

亀がカーソルの移動について行っていない（マウスカーソルを右に回したのに、左回りで動いてる…）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348583/78171982-47f3-8453-f544-99d37d89292a.png)

# 亀には早く動いてもらう

delay()で描画の遅延を無くすよう修正

[公式ドキュメントの「delay()」](https://docs.python.org/ja/3/library/turtle.html#turtle.delay)

## コード
```python
import turtle

kame = turtle.Turtle()
kame.shape("turtle") 

gamen = turtle.Screen()
gamen.delay(0)

kame.ondrag(kame.goto)
```

## 結果

亀が移動中でもお構いなしにondragで移動処理が呼ばれて、めっちゃ不自然に動く…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348583/ec738cf5-11a2-09b6-aebf-03cc16a69a6a.png)

# 亀が寄り道しないようにする

ondragで呼び出した処理が終わるまで、次のondragが呼ばれないよう修正

[公式ドキュメントの「イベントを利用する」](https://docs.python.org/ja/3/library/turtle.html#using-events)

## コード

```python
import turtle

kame = turtle.Turtle()
kame.shape("turtle") 

gamen = turtle.Screen()
gamen.delay(0)

def dragKame(x, y):
    kame.ondrag(None)
    kame.goto(x, y)
    kame.ondrag(dragKame)

kame.ondrag(dragKame)
```

## 結果

かなりそれっぽいけど、カーソル移動が速いとカクカクする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348583/795724d1-1e39-5a68-9c97-9381681ea681.png)

# 亀には滑らかに動いてもらう

ondragで呼び出した処理で、マウスカーソルの座標を貯めておき
ontimerで呼び出した処理で、貯めた座標を参考に亀を移動させるよう修正

[公式ドキュメントの「ontimer()」](https://docs.python.org/ja/3/library/turtle.html#turtle.ontimer)

## コード

```python
import turtle

kame = turtle.Turtle()
kame.shape("turtle") 

gamen = turtle.Screen()
gamen.delay(0)

coordList = []
    
def dragKame(x, y):
    global coordList
    
    coordList.append({'x': x, 'y': y})

def moveKame():
    global coordList
    
    while(len(coordList) > 0):
        coord = coordList.pop(0)
        kame.goto(coord['x'], coord['y'])
        
    gamen.ontimer(moveKame, 0)
 
kame.ondrag(dragKame)
gamen.ontimer(moveKame, 0)
```

## 結果

滑らかに動いた！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348583/499d1aed-c53d-d21a-fdc2-6b5df381fa5a.png)

けどCPU使用率がめっちゃ高い！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348583/51321e99-44ba-9833-b1ba-1e670ecca0ef.png)

# CPUには必要以上に頑張らないようにしてもらう

ドラッグした時にontimerを設定して、ドロップした時にはontimerを解除するよう修正

[公式ドキュメントの「onrelease()」](https://docs.python.org/ja/3/library/turtle.html#turtle.onrelease)

## コード

```python
import turtle

kame = turtle.Turtle()
kame.shape("turtle") 

gamen = turtle.Screen()
gamen.delay(0)

coordList = []
isMove = False
    
def dragKame(x, y):
    global coordList
    global isMove
    
    coordList.append({'x': x, 'y': y})
    
    if not isMove:
        isMove = True
        gamen.ontimer(moveKame, 0)

def dropKame(x, y):
    global isMove
    
    isMove = False

def moveKame():
    global isMove
    global coordList
    
    while(len(coordList) > 0):
        coord = coordList.pop(0)
        kame.goto(coord['x'], coord['y'])
        
    if isMove:
        gamen.ontimer(moveKame, 0)
 
kame.ondrag(dragKame)
kame.onrelease(dropKame)
```

## 結果

（ドラッグしてない間は）CPU使用率が下がった！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348583/b620a151-65f0-044c-c3c0-ee8f1ae638a5.png)

# 感想

ただドラッグで亀を動かしたかっただけなのに、思えば遠くに来たもんだ