Python Turtle入門: end_fill()で図形を美しく塗りつぶす方法
具体的には、次のような流れで使われます。
turtle.begin_fill()
の呼び出し: まず、塗りつぶしを開始したい図形を描画する前にturtle.begin_fill()
を呼び出します。これにより、タートルが描画する線が記憶され始めます。- 図形の描画:
turtle.forward()
やturtle.left()
などのコマンドを使って、塗りつぶしたい図形(例えば、四角形や円など)を描画します。この際、描画の開始点と終了点が一致している(つまり、図形が閉じている)必要があります。 turtle.end_fill()
の呼び出し: 図形の描画が終わったら、turtle.end_fill()
を呼び出します。これにより、begin_fill()
が呼び出されてから描画された線で囲まれた領域が、現在のタートルの塗りつぶし色 (turtle.fillcolor()
) で塗りつぶされます。
なぜこれが必要なのか?
turtle
モジュールで図形を描画するだけでは、その内部は透明なままです。内部を特定の色で塗りつぶしたい場合に begin_fill()
と end_fill()
のペアを使います。
例
import turtle
# タートルオブジェクトの作成
t = turtle.Turtle()
# 塗りつぶし色を赤に設定
t.fillcolor("red")
# 塗りつぶしを開始
t.begin_fill()
# 四角形を描画
for _ in range(4):
t.forward(100)
t.right(90)
# 塗りつぶしを完了
t.end_fill()
# 画面を閉じるまで待機
turtle.done()
このコードを実行すると、赤い色で塗りつぶされた四角形が描画されます。
よくあるエラーと問題
-
図形が塗りつぶされない (No Fill) これが最も一般的な問題です。
- begin_fill() が呼び出されていない、または間違った場所で呼び出されている
end_fill()
は、必ずbegin_fill()
の後に、塗りつぶしたい図形の描画処理を挟んで呼び出す必要があります。もしbegin_fill()
が呼び出されていない、あるいは図形の描画が始まる前に呼び出されていない場合、タートルは塗りつぶす範囲を認識できません。 - 図形が閉じていない (Shape Not Closed)
turtle
は、タートルがbegin_fill()
を呼び出してからend_fill()
を呼び出すまでの間に描いたパスが閉じている(開始点と終了点が同じ位置にある)ことを期待します。パスが閉じられていない場合、正しく塗りつぶされないか、予期せぬ部分が塗りつぶされることがあります。 - fillcolor() が設定されていない、または間違った場所で設定されている
塗りつぶしの色 (fillcolor
) を設定しない場合、デフォルトの色(通常は黒)が適用されますが、場合によっては何も塗りつぶされないように見えることもあります。また、begin_fill()
の前にfillcolor()
を設定しておくのが一般的です。 - begin_fill() と end_fill() がループの中に含まれている
例えば、多角形を描画するループの中でbegin_fill()
とend_fill()
を各辺ごとに呼び出してしまうと、期待通りに図形全体が塗りつぶされません。これらは図形全体の開始と終了を示すため、ループの外に配置する必要があります。
- begin_fill() が呼び出されていない、または間違った場所で呼び出されている
-
予期せぬ部分が塗りつぶされる (Unexpected Fill)
- penup()/pendown() の使用
begin_fill()
とend_fill()
の間にpenup()
(ペンを上げる)を使用すると、タートルが移動した経路が連続していないとみなされ、塗りつぶしが正しく行われないことがあります。塗りつぶしたい図形を描画している間は、ペンは下げておく (pendown()
) 必要があります。 - 複雑な図形や自己交差する図形
turtle
モジュールの塗りつぶしアルゴリズムは、比較的単純な図形を想定しています。自己交差する図形(星形など)の場合、塗りつぶしのルール(偶奇ルールや非ゼロ巻数ルールなど)によっては、期待通りの塗りつぶしにならないことがあります。これはturtle
の制限というよりは、グラフィックライブラリの動作によるものです。
- penup()/pendown() の使用
-
エラーメッセージが出る (Error Messages)
- TypeError: begin_fill() takes 1 positional argument but 2 were given
これはbegin_fill()
に引数を与えてしまった場合に発生します。begin_fill()
は引数を取りません。塗りつぶし色はfillcolor()
メソッドで設定します。
- TypeError: begin_fill() takes 1 positional argument but 2 were given
-
コードの順番を確認する
turtle.fillcolor("色名")
またはt.fillcolor("色名")
(タートルオブジェクトt
の場合)turtle.begin_fill()
またはt.begin_fill()
- 図形を描画するコード (例:
t.forward(100)
,t.left(90)
) turtle.end_fill()
またはt.end_fill()
この順番が守られているかを確認してください。
-
図形が閉じているか確認する
描画の開始点と終了点が一致していることを確認します。例えば、正方形であれば、最後にt.goto(開始点のX, 開始点のY)
を追加して明示的に閉じることもできますが、通常はforward()
とright()
などの組み合わせで自然に閉じます。 -
fillcolor() を明示的に設定する
塗りつぶしの色をturtle.fillcolor()
またはt.fillcolor()
で設定しているか確認してください。 -
begin_fill() と end_fill() の範囲を確認する
これらが塗りつぶしたい図形全体を囲むように配置されているか確認します。特にループを使用している場合は、ループの外にこれらのメソッドが配置されていることを確認してください。悪い例 (ループ内で begin_fill/end_fill)
import turtle t = turtle.Turtle() t.fillcolor("blue") for _ in range(4): t.begin_fill() # 間違い! t.forward(100) t.right(90) t.end_fill() # 間違い! turtle.done()
正しい例
import turtle t = turtle.Turtle() t.fillcolor("blue") t.begin_fill() # ここで開始 for _ in range(4): t.forward(100) t.right(90) t.end_fill() # ここで終了 turtle.done()
-
デバッグのために一時的に塗りつぶしを無効にする
begin_fill()
とend_fill()
をコメントアウトして、図形自体が正しく描画されているかを確認するのも良い方法です。図形が閉じていることを視覚的に確認できます。 -
簡単な図形で試す
もし複雑な図形で問題が発生している場合は、まず簡単な正方形や円でbegin_fill()
とend_fill()
が機能するかどうかを試してみることで、問題の切り分けができます。
例1:シンプルな四角形の塗りつぶし
最も基本的な使い方です。begin_fill()
で塗りつぶしを開始し、図形を描画した後、end_fill()
で塗りつぶしを完了します。
import turtle
# タートルオブジェクトの作成
t = turtle.Turtle()
t.speed(1) # 描画速度を少し遅くする (オプション)
# 塗りつぶしの色を設定
t.fillcolor("red") # 赤色で塗りつぶす
# ペンの色を設定(線の色)
t.pencolor("blue") # 青い線で描画する
# 塗りつぶしの開始
t.begin_fill()
# 四角形を描画
for _ in range(4):
t.forward(100) # 100ピクセル前進
t.right(90) # 右に90度回転
# 塗りつぶしの完了
t.end_fill()
# 描画ウィンドウがすぐに閉じないようにする
turtle.done()
解説
import turtle
: turtle モジュールをインポートします。t = turtle.Turtle()
: 描画を行うためのタートルオブジェクトを作成します。t.fillcolor("red")
: これから塗りつぶす際の色を「赤」に設定します。t.pencolor("blue")
: 線の色を「青」に設定します。t.begin_fill()
: ここから描画される図形を塗りつぶしの対象として記憶し始めます。for _ in range(4): ...
: 100ピクセルの辺を持つ四角形を描画します。タートルは開始点から出発し、最終的に開始点に戻って図形が閉じます。t.end_fill()
:begin_fill()
からend_fill()
までの間に描画された閉じられた図形が、設定されたfillcolor
(赤)で塗りつぶされます。turtle.done()
: 描画ウィンドウが自動的に閉じないようにします。
例2:異なる色で複数の図形を塗りつぶす
begin_fill()
と end_fill()
のペアを複数回使用することで、異なる図形を異なる色で塗りつぶすことができます。
import turtle
t = turtle.Turtle()
t.speed(3)
# 最初の図形:青い四角形
t.penup() # ペンを上げて移動
t.goto(-150, 0) # 座標(-150, 0)へ移動
t.pendown() # ペンを下げる
t.fillcolor("blue") # 塗りつぶし色を青に設定
t.pencolor("black") # 線の色を黒に設定
t.begin_fill()
for _ in range(4):
t.forward(80)
t.right(90)
t.end_fill()
# 2番目の図形:緑色の円
t.penup()
t.goto(50, 0) # 座標(50, 0)へ移動
t.pendown()
t.fillcolor("green") # 塗りつぶし色を緑に設定
t.pencolor("darkgreen") # 線の色を濃い緑に設定
t.begin_fill()
t.circle(60) # 半径60の円を描画
t.end_fill()
turtle.done()
解説
- 最初の四角形を塗りつぶすために、
penup()
とgoto()
で位置を移動し、fillcolor("blue")
で色を設定し、begin_fill()
とend_fill()
のペアを使います。 - 同様に、2番目の図形(円)を塗りつぶすために、別の位置に移動し、
fillcolor("green")
で色を設定し、再びbegin_fill()
とend_fill()
のペアを使用します。 - 重要なのは、
begin_fill()
とend_fill()
のペアは、それぞれが独立した塗りつぶし操作を完結させるという点です。
例3:星形を塗りつぶす(自己交差する図形)
turtle
は自己交差する図形(線が途中で交差する図形)も塗りつぶすことができますが、その際の塗りつぶしルール(通常は「非ゼロ巻数ルール」や「偶奇ルール」)によって、期待通りの塗りつぶしになるかは注意が必要です。
import turtle
t = turtle.Turtle()
t.speed(5)
t.penup()
t.goto(-100, 50)
t.pendown()
t.fillcolor("gold") # 金色で塗りつぶす
t.pencolor("orange") # オレンジ色の線
t.pensize(2) # ペンの太さ
t.begin_fill()
# 星形(五芒星)を描画
for _ in range(5):
t.forward(200)
t.right(144) # 360 / 5 * 2 = 144 (外角)
t.end_fill()
turtle.done()
解説
- 星形は、直線が交差する複雑な図形です。
right(144)
の角度で5回線を描くことで、星形を完成させます。 begin_fill()
とend_fill()
の間に星形の描画コードを挟むことで、turtle
がその形状を認識し、塗りつぶしを行います。- この場合、星の中央部分も塗りつぶされます。これは、
turtle
の内部的な塗りつぶしアルゴリズムが、パスが「閉じられている」と判断した領域全体を塗りつぶすためです。
例えば、goto()
を使って明示的に開始点に戻ることで図形を閉じる場合も、end_fill()
は機能します。
import turtle
t = turtle.Turtle()
t.speed(1)
t.fillcolor("purple") # 紫色で塗りつぶす
t.pencolor("black")
t.begin_fill()
# 三角形を描画(最後に開始点に戻る)
t.forward(100)
t.left(120)
t.forward(100)
t.left(120)
t.goto(t.xcor() - 100 * (t.heading() == 0), t.ycor()) # 開始点に正確に戻るための工夫(より確実な方法)
# あるいは単純に t.left(120); t.forward(100) でも閉じられます。
# しかし、このようにgotoを使うことも可能です。
t.end_fill()
turtle.done()
- この例では、三角形の3辺を描画した後、
t.goto()
を使って明示的に開始点に戻ることで図形を閉じています。 begin_fill()
とend_fill()
は、タートルが描いた経路が閉じられれば、その内部を塗りつぶします。
t.dot(size, color): 点を塗りつぶす
これは、塗りつぶされた円(点)を描画するのに使われます。特定の座標に小さな円を描画したい場合に便利です。
import turtle
t = turtle.Turtle()
t.speed(1)
t.penup()
# 複数の点を描画
t.goto(-100, 0)
t.dot(50, "red") # 直径50ピクセルの赤い点を描画
t.goto(0, 50)
t.dot(30, "blue") # 直径30ピクセルの青い点を描画
t.goto(100, -50)
t.dot(70, "green") # 直径70ピクセルの緑の点を描画
turtle.done()
解説
- これは
begin_fill()
とend_fill()
のペアを必要とせず、単一の呼び出しで完結します。 t.dot(size, color)
は、現在のタートルの位置に指定されたsize
(直径)とcolor
で塗りつぶされた円を描画します。
t.circle(radius, extent=None, steps=None): 円/弧を描き、fillcolor で自動的に塗りつぶす(Polygonオプション)
circle()
メソッドは、円や円弧を描画するために使用されますが、steps
引数を使うことで、擬似的に多角形を描画し、それが自動的に塗りつぶされるようにすることができます。これは、begin_fill()
と end_fill()
を手動で呼び出す手間を省きたい場合に便利です。
import turtle
t = turtle.Turtle()
t.speed(1)
# 塗りつぶしの色と線の色を設定
t.fillcolor("orange")
t.pencolor("brown")
# 8角形(八角形)を円の代わりに描画し、塗りつぶす
# radius=80: 半径80の円に内接する多角形
# steps=8: 8つの辺を持つ多角形
t.begin_fill() # circle(steps)を使う場合もbegin_fill/end_fillは使えますが、
# steps引数自体が閉じた図形を自動的に作ります
t.circle(80, steps=8) # 半径80の円を8つのステップ(辺)で描画(八角形)
t.end_fill() # この場合、begin_fill/end_fillがなくても塗りつぶされますが、明示的に使うこともできます
# fillcolorとpencolorを設定してからcircle(steps)を呼び出すと自動的に塗りつぶされる
t.penup()
t.goto(-200, 0)
t.pendown()
t.fillcolor("purple")
t.pencolor("magenta")
t.circle(60, steps=5) # 半径60の五角形を描画し、自動的に塗りつぶされる
turtle.done()
解説
- これは、特に正多角形を簡単に描画し、塗りつぶしたい場合に非常に便利です。
t.circle(radius, steps=N)
は、N
個の等しい辺を持つ正N
角形を描画します。この方法で描画された多角形は、事前にt.fillcolor()
が設定されていれば、自動的に塗りつぶされます。begin_fill()
とend_fill()
を明示的に呼び出す必要はありません。
厳密には図形の「塗りつぶし」ではありませんが、テキストを描画する際にその内部が塗りつぶされたように見えることがあります。これは、文字自体が形状を持つためです。
import turtle
t = turtle.Turtle()
t.speed(1)
t.penup()
t.goto(-150, 0)
t.pendown()
# 文字列を塗りつぶされたように描画
t.pencolor("darkblue") # 線の色
t.fillcolor("lightblue") # 塗りつぶし色
# write() は自動的に塗りつぶされないので、通常は文字の描画に使われます。
# しかし、フォントの種類によっては塗りつぶされたように見えることがあります。
# t.write("Hello!", move=False, align="left", font=("Arial", 40, "bold"))
# 文字の塗りつぶしは通常、begin_fill/end_fillとは関係ありませんが、
# テキストの描画も「塗りつぶされたような」出力として考えられるため、ここで触れました。
# もし文字の輪郭を描いて塗りつぶしたい場合は、別のライブラリ(例: Pillow, reportlab)を使うか、
# 各文字をパスとして描画する複雑な処理が必要です。
turtle.done()
- しかし、フォントのスタイルによっては、文字自体が塗りつぶされたように見えることがあります。これは直接的な代替方法ではありませんが、「塗りつぶされた出力」という広義の意味では関連します。
t.write()
は文字列を描画しますが、通常は文字の輪郭を描画するだけで、begin_fill()
/end_fill()
のような明示的な塗りつぶしは行いません。
t.write()
: テキストを描画するもので、図形の塗りつぶしとは異なりますが、塗りつぶされたような視覚効果を持つ場合があります。t.circle(radius, steps=N)
: 正多角形を自動的に塗りつぶしながら描画するのに非常に便利です。begin_fill()
/end_fill()
を明示的に使わなくても、fillcolor
が設定されていれば自動的に塗りつぶされます。t.dot()
: 単純な塗りつぶされた円を描画するのに最適です。begin_fill()
/end_fill()
は不要です。