[プログラミング演習(Ruby) > タートルグラフィクス]

タートルグラフィクス

もくじ

  1. はじめに
  2. プログラムの例
  3. 亀の動作の記述方法
  4. 亀の描画機能
  5. キャンバスの座標系
  6. 亀のデータ入出力機能(*)
  7. その他の機能(*)
  8. サンプルプログラム集(*)

ここではGtrというタートルグラフィクスパッケージを使って絵を描く プログラムを作成する方法を説明します. もくじの項目のうち(*)をつけたものは,まず読み飛ばしても問題ありません. また 「亀の描画機能」では描画に利用できる機能の一覧を紹介していますが,それらの全てを理解しなければプログラムが作れないわけではありません.

はじめに

タートルグラフィクスとは,画面上のタートル(亀)を動かして,亀の通った跡に線をひくことで絵を描く枠組みです. 亀の動きをプログラムで指示することでさまざまな絵を描くことができます. 次にタートルグラフィクスプログラムの実行画面の例を示します.

turtle_window

亀の動作の基本となるのが「前へ進む」と「向きを変える」という指示です. ただしこれらだけでは描ける絵が限定されますので, ここで紹介するタートルグラフィクスパッケージGtrでは, たとえば,線を描かずに移動すること,あるいは指定した範囲を塗りつぶすことなどができるようになっています. 詳しくは「亀の機能」を参照してください.

Gtrは筆者が独自に開発したパッケージです.標準のRubyでは使えません. Gtrパッケージを追加導入する必要があります. なおGtrパッケージは配布していません.

プログラムの例

次に簡単なサンプルプログラムを示します. これは黄色で正方形を描くプログラム(gtr_square.rb )です.

require 'gtr/turtle'

include Gtr

## 亀の動作の記述
class Turtle
  def draw

    # アニメーションのスピード設定
    set_speed(10)

    # 線の色指定
    set_color(255,192,0)

    # 動作記述(正方形を描く)
    forward(200) # 200進む
    turn(90)     # (反時計回りに)90度回転する
    forward(200) 
    turn(90)    
    forward(200) 
    turn(90)    
    forward(200) 
    turn(90)    
  end
end

# キャンバスの幅と高さ
WIDTH  = 640
HEIGHT = 480

# キャンバスを用意する(広さ=WIDTHxHEIGHT)
wrl = World.new(WIDTH,HEIGHT)

# 亀を用意する
t = Turtle.new()

# キャンバス上に亀を置く
# t: 亀
# (WIDTH/2,HEIGHT/2): 亀を置く場所
# 0: 亀の向き(0を上向きとして反時計回りの角度で指定する)
wrl.register(t,WIDTH/2,HEIGHT/2,0) 

# 画面を表示する
wrl.open

このサンプルプログラムは次のように実行します. 画面が表示されたら[Operation]→[Draw]とすれば絵を描くことができます. また[Operation]→[Quit]でプログラムを終了できます.


  $ ruby gtr_square.rb

プログラムの前半で亀の動作を記述しています. 演習ではこの部分を変更してさまざまなプログラムを作成することになります.

なお後半では,キャンバスの大きさの設定,亀を置く場所の指定など, 絵を描くための準備を行っています(「キャンバスの設定など」を参照のこと).

亀の動作の記述方法

亀の動作は次の形式で記述します.

include Gtr

class Turtle
  def draw

    # この中(def draw〜endの間)に亀の動作を記述する

  end
end

「def draw」から「end」までで亀の動作を書きます. 動作は好きなだけ書くことができます. 動作スピード,線の色,線の幅,線の種類などの指定, あるいはメッセージの表示やデータの取り込みも「def draw」から「end」の間に記述します. プログラムを実行すると,記述した内容が上の行から順に読み取られて,その指示の通りに順番に亀が動くことになります. 亀の具体的な動かし方については別途説明します(「亀の描画機能」を参照のこと).

もう一つの記述方法(*)

次のように亀の動きを記述することもできます.

include Gtr

# 亀を先に用意する
t = Turtle.new

def t.draw
  # この中(def draw〜endの間)に亀の動作を記述する
  # (classとendは不要なので注意)
end

# この後にTurtle.newは不要なので注意

複数の亀に別々の動作をさせる場合には,後者の方法で, それぞれの亀についてdrawを記述します.

include Gtr

# 亀を先に準備する
t0 = Turtle.new
t1 = Turtle.new

# 亀の動きをそれぞれ記述する
def t0.draw
  # この中(def draw〜endの間)に亀t0の動作を記述する
end

def t1.draw
  # この中(def draw〜endの間)に亀t1の動作を記述する
end

# キャンバスの幅と高さ
WIDTH  = 640
HEIGHT = 480

# キャンバスを用意する(広さ=WIDTHxHEIGHT)
wrl = World.new(WIDTH,HEIGHT)

# 亀をそれぞれキャンバスに配置する
wrl.register(t0,WIDTH/2,HEIGHT/4,0) 
wrl.register(t1,WIDTH/4,HEIGHT/2,180) 

wrl.open

注意

