turtle.update()

2025-06-06

通常、タートルグラフィックスでは、タートルが移動したり、図形を描画したりするたびに、画面が自動的に更新されます。しかし、大量の描画処理を一度に行う場合や、複雑なアニメーションを作成する場合には、自動更新の頻度が多すぎると、描画がカクカクしたり、処理速度が遅くなったりすることがあります。

ここでturtle.update()の出番です。

turtle.update()の主な機能と使い方

    • turtle.tracer(0)を呼び出すことで、自動画面更新を一時的に停止します。
    • この状態でタートルによる描画処理(例: forward(), left(), circle()など)を複数回実行します。
    • すべての描画処理が終わった後にturtle.update()を呼び出すと、それまでに行われたすべての描画が一度に画面に反映されます。これにより、描画処理の途中で画面が更新されないため、非常に高速な描画が可能になります。
  1. アニメーションの制御

    • turtle.tracer(0)で自動更新を停止した状態で、タートルを少しずつ動かし、その都度turtle.update()を呼び出すことで、フレームバイフレームのアニメーションを作成できます。これにより、アニメーションの滑らかさをより細かく制御できます。

使用例

import turtle

screen = turtle.Screen()
screen.setup(width=600, height=600)
screen.tracer(0)  # 自動画面更新を停止

t = turtle.Turtle()
t.speed(0) # 描画速度を最速に設定(tracer(0)を使っている場合はあまり意味がないが、念のため)

# 100個の正方形を描画
for i in range(100):
    t.forward(i * 2)
    t.right(90)

screen.update()  # 描画を一度に更新
screen.exitonclick()


