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

タートルグラフィクス

ここではタートルグラフィクス(Turtle Graphics)という枠組みに基づいて,キャンバスに絵を描くプログラムを作成する方法について説明します.

タートルグラフィクスは1967年にPapertらによって開発されたプログラミング言語Logoに組み込まれた描画の仕組みで(Logo History),プログラミング教育で広く用いられています.

本科目はRubyで動作する「Gtr」というタートルグラフィクスのパッケージを利用します. Gtrは本科目のために担当者が独自に開発したものです. 利用するには標準のRubyにパッケージを追加でインストールする必要があります. そこでこのページのプログラムを動かしてみる場合には,予め「初期設定」を完了させておいてください. なおGtrは一般公開していません(ネットからは入手できません).

もくじ

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

上の項目のうち(*)をつけたものは,まず読み飛ばしても問題ありません. また「亀の描画機能」では描画に利用できる機能を一覧にして紹介していますが,それらの全てを理解しなければプログラムが作れないわけではありません.

はじめに

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

turtle_window

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

プログラムの例

次に簡単なサンプルプログラムを示します. これは黄色の線で正方形(の枠)を描くプログラム(gtr_square.rb )です.なお正方形を描画した後,描画開始時に亀が向いていた方向に亀の向きを戻すようにしています.

require 'gtr/turtle' # Gtrパッケージの読み込み

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  = 800
HEIGHT = 600

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

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

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

# ウインドウを表示する
wrl.open

プログラムの最初に「require」でGtrのパッケージを読み込んでいます. こうすることで,(標準のRubyには含まれていない)Gtrの機能をプログラムで利用できるようになります. それにつづいてプログラムでは亀の動作を定めています(詳細は以下で説明します). プログラムの後半では,キャンバスの大きさの設定,最初に亀がいる場所と向きの指定など, 絵を描くための準備を行っています(「キャンバスの設定など」を参照のこと).

なおプログラムで#からその行の末尾までは「コメント」として解釈されます. コメントにはプログラムを読んで理解するための補足説明を示しています. コメントは人間が読むものです. プログラムを実行したときにコメントの記述はすべて無視されます. そこでコメントの記述内容を変更しても,コメントを(#を含めて)丸ごと削除してもプログラムの動作は変わりません. プログラムにどのようにコメントを書くのかは(文法上許される範囲で)自由に決められます.

プログラムの実行方法

(すでに初期設定が完了しているとして)このサンプルプログラムは次のように実行します.


  $ ruby gtr_square.rb

画面にウインドウが表示されたら,メニュー[Operation]の[Draw]を選ぶことで,プログラムで指示された絵が描かれます. またメニュー[Operation]の[Quit]でプログラムを終了できます.

亀の動作の記述方法

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

include Gtr

class Turtle
  def draw

    # 「def draw〜end」の間に亀の動作を順に記述する

  end
end

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

亀の描画機能

ここではタートル(亀)の描画機能について説明します. 基本となる機能は「前へ進む」(forward)と「向きを変える」(turn)です. 描画に使う色はset_colorで指定します(参考: Colortable(色サンプル)). まずこれらを使うだけでもいろいろな絵を描くことができるでしょう. さらに以下に示す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の円を描く(現在地は円周上の1点となる.円の中心からスタートするのではないことに注意).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)
set_speed(s) 亀の進む速さをsにする.sは1以上の整数で指定する.値が大きいほど速く動く(限界はある).なおMAX_SPEEDと指定すると最高速になる. set_speed(10)
set_speed(MAX_SPEED)
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)
string(msg,bg,pt) 亀の現在位置からキャンバスの右に向かって,msgで指定される文字列を描く(msg="…").文字は(亀の向きとは無関係に)必ず水平方向に描画される.文字の背景色をbgとする(bg=[r,g,b]).背景色を使わない場合にはbgにnilを指定する.文字のサイズをptで定める. string("Hello, World!",[0,255,255],32)
string("Hello, Gtr!",nil,18)
fill { ... } 現在の位置からはじめて,{ ... }の中で亀が動いて囲む部分を塗りつぶす.最初の地点に戻らない場合はfillの中の最後の地点と最初の地点を結んで囲う.{ ... }は2行以上に分けて書いてもよい.なおfillの内部ではset_color,set_weightは無効となる. さらにfill内部では線幅=1に一時的に変更される. またfillの内部にfillは指定できない(fillは入れ子構造にできない). fill {
  forward(160)
  turn(60)
  forward(160)
}
hover { ... } { ... }の中では亀が動いたあとに線を描かない(亀は空中を移動しているものとみなす).{ ... }は2行以上に分けて書いてもよい. hover内部でのfillは無効となる(hover内部ではfillによる塗りつぶしは行わない). hover {
  turnto(180)
  forward(100)
  turn(-60)
  move(10,10)
}
mark 現在の亀の位置に「マーク」を置く.マークを置くと現在の亀の位置と向きを記憶する.マークはいくつでも置ける. markは必ずbackとペアで使うことが想定されている.
back 直前に配置したマークの位置に亀が戻り,マークを置いたときの方向を向く. そのときマークは回収されて,回収したマークは捨てられる(回収したマークの記憶は失われる). 「back」したとき,「hover」していないのであれば線が描かれる. 亀はマークの列を順序づけて憶えていて, 「back」するとその時点で一番新しいマークに戻って回収する. つまりbackするたびにマークを置いた順とは逆順にマークを回収することになる. マークがないときにbackした場合は何も起きない.
hide 亀を画面から消す
show 亀を(再び)画面に表示する
wait(title) ポップアップウインドウに現在位置と向きを表示して, 一時停止する.再開を指示されるまで動かない. ポップアップウインドウにはタイトルとしてtitleも含めて表示する. titleは指定しなくてもよい.その場合は「wait」というタイトルを表示する. なおtitleは'...'のように引用符で括って指定する. 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)
push(obj) データobjを亀の内部のキュー(queue)の末尾に追加する. キューとはデータを順に並べた列である.
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.new 亀を用意する t = Turtle.new

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

機能名 意味
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でダウンロードしたプログラムの内容を見て参考にしてください.

Colortable(色サンプル)(*)

タートルでは描画色をRGB(赤,緑,青)の成分の強さを組み合わせて指定します.

  set_color(r,g,b)

各成分(r,g,b)の値は0〜255の整数で指定します(値が大きいほど,その成分が強くなります). 次のページでR,G,Bの値と色のサンプルを示していますので参考にしてください.

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