Python Turtle: begin_poly()で図形を自由自在に!カスタムシェイプ作成術
turtle.begin_poly()
は、Pythonの turtle
モジュールで使用される関数です。この関数は、タートル(亀)が描く線分の頂点を記録し始めるために使われます。
より具体的に説明すると、以下のようになります。
- 多角形の記録開始:
begin_poly()
を呼び出すと、タートルが次に移動する際に、その位置が多角形の頂点として記録され始めます。 - 頂点の追加:
begin_poly()
を呼び出した後、タートルをforward()
やleft()
などのコマンドで移動させると、その移動によって通過した点が自動的に多角形の頂点として追加されていきます。 - 記録の終了: 多角形の記録を終了するには、
turtle.end_poly()
を呼び出します。 - 多角形の取得:
end_poly()
を呼び出した後、turtle.get_poly()
を使うことで、記録された多角形の頂点のリスト(座標のタプル)を取得できます。
何のために使うのか?
この機能は、主に以下のような場面で役立ちます。
- 描画されたパスの保存: タートルが描いた線の経路を後で再利用したり、解析したりする場合に、その頂点情報を簡単に取得することができます。
- カスタムシェイプ(形状)の定義:
turtle
モジュールには、あらかじめいくつかの形状(円、正方形など)が用意されていますが、begin_poly()
を使えば、自由に複雑な形状を定義し、それをタートルの新しい形状として登録することができます。例えば、星形や家の形など、独自の図形をタートルに割り当てて描画させることができます。
import turtle
# タートルオブジェクトを作成
t = turtle.Turtle()
# 多角形の記録を開始
t.begin_poly()
# 複数の線分を描画
t.forward(100)
t.left(90)
t.forward(50)
t.left(90)
t.forward(100)
t.left(90)
t.forward(50)
# 多角形の記録を終了
t.end_poly()
# 記録された多角形の頂点を取得
my_polygon = t.get_poly()
print("記録された多角形の頂点:", my_polygon)
# 記録された多角形をシェイプとして登録し、使用する
turtle.addshape("my_custom_shape", my_polygon)
t.shape("my_custom_shape")
# 画面を閉じるまで待機
turtle.done()
begin_poly() と end_poly() のペア忘れ
最もよくある間違いは、begin_poly()
を呼び出したのに対応する end_poly()
を呼び忘れることです。
- トラブルシューティング:
- 必ず
t.begin_poly()
を呼び出したら、多角形の記録を終える部分でt.end_poly()
を呼び出しているか確認してください。これらの呼び出しは常にペアである必要があります。
- 必ず
- エラーの症状:
- 多角形が正しく記録されない(
get_poly()
が空のリストを返すなど)。 - 期待通りの形状にならない。
- 場合によっては、エラーメッセージが表示されないまま、意図しない動作になることがあります。
- 多角形が正しく記録されない(
get_poly() の呼び出し忘れまたはタイミングの問題
begin_poly()
と end_poly()
の間でタートルを移動させた後、その記録された多角形の頂点を使用するには、get_poly()
を呼び出す必要があります。
- トラブルシューティング:
t.end_poly()
の後にt.get_poly()
を呼び出しているか確認してください。begin_poly()
とend_poly()
の間に呼び出しても、その時点までの記録しか得られません。
- エラーの症状:
- 多角形の情報が取得できない(
my_polygon
変数が空になるなど)。 - カスタムシェイプを登録しようとしても、空の形状が登録される。
- 多角形の情報が取得できない(
多角形の描画中にタートルを非表示にする
多角形を記録している最中に t.hideturtle()
などを呼び出しても、多角形の記録自体には影響しませんが、視覚的に何が起こっているか分かりにくくなります。
- トラブルシューティング:
- 多角形を記録する際は、タートルを表示したままにして、線が描かれていることを確認するとデバッグがしやすくなります。
- 描画の最後に
turtle.done()
やturtle.mainloop()
を呼び出して、描画ウィンドウがすぐに閉じないようにすることも重要です。
- 問題の症状:
- コードが正しく動いているはずなのに、何も表示されないように見える。
turtle.addshape() での誤った使用
get_poly()
で得られた頂点リストを turtle.addshape()
に渡す際に、引数を間違えることがあります。
- トラブルシューティング:
turtle.addshape()
の第一引数にはシェイプの名前(文字列)、第二引数にはt.get_poly()
で得られた頂点リスト(タプルのリスト)を渡す必要があります。- 例:
turtle.addshape("my_custom_shape", my_polygon)
- エラーの症状:
TypeError: addshape() takes 2 positional arguments but 3 were given
のようなエラー。- カスタムシェイプが正しく適用されない。
_tkinter モジュールが見つからない
turtle
モジュールは内部的に tkinter
というGUIライブラリを使用しています。Pythonのインストールによっては、tkinter
が含まれていない場合があります。
- トラブルシューティング:
- お使いのPython環境に
tkinter
がインストールされているか確認してください。多くの場合、Pythonの標準インストールに含まれていますが、一部のLinuxディストリビューションなどでは別途インストールが必要な場合があります(例:sudo apt-get install python3-tk
)。
- お使いのPython環境に
- エラーの症状:
ModuleNotFoundError: No module named '_tkinter'
turtle
をインポートしようとするとエラーが発生する。
プログラムのファイル名を turtle.py
にしてしまうと、Pythonが標準ライブラリの turtle
モジュールではなく、自分の作成した turtle.py
をインポートしようとしてしまい、問題が発生します。
- トラブルシューティング:
- Pythonの標準モジュールと同じ名前(
turtle.py
など)でファイルを保存しないようにしてください。例えばmy_turtle_drawing.py
のように、ユニークな名前にします。
- Pythonの標準モジュールと同じ名前(
- エラーの症状:
AttributeError: partially initialized module 'turtle' has no attribute 'Turtle'
のようなエラー。turtle
モジュールの関数が正しく動作しない。
例1:単純な多角形の記録と表示
この最も基本的な例では、begin_poly()
と end_poly()
を使ってシンプルな四角形を記録し、その頂点情報を表示します。
import turtle
# タートルオブジェクトを作成
t = turtle.Turtle()
t.speed(1) # 描画速度を少し遅くして確認しやすくする
print("--- 例1: 単純な多角形の記録と表示 ---")
# 多角形の記録を開始
t.begin_poly()
print("多角形の記録を開始しました。")
# 四角形を描画しながら頂点を記録
t.forward(100)
t.left(90)
t.forward(50)
t.left(90)
t.forward(100)
t.left(90)
t.forward(50)
# 多角形の記録を終了
t.end_poly()
print("多角形の記録を終了しました。")
# 記録された多角形の頂点を取得
# get_poly() は、記録された頂点の座標のタプル(x, y)のリストを返します。
my_polygon_vertices = t.get_poly()
print("記録された多角形の頂点:", my_polygon_vertices)
# 画面を閉じるまで待機
turtle.done()
解説
t.get_poly()
を使うと、記録されたすべての頂点のリスト(各頂点は(x座標, y座標)
のタプル)を取得できます。この例では、長方形の4つの頂点とその開始点がリストに含まれるはずです。t.end_poly()
で記録が停止します。- その後、
t.forward()
やt.left()
でタートルを動かすたびに、現在のタートルの位置が多角形の頂点リストに追加されます。 t.begin_poly()
を呼び出すことで、タートルが移動する軌跡が頂点として記録され始めます。
例2:カスタムシェイプの作成と適用
この例では、begin_poly()
で独自の形状(ここでは星形)を定義し、それをタートルの新しい「シェイプ」として登録して使用します。
import turtle
# タートルオブジェクトを作成
t = turtle.Turtle()
t.speed(0) # 最速で描画
print("\n--- 例2: カスタムシェイプの作成と適用 ---")
# 星形を定義するための多角形の記録を開始
t.begin_poly()
print("星形シェイプの記録を開始しました。")
# 星形を描画(ここでは簡易的な星形、実際にはもっと複雑にできます)
for i in range(5): # 5つの角を持つ星
t.forward(100)
t.right(144) # 星の角度
# 多角形の記録を終了
t.end_poly()
print("星形シェイプの記録を終了しました。")
# 記録された多角形の頂点を取得
star_vertices = t.get_poly()
print("星形の頂点データ:", star_vertices)
# 取得した頂点データを使って新しいシェイプを登録
# turtle.addshape(シェイプ名, 頂点データ)
turtle.addshape("star_shape", star_vertices)
print("カスタムシェイプ 'star_shape' を登録しました。")
# タートルの形状を新しいカスタムシェイプに変更
t.shape("star_shape")
# シェイプの色を設定(塗りつぶし色)
t.color("gold")
t.fillcolor("gold")
# タートルを少し移動させて、登録されたシェイプを表示
t.penup()
t.goto(-50, 0)
t.pendown()
# 画面を閉じるまで待機
turtle.done()
解説
t.shape("star_shape")
で、タートルのアイコンがこの新しく定義した星形に変わります。これにより、タートル自身がこの形状で描画されるようになります。turtle.addshape("star_shape", star_vertices)
を使うことで、取得した頂点リストを「star_shape」という名前の新しいタートルシェイプとして登録します。star_vertices = t.get_poly()
で、この星形の頂点リストを取得します。begin_poly()
とend_poly()
の間で星形を描画します。このときのタートルの移動軌跡が星形の輪郭になります。
複数の異なるカスタムシェイプを定義し、プログラム内でそれらを切り替えて使用する例です。
import turtle
screen = turtle.Screen()
screen.setup(width=600, height=400)
t = turtle.Turtle()
t.speed(0)
t.penup() # 描画しないようにペンを上げる
print("\n--- 例3: 複数のカスタムシェイプの定義と利用 ---")
# --- 三角形のシェイプを定義 ---
t.goto(-200, 0) # 描画開始位置へ移動(見えない位置でもOK)
t.begin_poly()
t.forward(100)
t.left(120)
t.forward(100)
t.left(120)
t.forward(100)
t.end_poly()
triangle_vertices = t.get_poly()
turtle.addshape("triangle_shape", triangle_vertices)
print("カスタムシェイプ 'triangle_shape' を登録しました。")
# --- 家の形のシェイプを定義 ---
t.goto(0, 0) # 描画開始位置へ移動
t.begin_poly()
# 土台
t.forward(80)
t.left(90)
t.forward(60)
t.left(90)
t.forward(80)
t.left(90)
t.forward(60)
t.left(90)
# 屋根
t.forward(80)
t.left(90)
t.forward(60)
t.right(150) # 屋根の斜め部分1
t.forward(40)
t.right(60) # 屋根の頂点
t.forward(40)
t.right(150) # 屋根の斜め部分2
t.forward(60)
t.end_poly()
house_vertices = t.get_poly()
turtle.addshape("house_shape", house_vertices)
print("カスタムシェイプ 'house_shape' を登録しました。")
# --- 定義したシェイプを使ってタートルを表示 ---
# 三角形のタートル
t_triangle = turtle.Turtle()
t_triangle.shape("triangle_shape")
t_triangle.color("blue")
t_triangle.shapesize(2) # サイズを大きくする
t_triangle.penup()
t_triangle.goto(-150, -50)
t_triangle.stamp() # タートルをスタンプ
# 家の形のタートル
t_house = turtle.Turtle()
t_house.shape("house_shape")
t_house.color("brown")
t_house.shapesize(1.5)
t_house.penup()
t_house.goto(100, -50)
t_house.stamp() # タートルをスタンプ
# 元のタートルはデフォルトの形状に戻す
t.shape("turtle")
t.goto(0, 100)
t.pendown()
t.write("カスタムシェイプの例", align="center", font=("Arial", 16, "normal"))
# 画面を閉じるまで待機
turtle.done()
t.penup()
は、形状を記録する際に線が描画されるのを避けるためによく使われます。これにより、純粋に形状の定義のみを行い、後でその形状を適用したタートルを描画させることができます。- 登録されたシェイプは、新しく作成したタートルオブジェクト (
t_triangle
,t_house
) にt.shape()
メソッドで適用し、画面上にスタンプ (stamp()
) しています。これにより、同じ画面上に異なるカスタムシェイプのオブジェクトを配置できます。 - 収集した各頂点データは、それぞれ異なる名前 (
"triangle_shape"
,"house_shape"
) でturtle.addshape()
を使って登録されます。 - この例では、
t.begin_poly()
とt.end_poly()
のブロックを複数回使用して、異なる形状(三角形と家)の頂点データを収集しています。
begin_poly()
はタートルの「移動経路」を記録してシェイプを作るための強力なツールですが、それ以外にもさまざまなアプローチがあります。
Screen.addshape() を直接使用する
これは begin_poly()
の最も直接的な代替方法であり、多くの場合、より制御しやすい方法です。Screen.addshape()
メソッドは、名前と形状を定義するタプルのリストを直接受け取ります。
-
欠点: 頂点座標を手動で計算または特定する必要があるため、直感的な「描いて記録する」方法ではない。
-
利点: 座標が明確で、計算や外部データとの連携が容易。複雑なアルゴリズムで形状を生成する場合に適している。
-
使用例:
import turtle screen = turtle.Screen() # 四角形の頂点座標を直接定義 # 各要素は (x, y) のタプル square_shape_coords = [(-50, -50), (50, -50), (50, 50), (-50, 50)] # "my_square" という名前で新しいシェイプを登録 screen.addshape("my_square", turtle.Shape("polygon", square_shape_coords)) # または、より簡潔に: # screen.addshape("my_square_simple", square_shape_coords) t = turtle.Turtle() t.shape("my_square") # 定義したシェイプを適用 t.color("blue") t.penup() t.goto(-100, 0) t.stamp() # 星形を直接定義 star_points = [] size = 50 for i in range(5): star_points.append( (size * (0.809 * (i*2)*360/5/360 - 0.309* ((i*2)*360/5/360)), size * (0.588 * (i*2)*360/5/360 + 0.951* ((i*2)*360/5/360))) ) star_points.append( (size * (0.309 * ((i*2+1)*360/5/360) + 0.951* ((i*2+1)*360/5/360)), size * (0.951 * ((i*2+1)*360/5/360) - 0.309* ((i*2+1)*360/5/360))) ) # もっとシンプルな星形の例 (頂点を手で計算) # star_points_simple = [ # (0, 50), (14.6, 18.0), (47.5, 15.5), (23.8, -5.9), (29.4, -42.8), # (0, -20.0), (-29.4, -42.8), (-23.8, -5.9), (-47.5, 15.5), (-14.6, 18.0) # ] screen.addshape("my_star", star_points) # 直接リストを渡せる star_t = turtle.Turtle() star_t.shape("my_star") star_t.color("red") star_t.goto(100, 0) star_t.stamp() turtle.done()
-
特徴:
- タートルを動かして描画する必要がなく、頂点座標を直接指定できる。
- 外部ファイルから座標データを読み込んで形状を生成する場合に非常に便利。
- よりプログラマティックにシェイプを定義できる。
Screen.register_shape() と GIF/画像ファイル
turtle
モジュールは、GIF画像ファイルをタートルの形状として使用することをサポートしています。
-
欠点: 外部ファイル(GIF)が必要。Pythonコード内で直接形状を定義するわけではない。
-
利点: 非常に自由度が高く、視覚的に魅力的なシェイプを簡単に作成できる。
-
使用例:
import turtle screen = turtle.Screen() screen.setup(width=600, height=400) # 事前に 'my_image.gif' というGIF画像ファイルを用意しておく必要があります # 例: 以下のような内容のGIFファイル # - 飛行機、車、キャラクターなどの画像 # - サイズは小さめ(例: 50x50 ピクセル程度) try: screen.addshape("my_custom_image", "my_image.gif") # 画像ファイルを指定 except turtle.TurtleGraphicsError: print("エラー: 'my_image.gif' が見つからないか、有効なGIFファイルではありません。") print("作業ディレクトリに適切なGIFファイルを配置してください。") turtle.done() exit() t = turtle.Turtle() t.shape("my_custom_image") t.penup() t.goto(-100, 0) t.stamp() t2 = turtle.Turtle() t2.shape("my_custom_image") t2.color("green") # 画像の色は変わりませんが、ペンやスタンプの色として使われます t2.goto(100, 0) t2.stamp() turtle.done()
-
特徴:
- タートルで描画するよりも、はるかに複雑で詳細な画像をシェイプとして使用できる。
- デザインツールで作成した画像を利用できる。
- 透明度もサポートされる(GIFの透明度機能による)。
標準のシェイプを使う
turtle
モジュールには、最初からいくつかの基本的な形状が用意されています。
-
欠点: 非常に基本的な形状に限られる。
-
利点: 簡単、高速、コードが簡潔。
-
使用例:
import turtle t = turtle.Turtle() t.shape("turtle") # 亀の形 t.forward(50) t.shape("circle") # 円の形 t.color("red") t.forward(50) t.shape("square") # 四角の形 t.color("green") t.forward(50) t.shape("triangle") # 三角の形 t.color("blue") t.forward(50) turtle.done()
-
特徴:
- 最も簡単で手軽な方法。
- 特別な定義なしにすぐに使える。
"arrow"
,"turtle"
,"circle"
,"square"
,"triangle"
,"classic"
などがある。
これは厳密にはシェイプの代替ではありませんが、描画した図形を「オブジェクト」として扱う場合に類似の用途があります。
-
欠点:
begin_poly()
のように「タートルの形状そのもの」を変更するわけではない。あくまで描画された図形をスタンプするだけ。 -
利点: 描画と同時に塗りつぶしを行える。タートルの現在の状態(色、向きなど)でスタンプされる。
-
使用例:
import turtle t = turtle.Turtle() t.speed(0) t.penup() # 円を描いて塗りつぶし、スタンプする t.goto(-100, 0) t.pendown() t.fillcolor("orange") t.begin_fill() t.circle(30) t.end_fill() t.penup() t.stamp() # 描画した円をスタンプ # 四角形を描いて塗りつぶし、スタンプする t.goto(100, 0) t.pendown() t.fillcolor("purple") t.begin_fill() for _ in range(4): t.forward(60) t.left(90) t.end_fill() t.penup() t.stamp() # 描画した四角形をスタンプ turtle.done()
-
特徴:
- 多角形を描画し、それを塗りつぶすことができる。
stamp()
を使うことで、描画した図形を複製して画面にスタンプできる。
turtle.begin_poly()
はタートル自身の動きを記録してシェイプを定義する直感的な方法ですが、状況によっては上記の代替方法がより適切である場合があります。
- 描画した図形を「複製」したいだけで、タートルの形状自体を変える必要がない場合:
begin_fill()
とstamp()
の組み合わせが有用です。 - 非常にシンプルな形状で十分な場合: 標準のシェイプを使用するのが最も簡単です。
- 頂点座標が既知または計算で求められる場合:
Screen.addshape()
に直接座標リストを渡す方法が効率的です。 - 複雑な形状や外部デザインを利用したい場合:
Screen.addshape()
と GIF ファイルが最適です。