turtle.update()に関連するよくあるエラーとトラブルシューティング

    • 原因1: turtle.update()を呼び出していない turtle.tracer(0)を使って自動更新を停止した場合、描画した内容はメモリ上には存在しますが、画面には表示されません。turtle.update()を呼び出すことで、初めて画面に反映されます。

      • 対処法
        すべての描画処理が完了した後に、必ずscreen.update()(またはturtle.update())を呼び出してください。
      import turtle
      screen = turtle.Screen()
      screen.tracer(0) # 自動更新停止
      
      # 描画処理
      t = turtle.Turtle()
      t.forward(100)
      t.right(90)
      t.forward(100)
      
      screen.update() # これがないと表示されない
      screen.exitonclick()
      
    • 原因2: プログラムがすぐに終了してしまう(ウィンドウがすぐ閉じる) 特にスクリプトとして実行した場合、描画が完了した瞬間にプログラムが終了し、タートルグラフィックスのウィンドウがすぐに閉じてしまうことがあります。

      • 対処法
        • プログラムの最後にturtle.done()またはscreen.mainloop()を追加します。これにより、ウィンドウが閉じられるまでプログラムが待機します。
        • 簡単な確認であれば、input()を最後に追加して、Enterキーが押されるまで待機させることも可能です。
      import turtle
      screen = turtle.Screen()
      screen.tracer(0)
      
      t = turtle.Turtle()
      t.forward(100)
      screen.update()
      
      screen.mainloop() # または turtle.done() または input()
      
    • 原因3: turtle.tracer()の引数に問題がある turtle.tracer()screen.tracer()と同義で、引数にndelayを取ります。nは画面更新を行うコマンドの回数、delayは更新間の遅延時間です。tracer(0)は自動更新を完全に停止しますが、tracer(1)(デフォルト)は毎コマンド更新、tracer(N)はNコマンドごとに更新します。誤った引数を指定すると、更新が期待通りに行われないことがあります。

      • 対処法
        tracer(0)を使用して手動更新に切り替える場合は、引数を正しく0に設定します。
  1. アニメーションがカクカクする、または遅い

    • 原因1: turtle.update()の呼び出し頻度が高すぎる turtle.tracer(0)で自動更新を停止しているにも関わらず、ループ内でturtle.update()を頻繁に呼び出しすぎると、かえって処理が遅くなることがあります。update()は画面全体を再描画するため、毎回呼び出すのは非効率です。

      • 対処法
        大量の描画処理を行う場合や、アニメーションの各フレームで画面を更新したい場合は、turtle.update()は1フレームにつき1回だけ呼び出すようにします。各描画コマンドの間に呼び出すのは避けるべきです。
      import turtle
      import time
      
      screen = turtle.Screen()
      screen.tracer(0) # 自動更新停止
      
      t = turtle.Turtle()
      t.speed(0)
      
      for _ in range(360):
          t.forward(1)
          t.left(1)
          # screen.update() # ここで毎回呼ぶと遅くなる
      
      screen.update() # 全ての描画が終わってから一度だけ更新
      screen.exitonclick()
      
    • 原因2: time.sleep()の使用 time.sleep()はプログラム全体を一時停止させるため、アニメーションの滑らかさを損なうことがあります。特にscreen.tracer(0)を使用している場合、sleep中に描画が行われないため、画面がフリーズしたように見えます。

      • 対処法
        アニメーションの速度調整にはscreen.ontimer()を使用します。これは指定したミリ秒後に特定の関数を呼び出すため、プログラムの実行をブロックしません。
      import turtle
      
      screen = turtle.Screen()
      screen.tracer(0)
      
      t = turtle.Turtle()
      t.shape("turtle")
      
      def animate():
          t.forward(5)
          t.left(2)
          screen.update() # 各フレームで更新
          screen.ontimer(animate, 20) # 20ミリ秒後に再度animateを呼び出す
      
      animate() # アニメーション開始
      screen.mainloop()
      
  2. screen.update()turtle.update()の混同

    • 原因
      update()メソッドはturtle.Screenオブジェクトに属します。turtle.Turtleオブジェクトにはupdate()メソッドはありません。turtle.update()のようにモジュールレベルで呼び出す場合、それは内部的に現在のスクリーンオブジェクトのupdate()を呼び出しています。しかし、明示的にスクリーンオブジェクトを作成している場合は、そのオブジェクトのメソッドとして呼び出す方が明確で推奨されます。
      • 対処法
        • screen = turtle.Screen()のようにScreenオブジェクトを作成している場合は、screen.update()を使用してください。
        • turtle.update()は、複数のスクリーンを扱わない限り、動作はしますが、慣例としてscreen.update()を使うのが良いでしょう。
  3. 複数のタートルでの問題

    • 原因
      screen.tracer(0)は画面全体の自動更新を停止します。複数のタートルが存在する場合でも、screen.update()を一度呼び出すと、すべてのタートルの描画が同時に反映されます。しかし、特定のタートルだけを動かして表示したいといった細かい制御は難しくなります。
      • 対処法
        基本的にはscreen.tracer(0)screen.update()は画面全体の描画制御に使用します。特定のタートルだけを個別にアニメーションさせる場合は、ontimerと各タートルの描画コマンドを組み合わせて、フレームごとに画面を更新するようにロジックを組む必要があります。
  4. turtle.done()screen.mainloop()がプログラムの最後にない

    • 原因
      これらがないと、Pythonスクリプトは実行が完了するとすぐに終了してしまい、タートルグラフィックスのウィンドウが表示されなかったり、一瞬だけ表示されて消えたりします。
      • 対処法
        プログラムの最後に必ずscreen.mainloop()(またはturtle.done())を配置してください。これにより、ユーザーがウィンドウを閉じるまでプログラムが待機します。
  • 公式ドキュメントを参照する
    turtleモジュールの公式ドキュメントは、機能の詳細や正しい使い方を知るための最も信頼できる情報源です。
  • printデバッグ
    描画処理の前後にprint()文を挿入して、プログラムの実行フローや変数の状態を確認します。
  • コードをシンプルにする
    問題が複雑な場合は、関連する部分だけを抜き出して最小限のコードで再現を試みてください。これにより、問題の原因を特定しやすくなります。
  • エラーメッセージを読む
    Pythonがエラーを発生させた場合、そのメッセージは問題解決の重要な手がかりになります。NameErrorAttributeErrorTypeErrorなどを確認し、何が問題なのかを理解しようと努めてください。


例1: 大量の描画を高速化する

import turtle

# スクリーンオブジェクトを作成
screen = turtle.Screen()
screen.setup(width=600, height=600)
screen.title("高速描画の例")

# 自動画面更新を停止する (重要!)
# これにより、描画コマンドが実行されてもすぐに画面に表示されず、メモリ上で描画が行われる
screen.tracer(0)

# タートルオブジェクトを作成
t = turtle.Turtle()
t.speed(0) # 描画速度を最速に設定(tracer(0)を使っている場合はあまり意味がないが、念のため)
t.hideturtle() # タートルを非表示にする(描画完了まで見えない方がスムーズ)

print("描画を開始します。")

