Python Turtle入門: sety()を使った描画テクニックと注意点

2025-06-06

turtle.sety() とは

  • 動き: タートルは瞬間的に新しいY座標に「ジャンプ」します。forward()backward() のように線を引く動きとは異なり、この移動中に線が描かれることはありません(ペンが下がっていても)。
  • 引数: Y座標の新しい値を数値で指定します。この値は整数または浮動小数点数です。
  • 機能: タートルの現在のX座標はそのままに、Y座標を指定した値に設定します。これにより、タートルは垂直方向に移動します。

使用例

import turtle

# スクリーンとタートルをセットアップ
screen = turtle.Screen()
t = turtle.Turtle()

# 初期位置 (0,0) からスタート
print(f"初期位置: ({t.xcor()}, {t.ycor()})") # 出力例: 初期位置: (0.0, 0.0)

# Y座標を50に設定
t.sety(50)
print(f"sety(50)後: ({t.xcor()}, {t.ycor()})") # 出力例: sety(50)後: (0.0, 50.0)

# X座標はそのままに、Y座標を-100に設定
t.sety(-100)
print(f"sety(-100)後: ({t.xcor()}, {t.ycor()})") # 出力例: sety(-100)後: (0.0, -100.0)

# 描画が終わるまでウィンドウを開いたままにする
screen.mainloop()

上記の例では、タートルのX座標は常に 0.0 のままで、sety() を呼び出すたびにY座標が変化していることがわかります。

  • turtle.goto(x, y) / turtle.setposition(x, y) / turtle.setpos(x, y): X座標とY座標の両方を同時に設定します。
  • turtle.setheading(angle) / turtle.seth(angle): タートルの向き(角度)を設定します。
  • turtle.setx(x): Y座標はそのままに、X座標を設定します。


turtle.sety() に関する一般的なエラーとトラブルシューティング

エラー: AttributeError: 'module' object has no attribute 'sety' または AttributeError: 'NoneType' object has no attribute 'sety'

これは、turtle オブジェクトが正しく作成されていないか、turtle モジュール自体に対して sety() を呼び出そうとしている場合に発生します。

  • 解決策

    • 必ずタートルオブジェクトを作成し、そのオブジェクトのメソッドとして sety() を呼び出してください。
    import turtle
    
    # 悪い例 (モジュールに対して呼び出し)
    # turtle.sety(50) # エラー
    
    # 良い例 (タートルオブジェクトを作成し、それに対して呼び出し)
    my_turtle = turtle.Turtle()
    my_turtle.sety(50)
    
    turtle.done() # ウィンドウを閉じないように
    
    • t = turtle.Turtle() のように、タートルオブジェクトをインスタンス化していない。
    • turtle.sety() のように、モジュール名 (turtle) を使って直接呼び出そうとしている。
    • 変数にタートルオブジェクトが適切に代入されていない(例: t = screen.textinput(...) の後に t をタートルオブジェクトとして使おうとしている)。

エラー: TypeError: sety() missing 1 required positional argument: 'y'

このエラーは、sety() 関数に必要な引数(Y座標の値)が提供されていない場合に発生します。

  • 解決策

    • sety() には、必ずY座標の値を数値(整数または浮動小数点数)で渡してください。
    import turtle
    t = turtle.Turtle()
    
    # 悪い例 (引数がない)
    # t.sety() # エラー
    
    # 良い例 (引数を渡す)
    t.sety(100)
    t.sety(-50.5)
    
    turtle.done()
    
  • 原因

    • sety() を引数なしで呼び出している。

タートルが動かない、または描画されない