亀ごとにdrawを定義する場合,以下で説明している機能でのデータ指定の方法が若干変わります.

標準のdrawの場合 亀ごとのdrawの場合
ROTATE_LEFT,ROTATE_RIGHT Turtle::ROTATE_LEFT,Turtle::ROTATE_RIGHT
MOVE_FREE,MOVE_TOEDGE,MOVE_RETRY Turtle::MOVE_FREE,Turtle::MOVE_TOEDGE,Turtle::MOVE_RETRY
MAX_SPEED Turtle::MAX_SPEED

テンプレートファイル(*)

亀の動作以外の部分を書いたプログラムのテンプレートを用意しました. 名前を適宜変えて保存して利用してください.

亀の描画機能

ここではタートル(亀)の描画機能について説明します. 基本となる機能は「前へ進む」(forward)と「向きを変える」(turn)です. 線の色はset_colorで指定します. まずこれらを使うだけでもいろいろな絵を描くことができるでしょう. さらに以下に示すfill,hover等々を利用すればさらにバラエティに富んだ絵を描けるようになります. なお上の例でも指定してあるように最初に描画スピードを設定(set_speed)しておくとよいでしょう.

機能名 意味
forward(dist) distだけ前に進む.負の値を指定した場合はうしろに下がる. forward(100)
turn(degree) degree度だけ反時計回りに回転する. 負の値を指定した場合は時計回りに回転する turn(30)
move(dx,dy) 現在地から横(x方向)にdx,縦(y方向)にdyだけ離れた点に進む.亀の向きに関わらず,キャンバスの座標系を基準とすることに注意せよ.なお移動前と移動後で亀の向きは変わらない. move(60,-30)
toward(fore,right) 現在地から前にfore,右にrightだけ離れた点に進む.moveとは異なり,現在の亀の向きを基準とすることに注意せよ.なお移動前と移動後で亀の向きは変わらない. toward(30,-70)
moveto(x,y) 点(x,y)に移動する.ここで指定する値については「キャンバスの座標系」を参照のこと.なお移動前と移動後で亀の向きは変わらない. moveto(0,0)
turnto(d) 方位dに向きを変える.ここで指定する値については「キャンバスの座標系」を参照のこと. turnto(180)
circle(r,rot_dir) 現在地から半径rの円を描く.rot_dirはROTATE_LEFTかROTATE_RIGHT,つまり左回りか右回りかのいずれかを指定する. circle(50,ROTATE_RIGHT)
arc(r,a,is_fan) 現在地から半径rで中心角a度の円弧か扇形を描く.aが正なら左回り,負なら右回りに描く.is_fanにはtrueかfalseを指定する.trueなら扇形を描く.falseなら円弧だけを描く. arc(200,-120,true)
fill { ... } 現在の位置からはじめて,{ ... }の中で亀が動いて囲む部分を塗りつぶす.最初の地点に戻らない場合はfillの中の最後の地点と最初の地点を結んで囲う.{ ... }は2行以上に分けて書いてもよい. fill {
  set_color(255,32,32)
  forward(160)
  turn(60)
  forward(160)
}
hover { ... } { ... }の中では亀が動いたあとに線を描かない(亀は空中を移動しているものとみなす).{ ... }は2行以上に分けて書いてもよい. hover {
  turnto(180)
  forward(100)
  turn(-60)
  move(10,10)
}
set_color(r,g,b) 描く線の色を(r,g,b)に設定する.r,g,b(赤,緑,青成分)はそれぞれ0〜255の整数で与える. set_color(255,192,0)
set_weight(w) 描く線の太さをwに設定する.wは0以上の整数で与える.0の場合は線を描かない. set_weight(2)
set_style(s) 描く線の種類をsに設定する.sはDC::SOLID(実線),DC::DASHED(破線)のいずれかを指定する. set_style(DC::DASHED)
set_speed(s) 亀の進む速さをsにする(アニメーションを行うときのみ有効).sは1以上の整数で指定する.値が大きいほど速く動く(限界はある).なおMAX_SPEEDと指定すると最高速になる. set_speed(5)
hide 亀を画面から消す
show 亀を(再び)画面に表示する
anchor 現在の亀の位置にanchorを置く(現在の亀の位置と向きを記憶する).後でrewindによりanchorの位置に戻ることができる(向きも戻る).anchorはいくつでも置ける.2個以上anchorを置いた場合,rewindでは直前のanchorに戻ることになる.
rewind (直前の)anchorを置いた場所に戻る.そのときの方位を向く.戻るとanchorは回収されてなくなる.anchorがない場合には何も起きない.
mark anchorの別名.現在の位置と向きを記憶する.後でbackすると記憶した位置に戻ることができる(向きも戻る).いくつでも記憶できる.
back rewindの別名.markした場所に戻る.そのときの方位を向く(戻ったら,その場所についての記憶はなくなる).二つ以上記憶している場合は直前にmarkした場所に戻る.何も記憶していない場合には何も起きない.
wait(title) ポップアップウインドウに現在位置と向きを表示して, 一時停止する.再開を指示されるまで動かない. ポップアップウインドウにはタイトルとしてtitleも含めて表示する. titleは指定しなくてもよい.その場合は「wait」というタイトルを表示する. wait('Here!')
pos 亀の現在位置を得る. x,y=pos()
dir 亀の現在の向きを得る. d=dir()
canvas_size キャンバスの幅と高さを得る. w,h=canvas_size()
on_canvas?(margin) 亀がキャンバスの縁からx,y方向ともmargin以上離れているかどうかを判定する.marginは省略できる(省略した場合は0とみなされる). on_canvas?(20)
on_canvas?
set_move_policy(pol) 亀の動きを制御する.polはMOVE_FREE,MOVE_TOEDGE,MOVE_RETRYのいずれか.MOVE_FREEの場合は制限なし.MOVE_TOEDGEの場合は移動先がキャンバスの外になるときにはキャンバスの縁まで移動する.MOVE_RETRYの場合は移動先がキャンバスの外になるときには移動しない. set_move_policy(MOVE_RETRY)
stop(target) 亀targetの動作を終了させる.targetには対象の亀かその番号を指定する.targetが与えられない場合は,自分自身の動作を終了する.
pause(target) 亀targetを一時停止させる.targetには対象の亀かその番号を指定する.targetが与えられない場合は,自分自身が一時停止する.
wakeup(target) (一時停止中の)亀targetの動作を再開させる.targetには対象の亀かその番号を指定する.targetが与えられない場合は,自分自身の動作を再開する.
track(target,d) 亀targetに向かってd進む.targetには対象の亀かその番号を指定する.
distance_to(target) 亀targetまでの距離を得る.targetには対象の亀かその番号を指定する.
hit?(target,margin) 亀targetまで距離margin以内かどうかをチェックする.targetには対象の亀かその番号を指定する.marginを省略した場合には亀targetとぶつかったかどうかをチェックする.なお移動中は判定を行わない.
tid 亀の番号を得る
push(obj) objをデータキューの末尾に格納する
retrieve データキューの先頭のデータを読み出す.データキューに何もなければ,nilが得られる. obj=retrieve()
clear_queue データキューを空にする

