【Python】turtle.Shapeで描画をカスタマイズ!オリジナル形状の作り方
タートルグラフィックスとは?
まず、turtle
モジュールは「タートルグラフィックス」と呼ばれる描画システムを提供します。これは、画面上に仮想的な「亀(タートル)」がいて、その亀を動かすことで線を描いたり、図形を作成したりするものです。まるで、ペンを持った亀が紙の上を歩き回り、足跡で絵を描くようなイメージです。
turtle.Shape
の役割
このタートルグラフィックスにおいて、turtle.Shape
は以下のことを行います。
-
タートルの見た目を設定する: デフォルトでは、タートルは小さな矢印のような形をしています。しかし、
turtle.shape()
メソッドを使うことで、この見た目を変更することができます。利用可能な組み込みの形状
turtle
モジュールには、あらかじめいくつかの形状が用意されています。"arrow"
(矢印)"turtle"
(亀)"circle"
(円)"square"
(四角形)"triangle"
(三角形)"classic"
(クラシックな矢印、デフォルト)
import turtle my_turtle = turtle.Turtle() my_turtle.shape("turtle") # タートルの形を「亀」にする my_turtle.forward(100) turtle.done() # 描画ウィンドウを閉じないようにする
-
カスタム形状を登録する: 組み込みの形状だけでなく、自分で定義した形状(多角形など)をタートルに適用することも可能です。これは
turtle.register_shape()
という関数を使って行います。これは少し高度な使い方になりますが、より複雑な描画やアニメーションを作る際に役立ちます。
- デバッグや学習: タートルの形状を変えることで、プログラムの実行中にタートルの位置や向きを把握しやすくなり、デバッグや学習に役立ちます。
- 表現の豊かさ: 描画される図形だけでなく、描画主体であるタートル自体の見た目を変えることで、プログラムの表現力を高めることができます。
- 視覚的なわかりやすさ: タートルがどのような動きをしているのか、どの方向を向いているのかを視覚的に理解しやすくします。特に、初めてプログラミングを学ぶ人にとって、抽象的な概念を直感的に捉えるのに役立ちます。
turtle.Shape
はタートルの見た目を扱う機能ですが、いくつかの一般的な間違いや予期せぬ挙動に遭遇することがあります。
エラー:TurtleGraphicsError: There is no shape named "xxxxx" (または類似のエラー)
原因
turtle.shape()
メソッドに、存在しない形状名(タイプミス、または未登録のカスタム形状名)を渡した場合に発生します。
例
import turtle
my_turtle = turtle.Turtle()
my_turtle.shape("turle") # "turtle" のタイプミス
turtle.done()
トラブルシューティング
-
カスタム形状の登録を確認する
もしカスタム形状を使っている場合、turtle.register_shape()
を使ってその形状が正しく登録されているか確認してください。登録前にmy_turtle.shape()
を呼び出すとこのエラーが発生します。import turtle # このコードが実行される前に register_shape() が必要 # 例: # turtle.register_shape("my_star", ((0,10), (5,-5), (-5,-5))) my_turtle = turtle.Turtle() my_turtle.shape("my_star") # "my_star" が登録されていないとエラー turtle.done()
-
スペルミスを確認する
組み込みの形状名("arrow"
,"turtle"
,"circle"
,"square"
,"triangle"
,"classic"
)のスペルが正しいか再確認してください。
エラー:AttributeError: 'module' object has no attribute 'shape' (または類似のエラー)
原因
turtle
オブジェクト(例: my_turtle = turtle.Turtle()
で作成したインスタンス)ではなく、turtle
モジュール自体に対してshape()
を呼び出そうとした場合に発生します。shape()
メソッドは、特定のタートルインスタンスに属するものです。
例
import turtle
# turtle.shape("turtle") # これは間違い!モジュール全体に適用できない
my_turtle = turtle.Turtle()
my_turtle.shape("turtle") # 正しい
turtle.done()
トラブルシューティング
shape()
メソッドは、turtle.Turtle()
で作成したタートルオブジェクトのインスタンスに対して呼び出すようにしてください。
タートルの形状が変わらない(または、形状変更が反映されない)
原因
- 形状が小さすぎて見えない
タートルが非常に小さく設定されている場合、形状が変わっても視認しにくいことがあります。 - 別のタートルを操作している
複数のタートルインスタンスがある場合、意図しないタートルの形状を変更している可能性があります。 - 描画の更新がされていない
特にインタラクティブな環境や、複雑なアニメーションを作成している場合、画面の更新が間に合っていない可能性があります。
トラブルシューティング
-
タートルのサイズを確認する
t.shapesize(stretch_wid=None, stretch_len=None, outline=None)
を使って、タートルのサイズを一時的に大きくしてみてください。形状が変わっているのに小さくて見えなかっただけかもしれません。import turtle my_turtle = turtle.Turtle() my_turtle.shape("turtle") my_turtle.shapesize(stretch_wid=3, stretch_len=3) # タートルを大きくする turtle.done()
-
正しいタートルオブジェクトを操作しているか確認する
複数のタートルを扱っている場合、形状を変更したいタートルインスタンスが正しいか、変数名などをよく確認してください。 -
screen.update()またはturtle.update()を使用する (アニメーションの場合)
もしtracer(0)
などを使って自動更新をオフにしている場合、形状変更後にscreen.update()
(またはturtle.update()
)を呼び出すことで、画面を強制的に更新できます。import turtle screen = turtle.Screen() screen.tracer(0) # 自動更新をオフにする my_turtle = turtle.Turtle() my_turtle.shape("circle") my_turtle.goto(-50, 0) my_turtle.shape("square") # この時点では画面は更新されない my_turtle.goto(50, 0) screen.update() # ここで画面が更新され、両方の形状が見える turtle.done()
カスタム形状が期待通りに表示されない(特に登録後)
原因
register_shape()
に渡す座標リストが間違っているか、多角形が閉じていない(最後の点が最初の点と同じでない)ため、うまく描画されないことがあります。また、形状の原点(タートルの中心)がどこになるかを意識していないと、期待した位置に表示されないことがあります。
トラブルシューティング
- 原点を考慮する
register_shape()
で登録する形状の座標は、タートルの描画原点(通常は中央)を基準にしています。形状の中心がタートルの中心に来るように座標を調整する必要がある場合があります。 - 簡単な形状から試す
まずは正方形や三角形など、簡単な多角形でカスタム形状の登録と表示を試してみてください。 - 座標リストを確認する
渡した座標(タプルまたはリストのリスト)が正しいか、そして多角形として閉じているか(最後の点が最初の点と同じである必要はないが、意図した形になっているか)を確認してください。
turtle.Shape
は、タートルの見た目を変更したり、カスタム形状を定義したりするために使われます。
組み込みの形状を使用する (.shape() メソッド)
最も基本的な使用例です。turtle
モジュールに予め用意されている形状に変更します。
コード例
import turtle
# 画面のセットアップ
screen = turtle.Screen()
screen.setup(width=600, height=400)
screen.bgcolor("lightgray") # 背景色を設定
# タートルを作成
my_turtle = turtle.Turtle()
my_turtle.speed(1) # 速度を遅くして変化を見やすくする
my_turtle.penup() # 線を描かずに移動
# 各形状を試す
# 矢印 (デフォルト)
my_turtle.goto(-200, 100)
my_turtle.shape("arrow")
my_turtle.write("Arrow", align="center", font=("Arial", 12, "normal"))
# 亀
my_turtle.goto(-100, 100)
my_turtle.shape("turtle")
my_turtle.write("Turtle", align="center", font=("Arial", 12, "normal"))
# 円
my_turtle.goto(0, 100)
my_turtle.shape("circle")
my_turtle.write("Circle", align="center", font=("Arial", 12, "normal"))
# 四角形
my_turtle.goto(100, 100)
my_turtle.shape("square")
my_turtle.write("Square", align="center", font=("Arial", 12, "normal"))
# 三角形
my_turtle.goto(200, 100)
my_turtle.shape("triangle")
my_turtle.write("Triangle", align="center", font=("Arial", 12, "normal"))
# クラシック (古いバージョンのデフォルト矢印)
my_turtle.goto(-150, -50)
my_turtle.shape("classic")
my_turtle.write("Classic", align="center", font=("Arial", 12, "normal"))
my_turtle.goto(0, -150)
my_turtle.pendown() # 線を描き始める
my_turtle.pencolor("blue") # ペンの色
my_turtle.shapesize(2) # 形状のサイズを2倍にする
my_turtle.forward(100) # 描画テスト
my_turtle.stamp() # 現在の位置に形状のスタンプを押す
# ウィンドウを閉じるまで待機
turtle.done()
解説
my_turtle.stamp()
: 現在のタートルの形状と色で、その場に「スタンプ」を押すことができます。これは、形状自体が移動するのではなく、その形状の絵を残したい場合に便利です。my_turtle.shapesize(stretch_wid=val, stretch_len=val)
: タートルの形状の縦横の伸縮率を変更できます。ここでは単純にサイズを2倍にしています。my_turtle.write()
: 各形状の下に名前を表示しています。my_turtle.shape("shape_name")
: これが形状を変更する主要なメソッドです。括弧内に組み込みの形状名を文字列で指定します。my_turtle = turtle.Turtle()
: タートルオブジェクトを作成します。screen.setup()
とscreen.bgcolor()
: 描画するキャンバスのサイズと背景色を設定します。
カスタム形状を登録して使用する (turtle.register_shape())
自分で定義した多角形をタートルの形状として登録し、使用することができます。
コード例
import turtle
screen = turtle.Screen()
screen.setup(width=600, height=400)
screen.bgcolor("lightblue")
# 1. 星形のカスタム形状を定義する
# 各点はタートルの中心(0,0)からの相対座標
star_shape_coords = [
(0, 50),
(15, 15),
(50, 15),
(25, -5),
(35, -40),
(0, -20),
(-35, -40),
(-25, -5),
(-50, 15),
(-15, 15)
]
# 形状を登録する
turtle.register_shape("star", star_shape_coords)
# タートルを作成し、カスタム形状を適用
star_turtle = turtle.Turtle()
star_turtle.shape("star") # 登録した名前で形状を設定
star_turtle.color("gold", "darkorange") # ペン色と塗りつぶし色
star_turtle.shapesize(1.5) # 少し大きくする
star_turtle.speed(3)
# 星形タートルを動かして描画
star_turtle.penup()
star_turtle.goto(-100, 0)
star_turtle.pendown()
for _ in range(36):
star_turtle.forward(10)
star_turtle.right(10)
star_turtle.penup()
star_turtle.goto(150, 0)
star_turtle.write("My Custom Star!", align="center", font=("Arial", 16, "bold"))
# 2. 矢印と塗りつぶしを使ってより複雑なカスタム形状(例:家)を定義する
# この方法は、多角形の座標だけでは表現しにくい複雑な形状に適しています。
# この場合、Shapeクラスを直接操作します。
def create_house_shape():
house_polygon = turtle.Shape("compound") # 複数の部分からなる形状
# 壁
wall_coords = ((-30, 0), (30, 0), (30, 40), (-30, 40))
house_polygon.addcomponent(wall_coords, "brown", "saddlebrown") # 座標, ペン色, 塗りつぶし色
# 屋根
roof_coords = ((-40, 40), (40, 40), (0, 70))
house_polygon.addcomponent(roof_coords, "darkred", "firebrick")
# ドア
door_coords = ((-10, 0), (10, 0), (10, 20), (-10, 20))
house_polygon.addcomponent(door_coords, "black", "gray")
turtle.register_shape("house", house_polygon)
create_house_shape() # 形状を登録
house_turtle = turtle.Turtle()
house_turtle.shape("house") # 登録した形状を適用
house_turtle.penup()
house_turtle.goto(-100, -100)
house_turtle.shapesize(0.8) # 少し小さく表示
turtle.done()
解説
- 複合形状の登録 (高度な例)
create_house_shape()
関数の中では、turtle.Shape("compound")
を使って複数のサブコンポーネント(壁、屋根、ドア)からなる複雑な形状を作成しています。house_polygon.addcomponent(coords, pencolor, fillcolor)
: 複合形状に新しいパーツを追加します。各パーツは独自の座標、ペン色、塗りつぶし色を持つことができます。- この方法は、単一の多角形では表現できないような、より複雑な画像をタートルの形状として使いたい場合に非常に強力です。
star_turtle.shape("star")
: 登録した"star"
形状をタートルに適用します。turtle.register_shape("star", star_shape_coords)
:"star"
という名前で、star_shape_coords
で定義された多角形を新しい形状として登録します。star_shape_coords
: 星形を構成する点の座標をリストで定義しています。各タプルは(x, y)
座標を表し、タートルの中心(0,0)からの相対的な位置です。
描画をアニメーション化し、形状のスタンプを連続して押す
タートルの形状を使い、動かしながらその軌跡にスタンプを押すことで、簡単にパターンやアニメーションを作成できます。
コード例
import turtle
import time # 時間を制御するためにインポート
screen = turtle.Screen()
screen.setup(width=700, height=700)
screen.bgcolor("white")
screen.tracer(0) # 描画をオフにして高速化 (後で手動更新)
# 複数のタートルを作成
main_turtle = turtle.Turtle()
main_turtle.shape("circle") # 円形のスタンプ
main_turtle.color("blue")
main_turtle.penup()
main_turtle.speed(0) # 最速
stamp_turtle = turtle.Turtle()
stamp_turtle.shape("square") # 四角形のスタンプ
stamp_turtle.color("red")
stamp_turtle.penup()
stamp_turtle.speed(0) # 最速
# スタンプを押しながら円を描く
main_turtle.goto(0, -200)
main_turtle.pendown()
main_turtle.speed(5)
main_turtle.pencolor("green")
for i in range(360):
main_turtle.forward(1)
main_turtle.left(1)
if i % 10 == 0: # 10度ごとに円形のスタンプを押す
main_turtle.stamp()
# 別のタートルで螺旋状にスタンプ
stamp_turtle.goto(0, 0)
length = 5
for i in range(100):
stamp_turtle.forward(length)
stamp_turtle.right(90)
stamp_turtle.stamp() # 四角形のスタンプを押す
length += 2 # 次に進む距離を長くする
screen.update() # 描画を一度に更新して表示
# キー入力で終了
screen.onkey(turtle.bye, "q") # qキーで終了
screen.listen() # キーイベントを監視
turtle.done()
screen.onkey(turtle.bye, "q")
とscreen.listen()
: ウィンドウを閉じるためのイベントハンドラを設定しています。q
キーを押すとプログラムが終了します。my_turtle.stamp()
: タートルの現在の位置と向きで、その形状と色のスタンプを押します。タートル自体は移動せず、そのコピーが残ります。screen.tracer(0)
とscreen.update()
: これらはアニメーションをスムーズに見せるための重要なテクニックです。screen.tracer(0)
: 自動描画更新をオフにします。これにより、タートルが動くたびに画面が再描画されるのを防ぎ、処理が高速になります。screen.update()
:tracer(0)
を設定した場合、描画の変更を手動で画面に反映させるために必要です。すべての描画処理が終わった後に一度だけ呼び出すことで、一瞬で描画結果が表示されます。
turtle.Shape
はタートルの形状を管理するのに便利ですが、場合によっては別の方法でタートルの見た目を制御したり、独自の図形を描画したりすることも可能です。
shapesize() メソッドによる形状の拡大・縮小・歪ませる
turtle.Shape
で設定した既存の形状(組み込み形状やカスタム形状)のサイズを調整するのに使います。shape()
とは異なり、形状の種類自体は変えませんが、その見た目を変化させることができます。
turtle.shapesize(stretch_wid=None, stretch_len=None, outline=None)
stretch_wid
: 縦方向の拡大率(デフォルトの1に対する比率)。stretch_len
: 横方向の拡大率。outline
: 形状の枠線の太さ(ピクセル単位)。
コード例
import turtle
screen = turtle.Screen()
screen.setup(width=600, height=400)
screen.bgcolor("white")
my_turtle = turtle.Turtle()
my_turtle.shape("arrow") # まずは矢印形状を設定
my_turtle.color("blue")
my_turtle.penup()
# 通常サイズ
my_turtle.goto(-150, 50)
my_turtle.stamp()
my_turtle.write("Default Size", align="center", font=("Arial", 10, "normal"))
# 2倍のサイズ
my_turtle.goto(-50, 50)
my_turtle.shapesize(2, 2) # 縦横ともに2倍
my_turtle.stamp()
my_turtle.write("2x Size", align="center", font=("Arial", 10, "normal"))
# 横長に歪ませる
my_turtle.goto(50, 50)
my_turtle.shapesize(1, 3) # 縦1倍、横3倍
my_turtle.stamp()
my_turtle.write("Stretched Horizontally", align="center", font=("Arial", 10, "normal"))
# 縦長に歪ませる
my_turtle.goto(150, 50)
my_turtle.shapesize(3, 1) # 縦3倍、横1倍
my_turtle.stamp()
my_turtle.write("Stretched Vertically", align="center", font=("Arial", 10, "normal"))
# 枠線の太さを変更
my_turtle.goto(0, -100)
my_turtle.shapesize(2, 2, 5) # 2倍サイズ、枠線5px
my_turtle.color("red", "pink") # ペン色と塗りつぶし色
my_turtle.stamp()
my_turtle.write("Thick Outline", align="center", font=("Arial", 10, "normal"))
turtle.done()
解説
shapesize()
は、shape()
で設定された形状が既にある前提で、その見た目をより細かく調整したい場合に非常に有効です。特にアニメーションでオブジェクトが伸縮するような表現に使えます。
dot() メソッドによる単純な点(円)の描画
タートル自身の形状ではなく、タートルの現在位置に単純な点(円)を描画したい場合に便利です。タートル自体は非表示のまま、点を描画し続けることができます。
turtle.dot(size=None, color=None)
size
: 点の直径(ピクセル単位)。指定しない場合はペンの太さに依存します。color
: 点の色。
コード例
import turtle
screen = turtle.Screen()
screen.setup(width=600, height=400)
screen.bgcolor("lightyellow")
my_turtle = turtle.Turtle()
my_turtle.hideturtle() # タートル自身を非表示にする
my_turtle.speed(0) # 最速
my_turtle.penup() # 線を描かずに移動
# 様々なサイズの点を描画
my_turtle.goto(-200, 50)
my_turtle.dot(20, "red")
my_turtle.write("20px Red Dot", align="center", font=("Arial", 10, "normal"))
my_turtle.goto(-100, 50)
my_turtle.dot(40, "green")
my_turtle.write("40px Green Dot", align="center", font=("Arial", 10, "normal"))
my_turtle.goto(0, 50)
my_turtle.dot(60, "blue")
my_turtle.write("60px Blue Dot", align="center", font=("Arial", 10, "normal"))
# ランダムな位置に点を描画
import random
for _ in range(50):
x = random.randint(-280, 280)
y = random.randint(-180, -50)
my_turtle.goto(x, y)
my_turtle.dot(random.randint(5, 15), random.choice(["purple", "orange", "cyan"]))
turtle.done()
解説
dot()
は、タートルの形状を制御するのではなく、タートルが「スタンプ」として置く印を制御する方法です。シンプルな図形(粒子、星など)を多数描画するのに適しています。hideturtle()
と組み合わせることで、描画の主体であるタートルが見えない状態で点をプロットできます。
タートルを非表示にし、直接描画コマンドを使う
タートル自体の見た目を一切使わず、単に描画の「ペン」として利用する方法です。タートルは描画位置と向きの制御にのみ使い、線や塗りつぶしは通常のforward()
, circle()
, begin_fill()
, end_fill()
などのコマンドで描画します。
コード例
import turtle
screen = turtle.Screen()
screen.setup(width=600, height=400)
screen.bgcolor("lightgray")
my_pen = turtle.Turtle()
my_pen.hideturtle() # タートルを非表示にする
my_pen.speed(0) # 最速
# 正方形を描画
my_pen.penup()
my_pen.goto(-150, 50)
my_pen.pendown()
my_pen.pencolor("black")
my_pen.fillcolor("lightblue")
my_pen.begin_fill()
for _ in range(4):
my_pen.forward(100)
my_pen.right(90)
my_pen.end_fill()
# 円を描画
my_pen.penup()
my_pen.goto(100, 50)
my_pen.pendown()
my_pen.pencolor("darkgreen")
my_pen.fillcolor("lightgreen")
my_pen.begin_fill()
my_pen.circle(50) # 半径50の円
my_pen.end_fill()
# 星形を直接描画 (塗りつぶし付き)
my_pen.penup()
my_pen.goto(0, -100)
my_pen.pendown()
my_pen.pencolor("darkblue")
my_pen.fillcolor("skyblue")
my_pen.begin_fill()
for i in range(5):
my_pen.forward(100)
my_pen.right(144) # 星の角度
my_pen.end_fill()
turtle.done()
解説
この方法は、タートルの形状自体が描画の邪魔になる場合や、完全にカスタムな図形をプログラムで直接描きたい場合に有効です。タートルは単に移動と回転の「カーソル」として機能し、実際の描画はforward()
, circle()
, begin_fill()
/ end_fill()
などのメソッドで行います。