sety() はタートルのY座標を瞬間的に設定するだけで、その移動中に線を描くわけではありません。また、タートルがスクリーンに表示されていない可能性もあります。

  • 解決策

    • 線を描きたい場合は、sety() の前に t.pendown() を呼び出してください。ただし、sety() 自体は線を引く動きではないことを理解してください。線を引く移動をしたい場合は t.forward()t.backward() を使うか、t.goto() を使うとペンが下がっていれば移動中に線が引かれます。
    • t.showturtle() を呼び出して、タートルが表示されていることを確認してください。
    • Y座標の値が、turtle.Screen() のデフォルトまたは設定された座標範囲内に収まっているか確認してください。デフォルトでは、中央が (0,0) で、画面のサイズに応じてYの最大値と最小値が決まります。screen.screensize()screen.window_height() で確認できます。
    • プログラムの最後に turtle.done() または screen.mainloop() を追加して、グラフィックウィンドウが開いたままになるようにしてください。
    import turtle
    screen = turtle.Screen()
    t = turtle.Turtle()
    
    t.penup()      # ペンを上げる
    t.sety(50)     # 線は描かれない
    t.pendown()    # ペンを下げる
    t.forward(100) # ここで線が描かれる
    
    t.hideturtle() # タートルを非表示にする
    t.sety(-50)    # タートルは動いているが、見えない
    t.showturtle() # タートルを再表示する
    
    screen.mainloop()
    
  • 原因

    • ペンが上がっている (t.penup())。
    • sety() は瞬間移動であり、線は描かれないことを誤解している。
    • タートルが画面外に移動している(Y座標がスクリーンの範囲外)。
    • turtle.done()screen.mainloop() が呼び出されていないため、ウィンドウがすぐに閉じてしまう。
    • タートルが非表示になっている (t.hideturtle())。

タートルが期待した場所ではない

これは通常、座標系の理解不足や、他の移動関数と sety() を混同している場合に起こります。

  • 解決策

    • sety(y) は、タートルのY座標を原点 (0) からの絶対値 y に設定することを覚えておいてください。
    • 現在のタートルのY座標から相対的に移動したい場合は、t.sety(t.ycor() + delta_y) のように現在のY座標を取得し、それに加算または減算して新しいY座標を設定する方法を検討してください。
    • 特定の座標に移動したい場合は、t.goto(x, y) を使うのが最も一般的です。
    import turtle
    t = turtle.Turtle()
    
    t.sety(50) # Y座標が50になる (X座標は0のまま)
    print(f"現在の位置: ({t.xcor()}, {t.ycor()})") # 例: (0.0, 50.0)
    
    t.setx(100) # X座標が100になる (Y座標は50のまま)
    print(f"現在の位置: ({t.xcor()}, {t.ycor()})") # 例: (100.0, 50.0)
    
    # 現在のY座標からさらに20上に移動したい場合
    t.sety(t.ycor() + 20)
    print(f"現在の位置: ({t.xcor()}, {t.ycor()})") # 例: (100.0, 70.0)
    
    turtle.done()
    
  • 原因

    • sety() は現在のタートルの向きやX座標に影響を与えません。純粋にY座標だけを設定します。
    • 相対的な移動 (forward(), backward()) と絶対的な移動 (sety(), setx(), goto()) を混同している。
  1. Printデバッグ
    print(f"X: {t.xcor()}, Y: {t.ycor()}") のように、t.xcor()t.ycor() を使ってタートルの現在位置を頻繁に出力し、期待通りの座標になっているか確認してください。
  2. ステップ実行
    デバッガを使用してコードをステップ実行し、各行がタートルの状態にどのように影響するかを確認します。
  3. コメントアウト
    問題のあると思われるコードのセクションを一時的にコメントアウトし、それが問題の原因であるかどうかを特定します。
  4. シンプルなテスト
    複雑な描画の一部として sety() を使用している場合、まず sety() 単独で正しく動作するかどうかを、非常にシンプルなスクリプトでテストしてみてください。


例1: 単純なY座標の移動と位置の確認

最も基本的な使い方です。タートルの初期位置からY座標を変化させ、そのたびに現在位置を確認します。

import turtle

# 1. スクリーンとタートルオブジェクトの準備
screen = turtle.Screen() # 描画スクリーン
t = turtle.Turtle()      # タートル(ペン役)

t.shape("turtle") # タートルの形をカメにする
t.speed(1)        # タートルの速度をゆっくりに設定 (0=最速, 1=最も遅い, 10=速い)

print(f"初期位置: X={t.xcor()}, Y={t.ycor()}") # 開始時の座標を表示 (通常は0,0)

# 2. Y座標を上に移動
print("\nY座標を50に設定します...")
t.sety(50)
print(f"設定後の位置: X={t.xcor()}, Y={t.ycor()}") # Xは変わらず、Yが50になる