キャンバスの座標系

キャンバスでは原則として左下角が原点(0,0)となっています. 右向きにx軸,上向きにy軸がとられています. またy軸正方向を0として反時計回りで角度(degree)により方位を表します. 0が北,90が西,180が南,270が東になります. 360は,また北になります. もちろん中間の方位も角度で表すことができます.

なお座標系の原点を別途指定することもできます(以下の「キャンバスの設定など」を参照のこと).

亀のデータ入出力機能(*)

タートルグラフィクスでデータを読み込んだり,メッセージを表示したりする方法を紹介します.

機能名 意味
say("メッセージ") 画面にメッセージを表示する. say("こんにちは!")
alert("警告メッセージ") 画面に警告メッセージを表示する. alert("データの指定方法が不適切です.")
ask("質問文") 質問に対する答(文字列)を得る. yourname=ask("お名前を教えて下さい.")

その他の機能(*)

Gtrパッケージにはここまでで紹介したもの以外にもさまざまな機能もあります. なお演習を行うために以下で紹介する機能について理解する必要はありません.

亀のそのほかの機能(*)

Turtleには次のような機能もあります. どのプログラムでもTurtle.newは必ず使うことになります. なおここで紹介していない機能もあります. サンプルプログラムにはそのような機能を使っているものもあります.

機能名 意味
Turtle.new 新しい亀を用意する. t = Turtle.new
Turtle.find(k) (既に存在している)番号kの亀を得る
Turtle.up_tempo(m) 全ての亀の動作のテンポをm倍速にする. Turtle.up_tempo(3)
Turtle.set_tempo(t) 全ての亀の動作のテンポをtにする. Turtle.set_tempo(0.025)
Turtle.reset_tempo 全ての亀の動作のテンポを初期値に戻す.

キャンバスの設定など(*)

キャンバスを作る,亀をキャンバスに配置するといったキャンバスに関する設定を行うには,キャンバスの次のような機能を使います.

機能名 意味
World.new(width,height,cx,cy) width×heightのキャンバスを作成する.cx,cyは省略できる.cx,cyを省略した場合は「キャンバスの座標系」で説明したようにキャンバスの左下角が原点となる.cx,cyを指定した場合,座標系の原点をキャンバスの(cx,cy)の位置に設定する. 位置の解釈は「キャンバスの座標系」に従う. wrl = World.new(800,600)
wrl = World.new(800,600,400,300)
register(t,x,y,d) 亀tを(x,y)に配置する.亀の向きをdに設定する. wrl.register(t0,x0,y0,d0)
open キャンバスを画面に開く.プログラムでは全ての準備が整った後,必ずopenを実行する.openして はじめて画面上での操作ができるようになる. wrl.open
show_axis 座標軸を描画する. wrl.show_axis

サンプルプログラム集(*)

以下のサンプルプログラムを用意しました. ダウンロードして実行してみてください. またemacsでダウンロードしたプログラムの内容を見て参考にしてください.

[プログラミング演習(Ruby) > タートルグラフィクス]