Python Turtleでアニメーション!stamp()活用プログラミング例

2025-06-06

turtle.stamp()の動作

  1. 現在の位置にスタンプ
    stamp()が呼び出された時点でのタートルの形と向きが、その位置に複製されて残ります。タートル自体は移動しません。
  2. IDの返却
    stamp()は、作成されたスタンプのID(整数値)を返します。このIDは、後でその特定のスタンプを消去したい場合などに使用できます。
  3. 複数作成可能
    1つのタートルオブジェクトで、異なる位置に何度もstamp()を呼び出すことで、複数のスタンプを作成できます。

なぜturtle.stamp()を使うのか?

  • インタラクティブな要素
    例えば、ユーザーがクリックした場所にマークを残す、ゲームのキャラクターの分身を作る、といったインタラクティブな要素を作成するのに使えます。
  • 描画の高速化
    複雑な形状を繰り返し描画するよりも、一度描画したものをスタンプとして残す方が、処理が速くなる場合があります。
  • オブジェクトの配置
    特定の場所に同じ形のオブジェクトを複数配置したいが、実際にその場所へタートルを移動させて描画する必要がない場合に効率的です。
  • 残像効果
    タートルが移動する軌跡に、そのタートルの形を連続的に残したい場合に便利です。

使用例

import turtle

# 画面とタートルをセットアップ
screen = turtle.Screen()
t = turtle.Turtle()
t.shape("turtle") # タートルの形をカメにする

# タートルの移動とスタンプ
for i in range(10):
    t.forward(50)
    t.stamp() # 現在の位置にタートルの形をスタンプする
    t.right(36) # 少し回転

# 画面を閉じる準備
screen.exitonclick()

上記のコードを実行すると、タートルが前進してはスタンプを押し、少し回転するという動作を10回繰り返します。結果として、タートルの残像が円形に並んだような模様が描かれます。

スタンプの消去

stamp()が返したIDを使って、特定のスタンプを消去することもできます。

import turtle

screen = turtle.Screen()
t = turtle.Turtle()
t.shape("circle") # 形を円にする

# スタンプを押してIDを取得
stamp_id = t.stamp()

# 少し移動
t.forward(100)

# 最初のスタンプを消去
t.clearstamp(stamp_id)

screen.exitonclick()

このコードでは、まず円形のスタンプが押され、その後タートルが移動します。そして、最初に押したスタンプだけがclearstamp()によって消去されます。



タートルが見えない、または期待した場所にスタンプされない

原因

  • 描画が速すぎる
    非常に速いループでスタンプを押している場合、人間の目では個々のスタンプが追いきれないことがあります。
  • タートルが隠されている (t.hideturtle()): タートル自体は存在しますが、非表示になっているため、そのスタンプも非表示に見えることがあります(スタンプ自体は生成されますが、タートルと同じ形で、タートルが非表示であれば見えない可能性が高いです)。
  • タートルの色が背景色と同じ
    タートルの色やスタンプの色が、背景色と同じであるため、視覚的に区別できません。
  • タートルが画面外にいる
    タートルが描画領域の外に移動しているため、スタンプが押されても画面上では確認できません。

トラブルシューティング

  • screen.update() の確認
    もし screen.tracer(0) で自動更新をオフにしている場合、screen.update() を適切なタイミングで呼び出さないと、画面が更新されずスタンプが表示されません。
  • 遅延を入れる
    time.sleep(0.1) (要 import time) をループ内に追加して、描画に意図的な遅延を設けます。これにより、各スタンプの生成が視覚的に確認しやすくなります。
  • タートルを表示する
    t.showturtle() を呼び出して、タートルが確実に表示されるようにします。
  • タートルの色と背景色を確認する
    t.color("red")screen.bgcolor("white") などを使って、明確に区別できる色を設定します。
  • タートルの位置を確認する
    t.pos()t.xcor(), t.ycor() を使って、タートルの現在位置を確認します。必要であれば、t.goto(0, 0) などで中央に戻してみましょう。

スタンプが消えない、または意図しないスタンプが消える