# 3. Y座標を下に移動
print("\nY座標を-80に設定します...")
t.sety(-80)
print(f"設定後の位置: X={t.xcor()}, Y={t.ycor()}") # Xは変わらず、Yが-80になる

# 4. さらにY座標を上に移動 (小数点も使用可能)
print("\nY座標を20.5に設定します...")
t.sety(20.5)
print(f"設定後の位置: X={t.xcor()}, Y={t.ycor()}") # Xは変わらず、Yが20.5になる

# 描画ウィンドウがすぐに閉じないようにする
screen.mainloop()
# または turtle.done()

解説:

  • t.xcor()t.ycor() は、それぞれ現在のタートルのX座標とY座標を取得します。
  • sety() は、X座標はそのままでY座標だけを瞬間的に変更します。この移動中に線は描かれません。

例2: sety() を使った垂直なグリッドラインの描画

sety() をループ内で使用することで、Y座標を段階的に変更しながら描画を行うことができます。この例では、複数の水平線を描いてグリッドのように見せます。

import turtle

screen = turtle.Screen()
t = turtle.Turtle()
t.speed(0) # 最速で描画

t.penup() # ペンを上げる (移動中に線を描かない)
t.goto(-200, 150) # 開始位置に移動 (左上の方)
t.pendown() # ペンを下げる (ここから線を描く準備)

# 複数の水平線を描画
for i in range(7): # 7本の線を描く
    t.forward(400) # 右に400進む (水平線を描く)
    
    t.penup() # ペンを上げる
    # Y座標を下にずらす (現在のY座標から50ずつ減らす)
    # t.sety(t.ycor() - 50) は t.sety(現在のY - 50) と同じ
    t.sety(t.ycor() - 50) 
    
    t.backward(400) # 左に400戻る (次の線の開始位置に戻る)
    t.pendown() # ペンを下げる

screen.mainloop()

解説:

  • t.sety(t.ycor() - 50) の部分がポイントです。t.ycor() で現在のY座標を取得し、そこから 50 を引いた新しいY座標に設定しています。これにより、ループごとにタートルが下に移動し、水平線が等間隔で描かれます。
  • t.penup()t.pendown() を使って、線を描く時と描かない時を制御しています。

例3: sety()setx() を組み合わせた星の描画 (簡略版)

sety()setx() を組み合わせることで、タートルを特定の絶対座標に直接配置し、複雑な図形を効率的に描くことができます。

import turtle

screen = turtle.Screen()
t = turtle.Turtle()
t.speed(3)
t.color("blue", "yellow") # 線の色と塗りつぶしの色を設定

t.begin_fill() # 塗りつぶしを開始

# 星の頂点のY座標のリスト (X座標は後で調整)
# 実際の星の形状に合わせてY座標を調整
y_points = [80, 0, -80, -0, 80] # 例: 上、中央、下、中央、上

t.penup()
t.setx(0) # 最初のX座標を0に設定
t.sety(y_points[0]) # 最初のY座標を設定
t.pendown()

# 星の描画 (gotoを使用する方が一般的だが、setx/setyの組み合わせを示すため)
# 通常は goto(x, y) で一気に移動しますが、ここではsetxとsetyを分けて使います。
for i in range(5):
    # 星の各頂点に移動
    # ここでは、星の点を循環させるための簡単なロジック。
    # 実際の星形描画では角度と距離で描くことが多いですが、
    # sety/setxの利用例として示します。
    # この例では、単純なV字の繰り返しになります
    if i % 2 == 0: # 偶数番目の点 (上または下)
        t.sety(y_points[i])
        t.setx(t.xcor() + 50 * (-1 if i > 0 else 1)) # X座標を適当にずらす
    else: # 奇数番目の点 (中央)
        t.sety(y_points[i])
        t.setx(t.xcor() + 50 * (-1 if i > 0 else 1))

    # より一般的な星の描き方では、
    # t.forward(length) と t.right(angle) を繰り返します。
    # sety/setxを組み合わせる場合、各頂点の絶対座標を計算して
    # t.goto(x_coord, y_coord) を使う方が自然です。
    # このコードはあくまでsety/setxの組み合わせの例として見てください。
    
    # 実際には、t.goto(x_point[i], y_point[i]) のような形で
    # 座標のリストを直接使う方がはるかに一般的です。

