Turtleグラフィックス⑤ イベントの処理
イベントの処理
Turtleグラフィックスのイベント処理 の仕組みに関して学習しましょう. キャンバス上でのクリック操作とキー操作を検出し,特定の処理を実行することができます. イベント処理はライブラリに依存するため,汎用的なPythonの文法ではありませんが,その特徴を理解すれば,他のライブラリへの応用も簡単です.
準備
Muエディタを起動したら,Python3 モードを選択しましょう. ツールバーにある「保存」をクリックして,「chapter6.py」という名前でスクリプトを保存します. また,Turtleグラフィックスのライブラリ(モジュール)をインポートしておきましょう.
# Turtleグラフィックスのライブラリをインポート
from turtle import *
クリック・イベント
Turtleグラフィックスでは,クリック・イベントを検出して,特定の処理を実行することができます.
クリック・イベントが発生したときの処理を関数mouse_event(x, y)
として定義します.
このとき,引数のx
とy
は,スクリーン上でクリックされた座標を表します.
ここでは,クリックされた座標に,直径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)
マウスのボタン(左,中央,右)を区別して関数を登録することもできます.
関数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)
例題1
マウスの右ボタンで緑色のドットを描画してください.
キー・イベント
Turtleグラフィックスでは,キー・イベントを検出して,特定の処理を実行することができます.
キーボードの上下左右のカーソル・キー(Right
,Up
,Left
,Down
)を押したときの処理を,それぞれ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()
例題2
キーr
を押すと,スクリーンをリセットするようにしてください.
リセットするにはresetscreen()
を実行します.
タイマー
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後に実行
繰り返しを表現する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()
イベントを組み合わせた描画
タイマーとマウス・イベントを組み合わせて,マウスでクリックした座標を,タートルに追いかけさせてみましょう.
マウスでクリックした座標は グローバル変数 のtarget_x
とtarget_y
に記録します.
- グローバル変数 関数定義の外側で宣言した変数のことで,全ての関数から値を参照することが可能.
- ローカル変数 関数定義の内側で宣言した変数のことで,宣言した関数内から値を参照することが可能(関数の外からは参照できない).
グローバル変数は全ての関数から,代入されている値を参照することができますが,関数内で更新(値を変更)することはできません.
例えば,次の例では,target_x
とtarget_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_x
とtarget_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()
課題
次の課題に取組んでください.
- キー
r
で赤色,キーg
で緑色,キーb
で青色のペンを変更する - キー
space
を押すと原点(0, 0)
をターゲットに設定する
課題を完成させたらスクリプトを保存し,「chapter6.py」を提出してください.