原因

  • clear() や reset() と混同している
    • t.clear() は、そのタートルが描画した線や点をすべて消去しますが、スタンプは消しません
    • t.reset() は、タートルを初期状態に戻し、描画もスタンプもすべて消去しますが、これはそのタートルに関連するすべての要素を対象とします。特定のスタンプだけを消したい場合には向きません。
    • screen.clear() は、画面全体の描画とスタンプをすべて消去します。
  • スタンプを複数回消去しようとしている
    一度消去されたスタンプのIDを再度 clearstamp() に渡しても、何も起こりません(エラーにはなりませんが、効果もありません)。
  • clearstamp() に間違ったIDを渡している
    t.stamp() が返すIDは整数値であり、各スタンプに固有です。異なるスタンプのIDを渡すと、期待とは違うスタンプが消えたり、何も消えなかったりします。

トラブルシューティング

  • 消去したいスタンプのIDを正確に確認する
    デバッグのために、print(stamp_id) などでIDを確認してみるのも良いでしょう。
  • IDの管理を徹底する
    stamp() が返したIDを変数に格納し、そのIDを使って clearstamp() を呼び出すようにします。複数のスタンプを管理する場合は、リストなどにIDを保存するのが一般的です。
    stamp_ids = []
    for _ in range(5):
        t.forward(50)
        stamp_ids.append(t.stamp()) # IDをリストに保存
    
    # 例えば、3番目のスタンプを消す
    if len(stamp_ids) >= 3:
        t.clearstamp(stamp_ids[2]) # リストは0から始まるためインデックスは2
    

AttributeError: 'Turtle' object has no attribute 'stamp'

原因

  • 別のオブジェクトのメソッドを呼び出している
    turtle.stamp() のように、モジュール自体に対してメソッドを呼び出そうとしている(これはタートルオブジェクトのメソッドです)。
  • turtle モジュールが正しくインポートされていない
    import turtle を行っているが、タートルオブジェクトを正しく作成していないか、別の名前でインポートしている可能性があります。

トラブルシューティング

  • 正しいオブジェクトに対してメソッドを呼び出していることを確認する
    t など、作成したタートルインスタンスに対して .stamp() を呼び出すようにします。
  • タートルオブジェクトが作成されていることを確認する
    import turtle
    t = turtle.Turtle() # これが重要
    t.stamp() # tというタートルオブジェクトのメソッドとして呼び出す
    

TypeError: clearstamp() missing 1 required positional argument: 'stampid'

原因

  • clearstamp() メソッドに、消去したいスタンプのIDを渡していない。

トラブルシューティング

  • clearstamp() を呼び出す際には、必ず以前に stamp() が返したIDを引数として渡します。
    stamp_id = t.stamp()
    # ...
    t.clearstamp(stamp_id) # stamp_idを渡す必要がある
    

原因

  • 画面更新の頻度が高い
    screen.tracer() を使わずに、各スタンプ生成のたびに画面全体が更新されると、パフォーマンスが低下します。
  • 大量のスタンプを生成している
    stamp() は画像データを複製するため、数万、数十万といった大量のスタンプを生成すると、メモリ使用量が増加し、描画が非常に遅くなることがあります。
  • 不要なスタンプを消去する
    clearstamp() を使って、画面上から見えなくなった、あるいは役割を終えたスタンプを積極的に消去することで、メモリ使用量を抑えることができます。
  • 不必要なスタンプを生成しない
    本当に必要なスタンプのみを生成するようにコードを見直します。
  • screen.tracer(0) と screen.update() を利用する
    大量の描画を行う場合は、描画を一時的にオフにして、全てのスタンプを生成した後に一度だけ画面を更新することで、パフォーマンスを大幅に改善できます。
    import turtle
    
    screen = turtle.Screen()
    screen.tracer(0) # 自動更新をオフにする
    
    t = turtle.Turtle()
    t.speed(0) # 最高速に設定(描画速度とは異なる)
    
    for i in range(1000): # 例: 1000個のスタンプ
        t.forward(1)
        t.right(1)
        t.stamp()
    
    screen.update() # すべての描画が終わった後に一度だけ画面を更新
    screen.exitonclick()
    