t.end_fill() # 塗りつぶしを終了

screen.mainloop()

解説: この例は少し複雑で、sety()setx() を組み合わせて特定の絶対位置にタートルを移動させています。ただし、多くの複雑な図形描画では t.goto(x, y) を使う方が一般的です。sety()setx() は、例えばX座標は固定でY座標だけを変化させたい場合(例2のグリッド)や、Y座標は固定でX座標だけを変化させたい場合に特に便利です。

例4: アニメーション風の落下表現(sety() の連続使用)

sety() をループ内で少しずつY座標を変化させることで、オブジェクトが落下するようなアニメーションを表現できます。

import turtle
import time # 時間を一時停止するために使用

screen = turtle.Screen()
screen.setup(width=600, height=400) # スクリーンサイズを設定
screen.tracer(0) # アニメーションを高速化するため、自動更新をオフにする

ball = turtle.Turtle()
ball.shape("circle")
ball.color("red")
ball.penup()
ball.goto(0, 180) # 初期位置 (画面上部)

y_position = 180
g = 0.5 # 重力定数 (Y座標の変化量)
velocity = 0 # 初速度

# ボールが画面下部に到達するまで落下させる
while y_position > -180: # 画面下端近くまで
    velocity -= g # 速度に重力を加算 (下方向なので減算)
    y_position += velocity # 現在のY座標に速度を加算
    
    ball.sety(y_position) # ボールのY座標を設定
    
    screen.update() # 画面を手動で更新 (tracer(0) の場合必要)
    time.sleep(0.02) # 少し待つ (アニメーションの速度調整)

screen.mainloop()

解説:

  • time.sleep(0.02): 各フレームの間に短いポーズを入れることで、アニメーションの速度を制御しています。
  • y_position += velocity: この行でY座標を少しずつ変化させています。sety() はこの計算された新しいY座標にタートルを配置します。
  • screen.tracer(0)screen.update(): これらはタートルグラフィックスのアニメーションを滑らかにするためのテクニックです。tracer(0) は自動的な画面更新を止め、update() で明示的に更新することで、タートルの動きがカクカクせず滑らかに見えます。


turtle.sety() の代替方法

turtle.goto(x, y) または turtle.setposition(x, y) / turtle.setpos(x, y)

これは最も一般的な代替方法で、タートルを特定の絶対座標 (x, y) に移動させます。sety() がY座標のみを変更するのに対し、goto() はX座標とY座標の両方を同時に設定します。

  • 使用例:

    import turtle
    screen = turtle.Screen()
    t = turtle.Turtle()
    t.speed(1)
    
    t.penup()
    t.goto(-100, 50) # 開始位置に移動 (X=-100, Y=50)
    t.pendown()
    
    print(f"現在の位置 (goto後): X={t.xcor()}, Y={t.ycor()}")
    
    # sety(0) の代わりに goto(t.xcor(), 0) を使う
    print("\nY座標を0に設定 (gotoを使用)...")
    t.goto(t.xcor(), 0) # 現在のX座標を維持しつつY座標を0に
    print(f"設定後の位置 (goto後): X={t.xcor()}, Y={t.ycor()}")
    
    # XもYも動かす場合
    print("\n新しい位置へ (gotoを使用)...")
    t.goto(50, -80) # X=50, Y=-80へ移動
    print(f"設定後の位置 (goto後): X={t.xcor()}, Y={t.ycor()}")
    
    screen.mainloop()
    
  • sety() との比較:

    • sety(new_y): (current_x, new_y) に移動。
    • goto(current_x, new_y): (current_x, new_y) に移動(sety() と同じY座標の変更効果)。
    • goto(new_x, new_y): (new_x, new_y) に移動(X座標も変更する場合)。
  • 特徴:

    • X座標とY座標の両方を一度に指定できる。
    • ペンが下がっていれば、移動中に線が描かれる。
    • sety() の場合、X座標は現在の値を保持しますが、goto() は指定されたX座標に移動します。

