turtle.end_poly()
turtle
モジュールでは、タートル(描画するカメのようなオブジェクト)を動かして図形を描きます。特定の操作を行うことで、その軌跡を多角形の頂点として記録し、後でその多角形を利用することができます。
end_poly()
の役割
end_poly()
は、turtle.begin_poly()
と組み合わせて使用されます。
turtle.begin_poly()
: この関数を呼び出すと、タートルが動いた軌跡が多角形の頂点として記録され始めます。- (図形を描く操作):
forward()
,left()
,right()
など、タートルの位置を変更する操作を行うと、その位置が多角形の頂点として追加されていきます。 turtle.end_poly()
: この関数を呼び出すと、多角形の頂点の記録が終了します。
end_poly()
を使った後の活用
end_poly()
で記録を終了した多角形は、turtle.get_poly()
関数を使って取得することができます。取得した多角形のデータは、例えば以下のような用途に利用できます。
- 多角形の座標の取得: 記録された多角形の各頂点の座標をリストとして取得し、他の計算や描画に利用することができます。
- カスタムシェイプの登録:
turtle.register_shape()
関数に渡すことで、その多角形をタートル自身の新しい形として登録することができます。これにより、独自のキャラクターやオブジェクトをタートルの形として表示できるようになります。
例
import turtle
t = turtle.Turtle()
t.speed(1) # 描画速度を遅くする
# 多角形の頂点記録を開始
t.begin_poly()
# 四角形を描く
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
# 多角形の頂点記録を終了
t.end_poly()
# 記録された多角形を取得
my_polygon = t.get_poly()
# 取得した多角形を新しいシェイプとして登録
turtle.register_shape("mySquare", my_polygon)
# タートルの形を新しいシェイプに変更
t.shape("mySquare")
turtle.done()
この例では、タートルが描いた四角形の頂点が記録され、その四角形が "mySquare" という名前の新しいタートルの形として登録されます。最終的にタートル自身の形がその四角形に変わるのが確認できます。
begin_poly() を呼び出していない
エラーの症状
turtle.end_poly()
を呼び出す前に turtle.begin_poly()
を呼び出していない場合、通常は直接的なエラーメッセージは出ません。しかし、get_poly()
を呼び出しても空のリストや不完全な多角形データが返ってきたり、後で register_shape()
に渡しても期待通りの形状にならなかったりします。
原因
end_poly()
は「多角形の頂点の記録を終了する」ための関数であり、記録を開始する begin_poly()
が呼び出されていなければ、そもそも記録するものが存在しません。
トラブルシューティング
必ず turtle.begin_poly()
を呼び出して、多角形の記録を開始してから、多角形を構成する移動操作(forward()
, left()
, right()
, goto()
など)を行い、最後に turtle.end_poly()
を呼び出すようにしてください。
悪い例
import turtle
t = turtle.Turtle()
t.forward(100)
t.left(90)
t.end_poly() # begin_poly() がない
my_polygon = t.get_poly()
print(my_polygon) # 空のタプルや不完全なデータが返る可能性が高い
良い例
import turtle
t = turtle.Turtle()
t.begin_poly() # これが重要
t.forward(100)
t.left(90)
t.forward(100)
t.end_poly()
my_polygon = t.get_poly()
print(my_polygon) # ( (x1, y1), (x2, y2), ... ) の形式で頂点座標が記録される
get_poly() を呼び出していない、または結果を適切に利用していない
エラーの症状
end_poly()
で記録を終了しても、その多角形データは自動的に利用されるわけではありません。記録された多角形データが必要な場合は、get_poly()
を明示的に呼び出して取得する必要があります。これを忘れると、カスタムシェイプが登録されない、多角形の座標が利用できないなどの問題が発生します。
原因
end_poly()
はあくまで記録の「停止」を指示するだけで、記録されたデータそのものを返したり、自動的に何かに適用したりはしません。
トラブルシューティング
end_poly()
の直後に turtle.get_poly()
を呼び出し、その戻り値を変数に格納して利用するようにしてください。
悪い例
import turtle
t = turtle.Turtle()
t.begin_poly()
t.circle(50)
t.end_poly()
# ここで get_poly() を呼び出していないため、my_polygon は存在しない
# turtle.register_shape("myCircle", t.get_poly()) # エラーになるか、期待通りに動作しない
良い例
import turtle
t = turtle.Turtle()
t.begin_poly()
t.circle(50)
t.end_poly()
my_circle_shape = t.get_poly() # 記録された多角形データを取得
turtle.register_shape("myCircle", my_circle_shape) # 取得したデータを利用してシェイプを登録
t.shape("myCircle")
turtle.done()
多角形が閉じていない場合の挙動の誤解
エラーの症状
begin_poly()
と end_poly()
で囲まれた範囲で描画された多角形は、デフォルトで最初の頂点と最後の頂点が線で結ばれて閉じられます。もし、意図的に開いた多角形(折れ線)を作りたいのに、get_poly()
で取得したデータを使って register_shape()
などを行うと、勝手に閉じられた形になってしまうことがあります。
原因
turtle
の多角形機能は、主に閉じた図形を扱うために設計されています。get_poly()
で返されるデータは、通常、閉じた多角形を前提としています。
トラブルシューティング
- 開いた多角形(折れ線)を意図している場合
begin_poly()
/end_poly()
を使ってシェイプ登録することは適切ではありません。代わりに、単に線を描画したり、複数の線分として管理したりする方法を検討してください。もしカスタムシェイプとして登録したい場合は、頂点座標を手動で定義する必要があります。 - 閉じた多角形を意図している場合
最初の点に戻るようにタートルを動かす必要はありません。end_poly()
が自動的に最初の点と最後の点を結びます。
例(閉じた多角形が自動で閉じる)
import turtle
t = turtle.Turtle()
t.begin_poly()
t.forward(100)
t.left(90)
t.forward(50) # 始点に戻っていない
t.end_poly()
my_polygon = t.get_poly()
turtle.register_shape("L_shape", my_polygon) # L字型が閉じた五角形として登録される
t.shape("L_shape")
turtle.done()
この場合、開始点と終了点が直線で結ばれて、三角形のような形になります。
複雑すぎる、または不正な描画操作
エラーの症状
begin_poly()
と end_poly()
の間に、多角形の頂点として適切に解釈できないような操作(例えば、clear()
, reset()
, 非常に大きなジャンプなど)を挟むと、予期せぬ多角形が記録されたり、エラーにはならなくとも期待通りの結果が得られなかったりします。
原因
begin_poly()
はタートルの現在の位置を頂点として記録し、その後の移動によって新しい頂点を追加していきます。途中で描画状態がリセットされると、頂点データが途切れたり、不連続になったりする可能性があります。
エラーの症状
これは end_poly()
に直接関連するエラーではありませんが、turtle
グラフィックス全体でよくある問題です。スクリプトを実行しても、タートルウィンドウがすぐに閉じてしまったり、表示されなかったりする場合、描画が完了する前にプログラムが終了している可能性があります。
原因
Pythonスクリプトは、すべてのコマンドを実行し終えると終了します。turtle
ウィンドウは、通常、イベントループ(mainloop()
)が実行されている間だけ開いています。
トラブルシューティング
スクリプトの最後に turtle.done()
または turtle.mainloop()
を追加してください。これにより、タートルウィンドウが開いたままになり、描画された結果を確認できるようになります。
import turtle
t = turtle.Turtle()
t.begin_poly()
t.circle(30)
t.end_poly()
poly = t.get_poly()
turtle.register_shape("mycircle", poly)
t.shape("mycircle")
turtle.done() # これがないとすぐにウィンドウが閉じてしまう
例1:基本的な多角形の記録とカスタムシェイプの作成
この例では、turtle.begin_poly()
と turtle.end_poly()
を使ってシンプルな四角形を記録し、それを新しいタートルシェイプとして登録します。
import turtle
# 画面とタートルオブジェクトの準備
screen = turtle.Screen()
screen.setup(width=600, height=400) # ウィンドウサイズを設定
screen.bgcolor("lightblue") # 背景色を設定
t = turtle.Turtle()
t.speed(3) # 描画速度を速めに設定 (1:遅い, 10:速い, 0:最速)
t.color("darkgreen") # タートルの色を設定
t.pensize(2) # ペンの太さを設定
# 1. 多角形の頂点記録を開始
t.begin_poly()
# 2. 多角形を描く操作 (この例では四角形)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
# 3. 多角形の頂点記録を終了
t.end_poly()
# 4. 記録された多角形データを取得
# get_poly() は、記録された頂点の座標のタプルのタプルを返します
# 例: ((x1, y1), (x2, y2), ..., (xn, yn))
my_square_shape = t.get_poly()
print(f"記録された多角形の頂点: {my_square_shape}")
# 5. 取得した多角形データを新しいタートルシェイプとして登録
# "custom_square" という名前で登録します
turtle.register_shape("custom_square", my_square_shape)
# 6. タートルの形を新しく登録したシェイプに変更
# これでタートルは四角形の形になります
t.shape("custom_square")
t.penup() # ペンを上げて移動
t.goto(-150, 0) # 左に移動
# 別のタートルを作成し、同じカスタムシェイプを適用
t2 = turtle.Turtle()
t2.speed(3)
t2.color("red")
t2.shape("custom_square") # 同じカスタムシェイプを適用
t2.penup()
t2.goto(150, 0) # 右に移動
# 画面をクリックすると終了
screen.exitonclick()
解説
- 登録後、
t.shape("名前")
でタートルの形をその新しいカスタムシェイプに変更できます。 turtle.register_shape("名前", 多角形データ)
を使うことで、この多角形をタートルの新しい「形」として登録できます。t.get_poly()
は、その記録された頂点データを取得します。このデータは、タプルの中に各頂点の(x, y)
座標がタプルとして格納された形式です。t.begin_poly()
からt.end_poly()
の間でタートルが行った移動の軌跡が、多角形の頂点として内部的に記録されます。
例2:開いた多角形の記録と形状としての利用 (注意点あり)
turtle.end_poly()
は、デフォルトで開始点と終了点を自動的に結んで多角形を閉じようとします。この例では、閉じないL字型を描いて、その挙動を確認します。
import turtle
screen = turtle.Screen()
screen.setup(width=600, height=400)
screen.bgcolor("lightyellow")
t = turtle.Turtle()
t.speed(3)
t.color("blue")
t.pensize(3)
t.penup()
t.goto(-100, 50)
t.pendown()
# 多角形の記録を開始
t.begin_poly()
# L字型を描く (開始点に戻らない)
t.forward(100)
t.right(90)
t.forward(50)
t.left(90)
t.forward(50)
# 多角形の記録を終了
t.end_poly()
# 記録された多角形を取得
l_shape_data = t.get_poly()
print(f"L字型として記録された頂点: {l_shape_data}")
# カスタムシェイプとして登録
turtle.register_shape("custom_l_shape", l_shape_data)
# タートルの形を変更
t.shape("custom_l_shape")
t.penup()
t.goto(0, -50) # 位置を移動して確認しやすくする
# 注意: この場合、始点と終点が自動的に結ばれて閉じられた図形として登録されます。
# L字型そのものではなく、L字型が閉じた五角形のように見えます。
screen.exitonclick()
解説
- 開いた線分をシェイプとして使いたい場合は、
begin_poly()
/end_poly()
よりも、頂点座標を直接リストで定義する方法を検討する必要があります。 - このため、シェイプとして登録すると、意図した「L字型」そのままではなく、閉じられた図形として表示されます。
t.begin_poly()
からt.end_poly()
の間でタートルが描いたL字型は、開始点と終了点(この例では最初の(-100, 50)
と最後の(50, 0)
あたり)が直線で自動的に結ばれて、閉じた多角形としてl_shape_data
に記録されます。
例3:多角形の頂点座標を直接利用する
get_poly()
で取得した頂点データは、シェイプ登録だけでなく、他の目的でも利用できます。この例では、取得した座標を表示し、別の方法でその座標を使って描画します。
import turtle
screen = turtle.Screen()
screen.setup(width=600, height=400)
screen.bgcolor("lightgrey")
t = turtle.Turtle()
t.speed(3)
t.color("purple")
t.pensize(2)
t.penup()
t.goto(-100, 0)
t.pendown()
# 星形の一部を記録
t.begin_poly()
t.forward(100)
t.right(144) # 360 / 5 * 2 = 144
t.forward(100)
t.right(144)
t.forward(100)
t.end_poly()
# 記録された多角形データ (この場合、3つの頂点) を取得
part_of_star_points = t.get_poly()
print(f"星形の一部として記録された頂点: {part_of_star_points}")
# 別のタートルを作成し、取得した頂点を使って描画してみる
drawer = turtle.Turtle()
drawer.speed(1)
drawer.color("orange")
drawer.pensize(4)
drawer.penup()
# 記録された各頂点へ移動し、線で結ぶ
if part_of_star_points: # 頂点が存在することを確認
drawer.goto(part_of_star_points[0]) # 最初の頂点へ移動
drawer.pendown()
for point in part_of_star_points:
drawer.goto(point)
drawer.goto(part_of_star_points[0]) # 閉じるために最初の頂点に戻る
else:
print("頂点データがありませんでした。")
screen.exitonclick()
解説
- この例では、別のタートル
drawer
を使って、取得したpart_of_star_points
の各座標に移動し、線を描画しています。これにより、begin_poly()
/end_poly()
で記録した形状を、他のタートルの描画操作に再利用できることがわかります。 t.get_poly()
が返すのは座標のタプルなので、これを通常のPythonのリストやタプルと同じように扱えます。
複数の図形をそれぞれ異なるカスタムシェイプとして登録する例です。
import turtle
screen = turtle.Screen()
screen.setup(width=600, height=400)
screen.bgcolor("grey")
# 三角形のシェイプを定義
triangle_t = turtle.Turtle(visible=False) # 描画中にタートルが見えないようにする
triangle_t.speed(0)
triangle_t.penup()
triangle_t.goto(-100, 100)
triangle_t.pendown()
triangle_t.begin_poly()
for _ in range(3):
triangle_t.forward(80)
triangle_t.left(120)
triangle_t.end_poly()
triangle_shape = triangle_t.get_poly()
turtle.register_shape("custom_triangle", triangle_shape)
# 円のシェイプを定義 (ただし、円は多くの短い線分で構成される多角形になる)
circle_t = turtle.Turtle(visible=False)
circle_t.speed(0)
circle_t.penup()
circle_t.goto(100, 100)
circle_t.pendown()
circle_t.begin_poly()
circle_t.circle(40, steps=20) # 20ステップで円を描く
circle_t.end_poly()
circle_shape = circle_t.get_poly()
turtle.register_shape("custom_circle", circle_shape)
# これらのシェイプを使ってタートルを作成
t1 = turtle.Turtle("custom_triangle")
t1.color("green")
t1.penup()
t1.goto(-100, -50)
t2 = turtle.Turtle("custom_circle")
t2.color("blue")
t2.penup()
t2.goto(100, -50)
screen.exitonclick()
- 円は、
circle(radius, steps=N)
のようにsteps
引数を使うことで、N個の短い線分で構成される多角形として描画され、その頂点が記録されます。 - 異なるタートルを使って、それぞれ異なる多角形を記録し、異なる名前でシェイプを登録しています。
visible=False
をturtle.Turtle()
の引数として渡すことで、シェイプを記録するためのタートル自身は画面に表示されなくなります。これにより、記録プロセスがクリーンになります。
add_polygon() メソッドを使用する (より直接的な多角形定義)
turtle.end_poly()
はタートルの動きを追跡して多角形を記録しますが、もし多角形の頂点座標が既に分かっている場合や、プログラムで計算できる場合は、Screen
オブジェクトの add_polygon()
メソッドを直接使用する方がシンプルです。
特徴
add_polygon()
は非推奨のメソッドですが、一部の環境で動作する可能性があります。より推奨されるのはregister_shape()
の利用です。- 頂点座標のリスト(またはタプル)を直接渡す。
- タートルを動かす必要がない。
代替方法の例
import turtle
screen = turtle.Screen()
screen.setup(width=600, height=400)
screen.bgcolor("lightcyan")
# 1. 多角形の頂点座標を直接定義
# この例では、正方形の頂点を定義
square_vertices = ((-50, 50), (50, 50), (50, -50), (-50, -50))
# 2. 定義した頂点を使って新しいシェイプを登録
# turtle.register_shape() の第2引数に直接頂点リストを渡す
turtle.register_shape("direct_square", square_vertices)
# 3. 新しいシェイプを持つタートルを作成
t = turtle.Turtle("direct_square")
t.color("darkblue")
t.penup()
t.goto(-100, 0)
t.stamp() # その場でシェイプを描画
# 別のシェイプを定義 (三角形)
triangle_vertices = ((0, 50), (-50, -50), (50, -50))
turtle.register_shape("direct_triangle", triangle_vertices)
t2 = turtle.Turtle("direct_triangle")
t2.color("red")
t2.penup()
t2.goto(100, 0)
t2.stamp()
screen.exitonclick()
解説
- 頂点座標は、
(x, y)
のタプルのリスト、またはタプルのタプルとして渡します。 turtle.register_shape("シェイプ名", 頂点座標のリスト)
を使うことで、begin_poly()
とend_poly()
を介さずに直接カスタムシェイプを定義できます。
Shape オブジェクトを直接操作する
turtle
モジュールには、より低レベルでシェイプを操作するための Shape
クラスがあります。これを使って、複数の多角形や複合的な形状を定義することも可能です。
特徴
_add_polygon()
や_add_line()
など、より詳細な制御が可能だが、これらは内部的なメソッドであり、公式ドキュメントにはあまり記載されていないため、利用には注意が必要。- 複数の多角形を組み合わせたシェイプを作成できる。
- より柔軟に複雑な形状を定義できる。
代替方法の例 (少し高度)
import turtle
screen = turtle.Screen()
screen.setup(width=600, height=400)
screen.bgcolor("peachpuff")
# 1. 新しいShapeオブジェクトを作成
my_complex_shape = turtle.Shape("compound") # "compound" タイプは複数の要素を持つことができる
# 2. 最初の多角形 (長方形) を定義し、Shapeに追加
rect_points = ((-40, 20), (40, 20), (40, -20), (-40, -20))
my_complex_shape.addcomponent(rect_points, "darkgreen", "lightgreen") # 頂点, ペン色, 塗りつぶし色
# 3. 2番目の多角形 (三角形) を定義し、Shapeに追加
# 長方形の上に乗るように配置
tri_points = ((-20, 20), (0, 50), (20, 20))
my_complex_shape.addcomponent(tri_points, "darkblue", "lightblue")
# 4. Shapeオブジェクトをタートルシェイプとして登録
turtle.register_shape("my_house", my_complex_shape)
# 5. 新しいシェイプを持つタートルを作成
house_turtle = turtle.Turtle("my_house")
house_turtle.penup()
house_turtle.goto(0, -50)
house_turtle.stamp()
screen.exitonclick()
解説
my_complex_shape.addcomponent(頂点リスト, ペン色, 塗りつぶし色)
を使って、そのシェイプに複数の多角形を追加できます。これにより、複数の部分からなる一つのカスタムシェイプを作成できます。turtle.Shape("compound")
で複合的なシェイプを作成します。
end_poly()
はシェイプを登録するためのものですが、get_poly()
で取得した多角形データを一時的な描画や計算のみに利用し、永続的なシェイプ登録をしないという選択肢もあります。
特徴
- 多角形の頂点座標を他の描画ロジックや計算(例:衝突判定)に利用したい場合。
- 記録した多角形をタートルの形として保持する必要がない。
代替方法の例
import turtle
screen = turtle.Screen()
screen.setup(width=600, height=400)
screen.bgcolor("white")
t = turtle.Turtle()
t.speed(3)
t.color("black")
t.pensize(2)
t.penup()
t.goto(-150, 0)
t.pendown()
# 1. 多角形を描き、その頂点を記録
t.begin_poly()
t.circle(50) # 円を描く
t.end_poly()
# 2. 記録された多角形の頂点データを取得
circle_points = t.get_poly()
print(f"円の頂点: {circle_points}")
# 3. 記録された頂点を使って、別の場所にもう一つ円を描く
# シェイプとして登録するのではなく、描画コマンドで再構築
t.penup()
t.goto(50, 0)
t.pendown()
t.color("red")
t.pensize(3)
# 取得した頂点を使って描画
if circle_points:
t.goto(circle_points[0]) # 最初の点へ移動
t.pendown()
for point in circle_points:
t.goto(point)
t.goto(circle_points[0]) # 閉じる
screen.exitonclick()
解説
- これにより、一時的な描画や、図形分析などの目的で頂点データが必要な場合に便利です。
begin_poly()
とend_poly()
を使って頂点データを記録する点では同じですが、その後register_shape()
を呼び出さず、取得したcircle_points
を別の描画操作に直接利用しています。
turtle.end_poly()
の代替方法は、主に以下のシナリオによって選択肢が変わります。
- 既存の頂点座標がある、または簡単に計算できる場合
turtle.register_shape("名前", 頂点座標リスト)
が最も直接的で推奨される方法です。
- 複数の多角形を組み合わせて一つの複雑なシェイプを作成したい場合
turtle.Shape("compound")
とaddcomponent()
を使う方法が強力です。
- 多角形の頂点データを一時的に取得して、描画以外の目的(例:衝突判定、分析)で使いたい場合
begin_poly()
とend_poly()
を使ってget_poly()
でデータを取得し、それを直接利用します。シェイプ登録はしません。