# 多数の正方形を描画
# 通常であれば、一つずつ描画される様子が見えるため、非常に時間がかかる
for i in range(200):
    t.penup() # ペンを上げて移動
    t.goto(i - 200, i - 200) # 開始位置をずらす
    t.pendown() # ペンを下ろす

    for _ in range(4): # 正方形を描画
        t.forward(i * 2)
        t.right(90)

print("描画コマンドが完了しました。")

# これまでの描画を一度に画面に反映する
# この行が実行されるまで、画面には何も表示されない
screen.update()

print("画面を更新しました。ウィンドウをクリックして終了してください。")

# ウィンドウが閉じられるまでプログラムを待機させる
screen.exitonclick()

解説

  • screen.exitonclick(): ウィンドウが閉じられるまでプログラムを待機させます。
  • forループ内の描画処理: ここで200個の正方形を描画しています。tracer(0)がなければ、200回画面が更新されるため、非常にカクカクしたアニメーションに見えるか、処理が遅くなります。
  • screen.tracer(0): これがこの例の鍵です。画面の自動更新を完全に停止します。これにより、タートルがいくら描画しても画面は更新されません。

例2: スムーズなアニメーション(フレームバイフレーム)

turtle.update()screen.ontimer()を組み合わせて、滑らかなアニメーションを作成します。time.sleep()を使うとプログラム全体がフリーズして見えますが、ontimerはイベントループ内で動作するため、より良いアニメーションが可能です。

import turtle

screen = turtle.Screen()
screen.setup(width=600, height=600)
screen.title("スムーズなアニメーションの例")
screen.bgcolor("lightblue")

screen.tracer(0) # 自動更新を停止

t = turtle.Turtle()
t.shape("turtle") # タートルの形をカメにする
t.color("green")
t.penup() # 最初はペンを上げておく
t.goto(-250, 0) # 左端に移動
t.pendown() # ペンを下ろす
t.speed(0) # アニメーション速度とは関係ないが、念のため最速に

animation_speed_ms = 20 # アニメーションのフレーム間隔(ミリ秒)

def animate_turtle():
    """タートルを動かし、画面を更新する関数"""
    t.forward(5) # 少し前進

    # 画面の端に到達したら向きを変える
    if t.xcor() > 250 or t.xcor() < -250:
        t.left(180) # 180度向きを変える

    screen.update() # 描画を更新(1フレーム表示)

    # 指定時間後にこの関数を再度呼び出す
    # これにより、アニメーションがループする
    screen.ontimer(animate_turtle, animation_speed_ms)

print("アニメーションを開始します。")
animate_turtle() # 最初のフレームを呼び出してアニメーション開始

# ウィンドウが閉じられるまでプログラムを待機させる
screen.mainloop() # または turtle.done()

解説

  • screen.mainloop(): ontimerが動作するために必要です。イベントループを開始し、イベントが発生するのを待ちます(この場合はタイマーイベント)。
  • animate_turtle()関数:
    • タートルを少し動かします。
    • screen.update(): ここで1フレーム分の描画を更新します。これにより、タートルの動きが段階的にではなく、滑らかに見えます。
    • screen.ontimer(animate_turtle, animation_speed_ms): これが重要です。指定されたミリ秒数(animation_speed_ms)後に、animate_turtle関数を再度呼び出すようにスケジュールします。これにより、無限ループにならずに、イベントドリブンでアニメーションが進行します。
  • screen.tracer(0): やはり自動更新を停止します。

tracer(0)で完全に停止した後でも、必要に応じて部分的に更新を表示したい場合にupdate()を使用できます。

import turtle
import time

screen = turtle.Screen()
screen.setup(width=600, height=600)
screen.title("部分的な更新の例")
screen.bgcolor("lightgray")

screen.tracer(0) # 自動更新を停止

t = turtle.Turtle()
t.speed(0)
t.hideturtle()
t.penup()
t.goto(-280, 0)
t.pendown()

print("長い線を描画中...")
for _ in range(500):
    t.forward(1)
    t.right(0.1) # 少しずつ向きを変える
    
    # 100ステップごとに一度更新を表示する
    if _ % 100 == 0:
        screen.update() # ここで部分的に描画を更新
        # time.sleep(0.1) # 必要であれば少し待機(カクカクする原因になる可能性あり)

print("最終描画を更新します。")
screen.update() # 最終的な描画を更新