例1: 残像を伴う移動 (基本)

この例では、タートルが移動するたびに、その位置に自身のスタンプを残していきます。

import turtle

# 画面とタートルをセットアップ
screen = turtle.Screen()
screen.setup(width=600, height=600) # 画面サイズを設定
screen.bgcolor("lightblue") # 背景色を設定
screen.title("タートルの残像")

t = turtle.Turtle()
t.shape("turtle") # タートルの形を「カメ」に設定
t.color("green") # タートルの色を緑に設定
t.penup() # ペンを上げて線を描かないようにする (スタンプには影響しない)
t.speed(1) # タートルの移動速度を設定 (遅めにするとスタンプが見やすい)

# タートルを移動させながらスタンプを押す
for _ in range(10):
    t.forward(50) # 50ピクセル前進
    t.stamp()     # 現在の位置にタートルの形をスタンプ
    t.right(36)   # 右に36度回転

# 画面をクリックすると終了
screen.exitonclick()

解説

  • t.speed(1): 速度を遅く設定することで、スタンプが一つずつ押されていく様子がよくわかります。
  • t.penup(): 線を描かずにタートルを移動させたい場合に便利です。stamp() はペンの状態に関わらず、その時点でのタートルの形をコピーします。

例2: スタンプのIDを使った個別の消去

stamp() はスタンプのIDを返します。このIDを使って、後から特定のスタンプだけを消すことができます。

import turtle
import time # 遅延のために使用

screen = turtle.Screen()
screen.setup(width=600, height=600)
screen.bgcolor("lightgray")
screen.title("スタンプの個別消去")

t = turtle.Turtle()
t.shape("circle") # 形を円に設定
t.color("blue")
t.penup()
t.speed(3)

stamp_ids = [] # スタンプのIDを保存するリスト

# 複数のスタンプを押す
for i in range(5):
    t.forward(100)
    # 現在のタートルの色をスタンプごとに変えてみる
    if i % 2 == 0:
        t.color("red")
    else:
        t.color("blue")
    
    id = t.stamp() # スタンプを押し、IDを取得
    stamp_ids.append(id) # IDをリストに追加
    t.backward(100) # 元の位置に戻る
    t.right(72) # 回転

# 少し待つ
time.sleep(1)

# リストの真ん中のスタンプを消す
if len(stamp_ids) >= 3:
    print(f"ID {stamp_ids[2]} のスタンプを消去します。")
    t.clearstamp(stamp_ids[2]) # リストの3番目のスタンプ(インデックス2)を消去

# さらに少し待つ
time.sleep(1)

# 最初と最後のスタンプを消す
if len(stamp_ids) >= 1:
    print(f"ID {stamp_ids[0]} のスタンプを消去します。")
    t.clearstamp(stamp_ids[0]) # 最初のスタンプを消去
if len(stamp_ids) >= 5: # 5つあることを確認
    print(f"ID {stamp_ids[4]} のスタンプを消去します。")
    t.clearstamp(stamp_ids[4]) # 最後のスタンプを消去

screen.exitonclick()

解説

  • t.clearstamp(stamp_id): 指定されたIDを持つスタンプを消去します。
  • stamp_ids.append(id): stamp() が返したIDをリストに保存しておくと、後からそれらのスタンプを個別に操作できます。

例3: tracer() を使った高速描画と大量のスタンプ

import turtle

screen = turtle.Screen()
screen.setup(width=800, height=800)
screen.bgcolor("black") # 背景を黒に設定
screen.title("高速スタンプ描画")

t = turtle.Turtle()
t.shape("triangle") # 形を三角形に設定
t.color("white") # 色を白に設定
t.penup()
t.speed(0) # 最高速に設定 (tracerと組み合わせることで効果を発揮)

# 自動更新をオフにする (非常に重要!)
screen.tracer(0) 

# 大量のスタンプを生成
for i in range(500): # 500個のスタンプ
    t.goto(0, 0) # 中央に戻る
    t.setheading(i * 0.7) # 角度を少しずつ変える
    t.forward(i) # 前進距離を少しずつ増やす
    t.stamp()

