Turtleグラフィックス⑤ イベントの処理

Image from Gyazo

イベントの処理

Turtleグラフィックスのイベント処理 の仕組みに関して学習しましょう. キャンバス上でのクリック操作とキー操作を検出し,特定の処理を実行することができます. イベント処理はライブラリに依存するため,汎用的なPythonの文法ではありませんが,その特徴を理解すれば,他のライブラリへの応用も簡単です.

準備

Muエディタを起動したら,Python3 モードを選択しましょう. ツールバーにある「保存」をクリックして,「chapter6.py」という名前でスクリプトを保存します. また,Turtleグラフィックスのライブラリ(モジュール)をインポートしておきましょう.

# Turtleグラフィックスのライブラリをインポート
from turtle import *

クリック・イベント

Turtleグラフィックスでは,クリック・イベントを検出して,特定の処理を実行することができます.

クリック・イベントが発生したときの処理を関数mouse_event(x, y)として定義します. このとき,引数のxyは,スクリーン上でクリックされた座標を表します. ここでは,クリックされた座標に,直径10のドット(点)を描画します. この関数mouse_event(x, y)を,関数onscreenclick()に引数として渡します. これで,クリック・イベントが発生したときに,自動的に関数mouse_event(x,y)が呼び出されます.

# クリックが発生したときの処理
def mouse_event(x, y):
    penup()
    goto(x, y)
    pendown()
    dot(10)

# 関数を登録
onscreenclick(mouse_event)

Image from Gyazo

マウスのボタン(左,中央,右)を区別して関数を登録することもできます. 関数onscreenclick()の第2引数として,左ボタンは1,中央ボタンは2,右ボタンは3を設定します. ここでは,左ボタンなら赤色のドット,中央ボタンなら青色のドットを描画します.

# 左ボタンの処理
def mouse_left(x, y):
    penup()
    goto(x, y)
    pendown()
    color("red")
    dot(10)

# 中央ボタンの処理
def mouse_center(x, y):
    penup()
    goto(x, y)
    pendown()
    color("blue")
    dot(10)

# 左ボタンのクリックに関数を登録
onscreenclick(mouse_left, 1)

# 中央ボタンのクリックに関数を登録(トラックパッドの場合は2本指でタップ)
onscreenclick(mouse_center, 2)

Image from Gyazo

例題1

マウスの右ボタンで緑色のドットを描画してください.

キー・イベント

Turtleグラフィックスでは,キー・イベントを検出して,特定の処理を実行することができます.

キーボードの上下左右のカーソル・キー(RightUpLeftDown)を押したときの処理を,それぞれright()up()left()down()として定義します. カーソル・キーの方向に,setheading()でタートルの進行方向を設定し,20だけ前進させます. これらの関数を,関数onkeypress()に引数として渡します. これで,キー・イベントが発生したときに,自動的にright()up()left()down()が呼び出されます. 最後にlisten()を実行する必要があることに注意してください.

def right():
    setheading(0)
    forward(20)

def up():
    setheading(90)
    forward(20)

def left():
    setheading(180)
    forward(20)

def down():
    setheading(270)
    forward(20)

onkeypress(right, "Right")
onkeypress(up, "Up")
onkeypress(left, "Left")
onkeypress(down, "Down")
listen()

Image from Gyazo

例題2

キーrを押すと,スクリーンをリセットするようにしてください. リセットするにはresetscreen()を実行します.

Image from Gyazo

タイマー

Turtleグラフィックスでは,タイマーを設定して,一定時刻後に特定の処理を実行することができます.

一定時刻後に実行する処理を関数random_move()として定義します. randint(0, 359)で0から359までの乱数を生成ます. この乱数をタートルの向きに設定し,100だけ前進します. この関数random_move()を,関数ontimer()に引数として渡します. ontimer()の第2引数はタイマーの時間(単位はミリ秒)であり, ここでは2秒(2000ms)後に設定しています.

from random import *

def random_move():
    angle = randint(0, 359) # ランダムに角度を設定
    setheading(angle)
    forward(100)

ontimer(random_move, 2000) # 2000ms後に実行

Image from Gyazo

繰り返しを表現するfor文の代わりにタイマーを用いることが可能です. 次のようにrandom_move()の内部で,タイマーを利用して,再帰的にrandom_move()を呼び出します. この結果,2秒ごとに繰り返して,random_move()が実行されることになります.

from random import *

def random_move():
    angle = randint(0, 359) # ランダムに角度を設定
    setheading(angle)
    forward(100)
    ontimer(random_move, 2000) # 2000ms後に実行

random_move()

Image from Gyazo

イベントを組み合わせた描画

タイマーとマウス・イベントを組み合わせて,マウスでクリックした座標を,タートルに追いかけさせてみましょう. マウスでクリックした座標は グローバル変数target_xtarget_yに記録します.

グローバル変数は全ての関数から,代入されている値を参照することができますが,関数内で更新(値を変更)することはできません. 例えば,次の例では,target_xtarget_yは,関数setTarget()の内側で値を更新していますが,関数の外では更新されていません.

# グローバル変数(ターゲットの座標)
target_x = 0
target_y = 0

# ターゲットの更新
def setTarget(x, y):
    target_x = x
    target_y = y

setTarget(3, 5)
print(f"target_x={target_x} target_y={target_y}") # 更新されていない

関数内でglobalを用いて対象のグローバル変数を指定することで,更新が可能になります. ここでは,setTarget()の内部で,globalを指定することで,マウスのクリックした座標を,ターゲット座標のtarget_xtarget_yに更新しています. また,chase()で,タートルから見たターゲットの方向をtowards()で算出し,20だけ前進させます. このとき,タートルとターゲットの距離をdistance()で算出し,距離が20より大きいときだけ前進させることにします. 距離が20以下のときは,setposition()で,ターゲットと同じ位置にタートルを移動させます. このchase()を200msごとに再帰的に呼び出すことで,タートルは繰り返しターゲットを追いかけます.

# グローバル変数(ターゲットの座標)
target_x = 0
target_y = 0

# ターゲットの更新
def setTarget(x, y):
    global target_x, target_y # グローバル変数を指定
    target_x = x
    target_y = y

onscreenclick(setTarget)

# ターゲットを追いかける
def chase():

    # ターゲットまでの距離が20より大きいとき
    if(distance(target_x, target_y) > 20):
        angle = towards(target_x, target_y) # 目的方向の角度を算出
        setheading(angle)
        forward(20)
    else:
        goto(target_x, target_y) # ターゲットに移動

    ontimer(chase, 200) # 200msごとにchase()を再帰的に呼び出す

chase()

Image from Gyazo

課題

次の課題に取組んでください.

Image from Gyazo

課題を完成させたらスクリプトを保存し,「chapter6.py」を提出してください.

参考書籍

愛知県名古屋市にある椙山女学園大学 文化情報学部 向研究室の公式サイトです. 専門は情報科学であり,人工知能やデータベースなどの技術要素を指導しています. この公式サイトでは,授業で使用している教材を公開すると共に, ベールに包まれた女子大教員のミステリアスな日常を4コマ漫画でお伝えしていきます. サイトに関するご意見やご質問はFacebookまたはTwitterでお問い合わせください.