turtle.setx(x) と組み合わせて使う

sety() がY座標のみを設定するのに対し、turtle.setx(x) はX座標のみを設定します。これらを組み合わせて使うことで、goto() と同じような効果を得ることができますが、XとYの移動を別々に行うことが意図される場合に便利です。

  • 使用例:

    import turtle
    screen = turtle.Screen()
    t = turtle.Turtle()
    t.speed(1)
    
    t.penup()
    t.goto(0, 0) # 初期位置
    t.pendown()
    
    print(f"初期位置: X={t.xcor()}, Y={t.ycor()}")
    
    # X座標を100に設定
    print("\nX座標を100に設定...")
    t.setx(100)
    print(f"setx後の位置: X={t.xcor()}, Y={t.ycor()}")
    
    # その後、Y座標を50に設定
    print("\nY座標を50に設定...")
    t.sety(50)
    print(f"sety後の位置: X={t.xcor()}, Y={t.ycor()}")
    
    # 結果として (100, 50) に移動する
    
    screen.mainloop()
    
  • 特徴:

    • XとYの変更を独立して制御できる。
    • 各呼び出しの間にタートルの位置を確認したり、他の処理を挟んだりできる。
    • ペンが下がっていれば、setx()sety() の呼び出しの間に線が引かれる可能性があります(ただし、瞬間移動なので見えないことが多い)。

turtle.forward(distance) / turtle.backward(distance) と turtle.setheading(angle) / turtle.left(angle) / turtle.right(angle) を組み合わせる

これは絶対座標ではなく、タートルの現在の向きと相対的な距離を使って移動させる方法です。sety() のように特定のY座標に直接移動させるわけではありませんが、垂直方向の移動を含む様々な動きを生成できます。

  • 使用例 (垂直移動のシミュレーション):

    import turtle
    screen = turtle.Screen()
    t = turtle.Turtle()
    t.speed(1)
    t.penup()
    t.goto(0, -100) # 開始位置 (下の方)
    t.pendown()
    
    print(f"初期位置: X={t.xcor()}, Y={t.ycor()}")
    
    # 真上に移動する
    print("\n真上に150進む...")
    t.setheading(90) # 向きを真上 (90度) に設定
    t.forward(150)   # 150だけ進む (Y座標が150増える)
    print(f"移動後の位置: X={t.xcor()}, Y={t.ycor()}")
    
    # 真下に移動する
    print("\n真下に100進む...")
    t.setheading(270) # 向きを真下 (270度または-90度) に設定
    t.forward(100)    # 100だけ進む (Y座標が100減る)
    print(f"移動後の位置: X={t.xcor()}, Y={t.ycor()}")
    
    screen.mainloop()
    
  • 特徴:

    • タートルの現在の向きに基づいて移動する。
    • 線を描きながら移動するのが主な目的。
    • 垂直な移動をしたい場合は、まずタートルの向きを真上(90度)または真下(270度、または-90度)に設定する必要がある。

解説:

  • t.forward(distance) は、現在の向きに沿って進みます。Y座標を変化させるには、タートルの向きが上または下である必要があります。
  • t.setheading(90) はタートルの向きを上方向にします。
  • 移動中に線を描きたい:

    • turtle.pendown() の後に goto() を使う。
    • sety() は瞬間移動なので、線を描く目的には直接適していません(線を描きたい場合は goto() を使うか、forward() などの相対移動を使うべきです)。
  • 移動中に線を描きたくない(ワープさせたい):

    • turtle.penup() の後に sety() または goto() を使う。
  • タートルの現在の向きに基づいて相対的に移動させたい:

    • turtle.forward(distance)turtle.backward(distance) を使用し、必要に応じて turtle.setheading()turtle.left() / turtle.right() で向きを調整する。
  • 特定の絶対座標 (x, y) に移動させたい:

    • turtle.goto(x, y) が最も簡潔で推奨される。
    • 代替としては t.setx(x) の後に t.sety(y)(またはその逆)。
  • 特定のY座標に直接移動させたい(X座標は現在のまま):

    • 最も直接的なのは turtle.sety(new_y)
    • 代替としては turtle.goto(t.xcor(), new_y)