# 画面を更新してすべてのスタンプを表示
screen.update()

screen.exitonclick()

解説

  • t.speed(0): tracer() を使う場合、タートルの速度設定は描画速度には影響しませんが、計算速度に影響する可能性があります。0は最高速を意味します。
  • screen.update(): tracer(0) を呼び出した後、描画の完了時にこのメソッドを呼び出すことで、それまでに蓄積されたすべての描画を一括して画面に表示します。これにより、スムーズで高速なアニメーションや描画が可能になります。
  • screen.tracer(0): この行が非常に重要です。これを呼び出すと、タートルグラフィックスは自動的な画面更新を行わなくなります。すべての描画コマンドは内部的に実行されますが、画面には表示されません。

スタンプとランダムな位置・向きを組み合わせて、星空のようなものを描いてみましょう。

import turtle
import random

screen = turtle.Screen()
screen.setup(width=800, height=600)
screen.bgcolor("darkblue") # 暗い青を背景に
screen.title("星空")

t = turtle.Turtle()
t.shape("star") # カスタムシェイプを登録して星形にする
t.color("yellow")
t.penup()
t.speed(0)

# 星の形を登録 (Turtleモジュールにはデフォルトで"star"シェイプはないため、作成)
# ここでは簡易的に、正五角形を描画して、その中心に向かう線で星を表現
# 実際にはもっと複雑なカスタムシェイプも可能です
screen.register_shape("star", ((0, 20), (5, 5), (20, 5), (10, -5), (15, -20), (0, -10), (-15, -20), (-10, -5), (-20, 5), (-5, 5)))

# 自動更新をオフにする
screen.tracer(0)