screen.exitonclick()
  • 最後のscreen.update(): 全ての描画が完了した後に、最終的な状態を表示するために再度呼び出します。
  • if _ % 100 == 0:: 100回描画するごとに、screen.update()を呼び出しています。これにより、長い描画処理の途中経過を、フリーズしているように見せずに確認できます。完全にスムーズなアニメーションではないですが、処理が止まっているわけではないことを示せます。
  • screen.tracer(0): 自動更新を停止。


    • 説明
      これがタートルグラフィックスのデフォルトの挙動です。tracer()を呼び出さない場合、またはscreen.tracer(1)1は省略可能)を設定した場合、タートルが描画コマンドを実行するたびに画面が自動的に更新されます。つまり、update()を明示的に呼び出す必要はありません。
    • 利点
      • 最もシンプルで、コード量が少ない。
      • 初心者にとっては、描画がどのように進んでいるかを視覚的に追いやすい。
    • 欠点
      • 大量の描画処理を行う場合、画面更新の頻度が高すぎて処理が非常に遅くなる。
      • アニメーションがカクカクして見えることがある(特に複雑な描画や短い時間間隔で多くの動きがある場合)。
    • 使用例
      import turtle
      
      screen = turtle.Screen()
      screen.setup(width=400, height=300)
      screen.title("デフォルトの自動更新")
      
      # screen.tracer(1) はデフォルトなので、この行は省略可能
      # screen.tracer(1)
      
      t = turtle.Turtle()
      t.speed(1) # 描画速度を遅くして、自動更新の様子を確認
      
      for _ in range(4):
          t.forward(100)
          t.left(90)
      
      # update() は不要
      screen.exitonclick()
      
    • どのような場合に使うか
      • 描画する図形が少ない場合。
      • 処理速度がそこまで重要でない場合。
      • タートルの動きを追跡したい場合(デバッグや学習目的)。
  1. screen.tracer(n) (n > 1 の場合)

    • 説明
      screen.tracer(n)nに1より大きい整数を指定すると、タートルはn個の描画コマンドを実行するごとに画面を一度更新します。これは、tracer(0)update()の中間的な方法と言えます。
    • 利点
      • デフォルトの自動更新よりも高速。
      • 完全に更新を停止するtracer(0)よりも、途中の進行状況が見えやすい。
    • 欠点
      • nの値によっては、依然としてカクカクすることがある。
      • 最適なnの値を見つけるのが難しい場合がある。
    • 使用例
      import turtle
      
      screen = turtle.Screen()
      screen.setup(width=600, height=600)
      screen.title("Nコマンドごとの更新")
      
      # 50個の描画コマンドごとに画面を更新
      screen.tracer(50) 
      
      t = turtle.Turtle()
      t.speed(0) # 描画速度は最速にしておく
      
      for i in range(500):
          t.forward(i * 0.5)
          t.left(89)
      
      # 最後に残った描画を確実に表示するために update() を呼ぶと良い場合もあるが、
      # tracer(N) は基本的に自動で最後まで更新してくれる
      # screen.update() 
      
      screen.exitonclick()
      
    • どのような場合に使うか
      • 高速化したいが、完全に描画が隠れるのは避けたい場合。
      • 特に、大量の短い描画ステップを繰り返し行う場合に有効。
方法説明利点欠点推奨される用途
screen.tracer(0) + screen.update()自動更新を完全に停止し、必要な時に手動で一括更新。最も高速、滑らかなアニメーション制御。update()を呼び忘れると何も表示されない。大量の描画、複雑なアニメーション、パフォーマンスが重要な場合。 (update()の主要な使い方)
デフォルト (screen.tracer(1))描画コマンドごとに自動更新。シンプル、コード量が少ない、学習目的。遅い、カクカクしやすい。少量の描画、タートルの動きを追跡したい場合、初心者向け。
screen.tracer(n) (n > 1)n個の描画コマンドごとに自動更新。デフォルトより高速、途中経過が見える。最適なnを見つけるのが難しい場合がある、tracer(0)よりは遅い。ある程度の高速化が必要だが、完全に描画が隠れるのは避けたい場合。
screen.delay() / turtle.speed()描画更新の遅延時間やタートルの速度を制御。描画を意図的に遅くできる。描画メカニズムそのものを制御するものではない、パフォーマンス改善には不向き。ごく簡単なデモンストレーションで、描画速度を調整したい場合。(ほとんどの場合、tracer(0)ontimerを使うべき)