# 多数の星をランダムな位置に配置
for _ in range(100):
    x = random.randint(-screen.window_width() // 2 + 20, screen.window_width() // 2 - 20)
    y = random.randint(-screen.window_height() // 2 + 20, screen.window_height() // 2 - 20)
    t.goto(x, y) # ランダムな位置へ移動
    t.setheading(random.randint(0, 359)) # ランダムな向きに設定
    t.stamp() # スタンプ

# 画面を更新
screen.update()

screen.exitonclick()
  • random.randint(): random モジュールを使って、タートルの位置や向きをランダムに決定しています。
  • screen.register_shape("star", ...): turtle モジュールにはデフォルトで「星」の形は用意されていません。register_shape() を使うことで、座標のリストを使ってオリジナルの形を登録できます。この例では簡易的な星形を作成しています。


turtle.stamp() は「タートルの形状をその場に複製して残す」機能ですが、これに似た効果は他の描画メソッドでも実現できます。

turtle.dot() / turtle.circle() / turtle.write() など、直接描画するメソッド


ランダムな位置に点を描画する

import turtle
import random

screen = turtle.Screen()
screen.setup(width=600, height=400)
screen.bgcolor("black")
screen.title("点を描画する代替")

t = turtle.Turtle()
t.penup() # ペンを上げて線を描かないようにする
t.hideturtle() # タートル自体は表示しない (描画は可能)
t.speed(0)

screen.tracer(0) # 高速化のため自動更新をオフ

for _ in range(100):
    x = random.randint(-280, 280)
    y = random.randint(-180, 180)
    t.goto(x, y)

    # ランダムな色とサイズの点を描画
    dot_color = (random.random(), random.random(), random.random()) # RGB値をランダム生成
    dot_size = random.randint(5, 20)
    t.dot(dot_size, dot_color) # サイズと色を指定して点を描画

screen.update()
screen.exitonclick()

利点

  • 軽量性
    シンプルな図形(点など)であれば、stamp() よりも処理が軽い場合があります。
  • 制御
    サイズや色を直接指定して描画できます。
  • 柔軟性
    タートルの形状に依存せず、多様な形状(点、円、正方形、テキストなど)を描画できます。

欠点

  • 描画されたオブジェクトを個別に消去する clearstamp() のような直接的なメソッドはありません(undo()clear() を使うか、画面全体をクリアする必要があります)。
  • stamp() のようにタートル自身の複雑なカスタム形状をそのまま残すことはできません。

別のタートルオブジェクトを作成して配置する


複数の独立したタートルを配置し、一つだけ動かす

import turtle
import time

screen = turtle.Screen()
screen.setup(width=600, height=400)
screen.bgcolor("white")
screen.title("複数のタートルオブジェクト")

# 中央にタートルを配置
t1 = turtle.Turtle()
t1.shape("turtle")
t1.color("green")
t1.penup()
t1.goto(-100, 0)
t1.stamp() # 残したい場合はスタンプも使える

# もう一つのタートルを配置
t2 = turtle.Turtle()
t2.shape("arrow")
t2.color("blue")
t2.penup()
t2.goto(100, 0)
t2.stamp()

# 別のタートルを作成し、動かすタートルとして使用
mover = turtle.Turtle()
mover.shape("triangle")
mover.color("red")
mover.penup()
mover.goto(0, -50)
mover.speed(1)

# mover タートルを動かす
for _ in range(5):
    mover.forward(20)
    mover.left(90)
    time.sleep(0.5) # 少し待つ

screen.exitonclick()

利点

  • 複雑な動き
    それぞれのタートルに異なるアニメーションや振る舞いをさせることができます。
  • 独立した操作性
    各「スタンプ」が個別のタートルオブジェクトであるため、後から個別に移動、回転、色変更、形状変更など、タートルオブジェクトの全機能を使って操作できます。

欠点

  • 大量の「スタンプ」が必要な場合は、stamp() よりもコードが複雑になる傾向があります。
  • タートルオブジェクトの数が増えるほど、メモリ使用量が増加し、パフォーマンスに影響を与える可能性があります。

カスタムシェイプを描画する関数を定義する


星を描画する関数を定義する

import turtle
import random

screen = turtle.Screen()
screen.setup(width=600, height=400)
screen.bgcolor("darkblue")
screen.title("カスタム描画関数")

t = turtle.Turtle()
t.hideturtle() # タートル自体は表示しない
t.penup()
t.speed(0)

screen.tracer(0)

# 星を描画する関数を定義
def draw_star(tur, x, y, size, color):
    tur.goto(x, y)
    tur.dot(5, "white") # 中心に点を打つ (任意)
    tur.color(color)
    tur.pendown()
    tur.begin_fill() # 塗りつぶしを開始
    for _ in range(5):
        tur.forward(size)
        tur.right(144) # 星の角を形成する角度
    tur.end_fill() # 塗りつぶしを終了
    tur.penup()

# ランダムな位置に星を描画
for _ in range(50):
    x = random.randint(-280, 280)
    y = random.randint(-180, 180)
    size = random.randint(10, 40)
    star_color = (random.random(), random.random(), random.random()) # ランダムな色
    draw_star(t, x, y, size, star_color)

screen.update()
screen.exitonclick()

利点

  • メモリ効率
    stamp() のように内部的に画像を複製するわけではないため、非常に複雑な形状でない限り、メモリ効率が良い場合があります。
  • 再利用性
    一度定義した描画関数は、何度も呼び出して異なるパラメータで利用できます。
  • 高度なカスタマイズ性
    描画する形状、サイズ、色、向きなどを関数内で完全に制御できます。
  • 描画されたオブジェクトを個別に消去する直接的な方法はありません。
  • 描画ロジックを自分で書く必要があるため、手間がかかります。
代替方法特徴適したケース
turtle.dot() / turtle.circle() などタートルが指定された位置に直接図形(点、円など)を描画します。タートルの形状は関係ありません。汎用的な図形を配置したい場合、タートルの形状に縛られたくない場合。
別のタートルオブジェクトを作成各々が独立した機能を持つ複数のタートルを作成し、それぞれを配置します。後から個別に操作(移動、回転など)できます。独立した動きや振る舞いを持つ「スタンプ」が必要な場合、複雑なインタラクション。
カスタム描画関数を定義任意の複雑な図形を描画するための関数を自分で作成します。関数内で描画ロジックを完全に制御できます。独自の複雑な形状を繰り返し描画したい場合、描画の細部を完全に制御したい場合。