レッスン17

タートルグラフィックスプログラムの構築

【以下、【】内は訳者が勝手に付け加えた部分です。なお、少し古すぎると思われた事柄で省略した部分があります。】

さて、グラフィックスプログラムを見ることができます。名前はTurtle(タートル)です。 それはたくさんの複雑な曲線図形と、このプログラム内のいくつかの定義からミニ-Logo言語をつくり出すことができる方法を定義しています。 ツールボックス【カーボン】コールを用いる機会も、もう少し多くなるでしょう。 ソースファイルは‘Turtle’という名前で、‘Demo folder’に入っています。

まず、全体を挙げておきます。それから細かい点を見ていきましょう。

\ Turtle Graphics Objects for Demo

need	sin

decimal

\ Class PEN defines a turtle-graphics pen.

syscall GetPenState
syscall SetPenState
syscall Line
syscall LineTo

:class	PEN	super{ object }
68k_record{			\ These first 5 ivars comprise a PenState structure
point	PnLoc		\ location of pen
point	PnSize		\ width, height
int	PnMode
var	PnPatLo
var	PnPatHi
}
angle	Direction
point	homeLoc
int	maxReps
int	initLen
int	deltaLen	\ change in len
	int	deltaDeg	\ change in angle

:m GET:    ^base GetPenState ;m		\ Save state here
:m SET:    ^base SetPenState ;m		\ Restore from here

:m TURN: ( deg -- )	+: direction ;m

:m UP:	90 put: direction ;m

:m MOVETO:	\ ( x y -- )	Draws a line to x,y if pen shows
set: self LineTo get: self ;m

:m MOVE: { dist -- }	\ Draws dist bits in current direction
set: self cos: direction dist * 10000 /
sin: direction dist * 10000 /   negate
Line get: self ;m

:m GOTO:	\ ( x y -- )	Goes to a location without drawing
put: PnLoc ;m

:m CENTER:	\ ( x y -- )	Sets the center coordinates
put: homeLoc ;m

:m HOME:	\ ( -- )		Places pen in center of Mops window
get: homeLoc goto: self   ;m

:m SIZE:	\ ( w h -- )	Sets size in pixels of drawing pen
put: PnSize ;m

:m INIT:	\ ( x y w h mode -- )
put: PnMode put: PnSize   put: PnLoc ;m

:m PUTRANGE:	\ ( initlen dLen dDeg -- )	Sets parameters
put: deltaDeg put: deltaLen put: initLen ;m

:m PUTMAX:   ( maxReps -- )    put: maxReps ;m

:m CLASSINIT:   get: self   200 put: maxReps ;m

:m SPIRAL: { \ dist degrees delta reps -- }
	\ Draws a spiral of line segments - Logo POLYSPI
home: self
get: initLen -> dist get: deltaLen -> delta
get: deltaDeg -> degrees   0 -> reps
BEGIN	1 ++> reps reps get: maxReps <
WHILE	dist move: self   degrees turn: self
	delta ++> dist
REPEAT ;m

:m DRAGON:	\ ( n -- )   Dragon curves from Martin Gardner
dup
NIF	get: deltaLen move: self drop
ELSE	dup 0>
	IF	dup 1- dragon: self
		get: deltadeg turn: self
		1 swap -   dragon: self
	ELSE
		-1 over -   dragon: self
		360 get: deltadeg - turn: self
		1+ dragon: self
	THEN
	THEN ;m

:m LJ: { \ reps -- }	\ Draws an infinite Lissajous figure
up: self   0 -> reps
get: initLen get: direction * cos 120 /         getX: homeLoc +
get: deltalen get: direction * sin 120 / negate getY: homeLoc +
goto: self
BEGIN   1 ++> reps reps get: maxReps <
WHILE
	get: initLen get: direction * cos 120 / getX: homeLoc +
	get: deltaLen get: direction * sin 120 / negate
	getY: homeLoc +   moveTo: self
	get: deltaDeg turn: self
REPEAT ;m
;class

\ Define a Smalltalk Polygon object as subclass of Pen

:class POLY super{ pen }
	int	Sides			\ # of sides in the Polygon
	int	Length			\ Length of each side

:m DRAW: { \ turnAngle -- }
360 get: sides /   -> turnAngle
get: sides 0
DO	get: length move: self
	turnAngle turn: self
LOOP ;m

:m SIZE:	\ ( len #sides -- )	Stores sides and goes to Home
get: self put: sides put: length
home: self   up: self ;m

:m SPIN: { \ reps -- }		\ Spins a series of polygons around a point
home: self 10 get: initLen size: self
0 -> reps
BEGIN	reps get: maxReps <
WHILE	draw: self get: deltaDeg turn: self
	get: deltaLen +: length 1 ++> reps
REPEAT ;m

:m CLASSINIT:		\ Default Poly is 30-dot triangle
30 3 size: self 100 put: maxReps ;m

;class

\ Create a pen named Bic
Pen	BIC

\ Create a Polygon named Anna
Poly	ANNA
60 4 size: Anna

プログラムを詳しく見ていきましょう。
need sin
この陳述は、Sin ファイルがこのファイルより前にロードされることを確証します。 このファイルではファイル Sinで定義されたAngleクラスを使うことになります(前のレッスンで説明しました)。
decimal
プログラムは、続く全ての数値は10進表示であるとの宣言をもって始まります。 これによって以後の数値は10進数であることが確証されます。以前に別の基数が用いられていた場合を慮ってのことです。 ついでながら、プログラムの部分毎に異なる基数を用いることもできます。 しかし、全体としては10進にしておいて、16進数についてはその前にドル記号と空白とをおく($ AE9F のように)ようにした方が、 いま現在どの基数の下で作業しているのかが憶え易くなるでしょう。
syscall GetPenState
syscall SetPenState
syscall Line
syscall LineTo
GetPenState, SetPenState, Line および LineTo は、Macのツールボックス(カーボン)の呼出しです。 わたしたちは、あなたのMopsプログラムで可能な全てのツールボックスコールについて説明したいとは思いません。 というのは、それはあまりにも数が多いからです。しかし、実際に利用するものについては説明が必要です。 ワード‘syscall’は、Mopsシステムに対して、あなたが、‘syscall’の後に来る名前をもったツールボックスコールを利用しようとしていることを知らせます。 これは、Mopsがこの呼出しを正しくコンパイルするのに必要な情報を含んでいます。

syscallについて知っておくべき重要なことは次の通りです。:
ツールボックス呼出しをしようとする場合は、いつもsyscall宣言を使わなければなりません。この宣言は、定義の外で、その呼出しを実施するワード定義よりも前に行わなければなりません。ひとつの呼出しについてsyscall宣言を複数回 -- 例えば、異なるファイルの中で -- 行っても問題ありません。後の宣言は無視されます。 実際、上のsyscallのうちの三つは既にQD (QuickDraw)ファイルで定義されています。 しかし、それらの全てをここに置くことによって、何の不利益もない上、QDファイルに変更があった場合でも、このコードはなお動くことになります。
syscallに続く名前は、ケースセンシティブ(大文字と小文字が区別される)です。 これはMopsで大文字か小文字かが問題になるほぼ唯一の局面です。 これは、AppleがMac上のツールボックス呼出しを処理する際の方法のせいで、そうしなければならないのです。 ですから例えば、上で
syscall getpenstate
とやった場合には、コンパイル時に、Mopsがその名前を発見できない旨のエラーメッセージを受け取ることになるでしょう。
Carbonドキュメンテーションで言及されている全てのツールボックスルーチンがMopsから利用可能なわけではありません。 というのは、それらのうちのいくつかは実際にはMacOSには組み込まれておらず、CodeWarriorやGCC、その他のコンパイラーによって提供されるものだからです。 Carbonドキュメントにあるツールボックスルーチンに対応するコードがMacOS内にない場合には、Mopsはコンパイルタイムエラーメッセージを表示するでしょう。
また、syscallのデータは若干古くなっており、比較的新しいCarbonルーチンの中には、必要なデータが含まれていないため、 コンパイル時にエラーが表示されることもあります。 その場合には、Carbonライブラリーを通常のダイナミックライブラリーとして利用することができます(具体的な方法については、第二部参照)。 【この項目はCarbon+0S Xに合わせて変えてあります。】
:class	PEN	super{ object }
ここが、このプログラムのための主要なクラスの定義の始まりです。 このクラスは、Macのスクリーンに描画を行うペンの特性を定義しています。 ドローイングペンをMopsのオブジェクト指向環境で定義することによって、スクリーン(例えばウィンドウ)の与えられた区画に対象を描画するひとつのペン以上のものを手にすることができることは、指摘しておくべきでしょう。Macのツールボックスそれ自体は、このパワーを与えてはくれません。 Mopsのようなオブジェクト指向言語を用いることの追加的ボーナスと考えましょう。 お分かりのように、このクラスにはたくさんのインスタンス変数があります。あるものはpoint(点)であり、 あるものはInteger(2バイト整数)、いくつかはVar(4バイト整数変数)で、ひとつはAngleクラス(前レッスン)で定義されたangle(角)です。

コメントが示唆するように、最初の5つのインスタンス変数は、Macintoshツールボックスのデータ構造"PenState"の成分です。 これはGetPenStateとSetPenStateの呼出しに必要なデータ構造で、FrameRectが長方形(Rect)を必要としたのと同様です(レッスン 5)。 PenState変数が何であるのかの詳細については、Inside MacintoshのQuickDrawの章が最良の資料です。【Carbonのドキュメントにも記載されています。】 PenStateは次の四つの変数を含むことがわかるでしょう:pnLoc(点座標)、pnSize(ペンがある場所の幅と高さのピクセル数を示す点座標 -- (0,0)からみて)、pnMode(整数)およびpnPat(ペンパターンの8バイト表現)。 対応する変数は、このクラスから生成されるすべてのオブジェクトがその引数を正しい場所に正しい順序で格納するように設定されています。

PnPatが分割されている理由は、既定義データ構造クラスから利用できる最大の基礎データ構造が4バイト幅:VARだからです【64Bit版では8バイト幅変数zVARがあります】。 このとき我々にできることは、8バイトのpnPat変数を二つの4バイト切片に分けて、PnPatLoおよびPnPatHiと呼び。PnPatHiに左側のバイト値を格納することです。

残りのインスタンス変数は、このクラスのメソッド定義内で、その他の目的にために用いられます。このクラスを一から作ろうというのであれば、メソッド定義の間に必要であるとわかったものを、新しいインスタンス変数としてこのリストに挿入していくということになるでしょう。
:m GET:    ^base GetPenState ;m		\ Save state here
:m SET:    ^base SetPenState ;m		\ Restore from here
これら二つのメソッドは、このクラスが何かをスクリーン上に描画するときにはしばしば利用されることになるでしょう。 初めの"GET:"はペンの状態(Pen State)の変数をMacintoshのツールボックスから、オブジェクトのインスタンス変数へとコピーします。 これは与えられた瞬間のパラメターのスナップショットをとるようなものです。 ですから、ペンを点x,yに移動した後に、"GET:"はPenStateの状態をオブジェクトのメモリースペースに保存します。 後で、移動を止めたところを拾い上げるときには、引数を"SET:"することができます。これは引数をオブジェクトのメモリーからツールボックスにコピーします。

PenState変数はオブジェクトの"プライベートデータ"内に保存されるので、他のオブジェクトが同じツールボックスルーチンを、最初のオブジェクトの引数を破壊することなく、利用することができるのです。

例えば、座標(1,1)にあるScripto1という名前のPenクラスのオブジェクトを設置するようツールボックスに命令して、Scripto1のデータ領域にその座標を保存したならば、Scripto1のデータに影響を与えることなく、(100,200)にあるScripto2を設置するようにツールボックスに命ずることが自由にできるのです。 後になって、Scripto1で作業する必要になったときには、"SET:"コマンドがScripto1の最後の位置をツールボックスに思い出させます。
:m TURN:	\ ( deg -- )
	+: direction ;m
...
...
続く12個のメソッドは、このクラスのどのオブジェクトにも影響を与える引数の操作を扱います。 例えば、"TURN:"は、オブジェクトのDirectionインスタンス変数に格納された値をこのメッセージに渡された角度数値の分だけ増加させます(+: Direction)。例えば、:
30 turn: Scripto1
Directionインスタンス変数は、前レッスンのsin:とcos:に利用されます。 これらは、359度より大きい角度や0より小さい角度の値を正しく操作します。 この理由のため、"TURN:"は新しいDirectionが0-359度の間にあるかどうかを気にする必要はありません。

"UP:" は単にオブジェクトのDirectionインスタンス変数のデータセルに90を置くだけです。 このことは前レッスンで見たように上方をさす角度が90度であることと一貫しています。 これはこのクラスのペンオブジェクトで描画されたオブジェクトの向き付けをリセットするための位置決めメッセージで利用されることになります。

"MOVETO:"メソッドには、LineToツールボックスの呼出しがあります。 LineToクイックドロー手続は、Inside Machintoshで説明されているように、現在のペン位置(set: selfによってツールボックスにセットされたもの)から、二つの引数で特定される座標点へ向けて直線を描画します。 描画が終了するとすぐ、新しいペンの状態はオブジェクトのメモリーに保存されます(get: self)。

"MOVE:"メソッドは別形式の直線描画を提供します。 現在のペン状態はオブジェクトのインスタンス変数からツールボックスにコピーされます。 それから、現在の方向(オブジェクトのDirectionインスタンス変数がこの情報源になります)の余弦にピクセル値で測った距離がかけ算され、 それから10.000で割り算され(正弦*余弦値は使いやすいように10,000倍されていたことを思い出してください)、 目的地点のx座標が得られます(これはまだスタックに残っています) y座標は37行目の演算で計算されます。 最後に、この二つの座標がひとつのセルにパックされ、QuickDrawルーチンであるLineに送られます。これは新しい直線を描画します。 描画が終了したあと、ペン状態はオブジェクトのメモリーに保存されます(get: self)。

次の四つのメソッド"GOTO:"、"CENTER:"、"HOME:"および"SIZE:"は、大部分は名前からわかるでしょう。 "HOME:"を除くすべては、特定のインスタンス変数 -- ペン状態のいくつかの値に影響するものもあります -- に新しい値を格納します。 "HOME:"は単に、"CENTER:"メソッドによって最も最近格納された値を取り出し、Penクラスのオブジェクトをその場所に移動するだけです。 "CENTER:"に渡した値は、表示用ウィンドウのサイズに依存します。なぜなら、座標はウィンドウの左上角からの相対座標で、スクリーンのどの位置に洗われるか関係しないからです。(比較のためにいえば、最小のMacスクリーンは横512ピクセル、縦342ピクセルです。)

"INT:"によって、オブジェクトはひとつのメッセージで三つのペン状態引数(mode,sizeおよびlocation)まで特定できるようになります。 そのうちのたった一つだけが変更される場合であっても、すべての引数がメッセージと共に送られなければなりません。

"PUTRANGE:"メソッドはオブジェクトのインスタンス変数スロットに値を格納し、 これはこのプログラムの後の部分で装飾的なグラフィックのための引数として利用されることになります。 名前は、角度の変分(change (delta) in degree)、長さの変分(change in length)、初期長(initial length)に対応しています。

"PUTMAX:"はいくつかの図形が行う繰り返しの回数の最大値を設定することができるメソッドです。 引数の効果は、図形それ自体に到達したときに、もっと明らかになるでしょう。

次ぎにくるのが今では周知の"CLASSINIT:"メソッドで、これはこのクラスのオブジェクトが生成されるときに実行されます。 これは現在のペン状態パラメターをツールボックスからコピーしオブジェクトの初めの五つのインスタンス変数に保存します(ツールボックスはこれから始めます) (get: self)。最後に、そのオブジェクトのmaxRepsを200に設定します。
:m SPIRAL: { \ dist degrees delta reps -- }
...

:m DRAGON:	 \ ( n -- )   Dragon curves from Martin Gardner
...

:m LJ: {  \ reps -- }	 \ Draws an infinite Lissajous figure
...
これら三つのメソッドは、次の三つのタイプの図像の数学的計算のMops版であるといえます。三つのタイプとは、螺旋(spiral)、ドラゴン曲線(dragon curves)、そして、リザージュ(Lissajours)図形です。 私達のここでの議論のためには、これらのグラフィックルーチンの内部の働きを理解することは重要ではありません。 もちろん、そうしたければ、手続を追跡してもよいでしょう。

しかし注意してもらいたいのは、"SPIRAL:"(と"LJ:")での局所変数の使い方です。 中括弧内のバックスラッシュは、以下の名前が、名前付き入力引数ではなくて、局所変数であることを表します(上の"MOVE:"参照)。 以前のレッスンで述べたように、局所変数名は厳格にその定義内でのみ利用され、同じ定義内の名前付き入力引数とは関係を持ちません。

"SPIRAL:"メソッドは四つの局所変数を宣言しています:dist, degree, deltaそしてreps.
home: self
はペンを現在の描画ウィンドウの中央に移動します。
get: initLen -> dist get: deltaLen -> delta
Distとdeltaの値は、そのオブジェクトの二つのインスタンス変数、initLenとdeltaLenから最初に値が取り出され、 それから、それらの対応する局所変数へと(->オペレーションで)格納されることによって与えられます。
get: deltaDeg -> degrees   0 -> reps
ここで第三の局所変数degreeが、deltaDegインスタンス変数の値がそのオブジェクトのメモリーから取り出された後、その値を得ます。 Repsは0に初期化され、maxRepsと比較するためのカウンターとして利用されます。 ひとたびこれらの局所変数が値を格納されると、それらは、次のコードに見られるように、そのメソッド全体を通じて、計算に必要とあらばいつでも利用することができます。:
BEGIN	1 ++> reps reps get: maxReps <
WHILE	dist move: self   degrees turn: self
	delta ++> dist
REPEAT ;m
局所変数なしでは、計算のために正しい値を正しい位置にとどめるのにかなりの量のスタック操作のためのアレンジが必要となります。 それは複雑な式をMopsに移す作業も単純化してくれます。というのは、演算の中で自分にわかりやすい値の名前を用いてメソッドを構成することができるからです。

これは、もちろん、プログラムは、"SPIRAL:"セレクターメッセージを送ることができるようになるには、その前にinitLen、deltaLenおよびdeltaDegに値をロードしなければならないということを意味します。 しかし、この理由のため、"PUTRANGE:"がもっと前に定義されているのです。
;class
でPenクラスの定義は終わります。
\ Define a Smalltalk Polygon object as subclass of Pen

:class POLY super{ pen }
...
次のセクションはもうひとつのクラス定義です。このクラスPolyは、Penのサブクラスですから、Penのメソッドとインスタンス変数を継承します。 したがって、Polyクラスのオブジェクトを生成すれば、それに"MOVE:"や"HOME:"のようなセレクターをもつメッセージを送ることができます。
int	Sides		\ # of sides in the Polygon
int	Length		\ Length of each side  
Polyクラスは、二つの追加的インスタンス変数をもっています。どちらも整数です。 このクラスのオブジェクトを生成するとき、追加的インスタンス変数が、Penクラスから継承されたインスタンス変数のリストに追加されます。 ひとつのインスタンス変数はこのクラスから生成されたポリゴン(多角形)オブジェクトの辺の数に対応します。 もうひとつは、各辺の長さ(ピクセルで)です(すべての辺は同じ長さです)。
:m DRAW: { \ turnAngle -- }
	360 get: sides /   -> turnAngle
	get: sides 0
DO	get: length move: self
	turnAngle turn: self
LOOP ;m
このメソッドはPenクラスで定義された"MOVE:"と"TURN:"メソッドの拡張です。 初めに360を辺の数で割ることによって方向転換の角度が計算され、局所変数turnAngleに保存されます。 "DRAW:"は続いてDO...LOOPを設定し、これが実際の多角形の描画を実行します。 Sidesインスタンス変数をループの境界として用いて、まずひとつの辺が描画されます(GET: Length MOVE: self)。 それからturnAngleの分だけ方向が変えられます。この、描画--方向転換アクションは指標値がこのループの境界値に等しくなるまで繰り返されます。
:m SIZE:	\ ( len #sides -- )	Stores sides and goes to Home
get: self put: sides put: length
home: self   up: self ;m
"SIZE:"はこのサブクラスのために再定義されています。 これは二つの引数をとります。:その多角形の各辺の長さと辺の数です。 "GET: Self"は、新しいPolyオブジェクトのサイズを特定するときに、 現在のペン状態をオブジェクトのPenStateインスタンス変数にコピーします(SIZE:は新しいPolyオブジェクトに送る最初のセレクターとなるでしょう。そして、それはPenState変数をそのインスタンス変数の中に直ちに必要とします)。 サイズの引数はそれぞれ対応するインスタンス変数、SidesとLengthに格納されます。 このメソッドもまたオブジェクトをホームポジションに置き(PenクラスのHOME:メソッドで定義されているように)、スクリーンの上方向に方向を向けます(PenクラスのUP:メソッドによります)。
:m SPIN: { \ reps -- }	\ Spins a series of polygons around a point
home: self 10 get: initLen size: self
0 -> reps
BEGIN	reps get: maxReps <
WHILE	draw: self get: deltaDeg turn: self
	get: deltaLen +: length 1 ++> reps
REPEAT ;m
"SPIN:"メソッドは中心点周りに多角形の系列を描画し、あたかもそれらが回転しているかのように見せるルーチンです。 このメソッドは、ひとつの局所変数repsをもっていることに注意してください。これはBEGIN...WHILE...REPEATループを通じて、 繰り返しの数のためのカウンターとして利用されます。
:m CLASSINIT:	\ Default Poly is 30-dot triangle
30 3 size: self 100 put: maxReps ;m
最後に、Polyクラスのオブジェクトの初期設定が"CLASSINIT:"で設定されます。 別様に指定されない限り、Polyオブジェクトは三つの辺をもつ多角形であり、各辺は30ピクセルの長さがあります。 このメソッドも、インスタンス変数maxRepsを100にセットします。
\ Create a pen named Bic
Pen	BIC
 
\ Create a Polygon named Anna
Poly	ANNA
60 4 size: Anna
これらは上でちょうど定義されたクラスから生成されたオブジェクトの二つの例です。 初めのBicはPenクラスのオブジェクトです。 AnnaはPolyクラスのオブジェクトです。 最後の行で、Annaは、そのデフォルトの30ピクセル三角形から、一辺が60ピクセルの四角形(辺は四つ)に変えられています。

Tutleで実験する

さて、あなたはTurtleプログラムの内部の働きを理解しましたから、こんどはそれと戯れてみるべきときです。 オブジェクトをいくつか生成し、新たなMopsワードを定義し、新たなサブクラスを定義し、ちょっとしたトリックのために既存のメソッドを変形するということによってできることについて、一定の理解を得るところから始めましょう。Mopsと戯れればその分だけ、より速くその力に満足を感じられるようになるでしょう。

まず、ファイル Turtleをロードしなければなりません。fileメニューからロードコマンドを選ぶか、
// turtle
のように‘スラッシュ スラッシュ’コマンドを打ち込むか、どちらかを実行します。

ファイルがロードされるとき、各成分ファイルがロードされるに従ってメッセージが現れるでしょう。

ひとたび諸ファイルがロードされたなら、リサージュ図形とは何であるのか見てみたいでしょう。 Bicペンオブジェクトを描画デバイスとして使いましょう。LJ:のメソッド定義をよく見れば、それが機能するにはBicのいくつかのインスタンス変数が必要であることがわかるでしょう。それはinitLen、deltaLen、deltaDegそしてhomeLocです(maxRepsも必要ですが、その値はCLASSINIT:で200に設定されています。)。 便宜上、Mopsワード‘lj’を定義しましょう。これはa)三つの入力引数をとり、それらを最初の三つのインスタンス変数に割り当て(メソッドPUTRANGE:で実行される操作です。)b)homeLocationをスクリーンの中心に置き(メソッドCENTER:で実行されます)、c)リサージュ図形を描画します(メソッドLJ:)例えば次のようにします。:
: lj  cls  putrange: bic
           230 160 center: bic
           lj: bic   cr   ;
三つの数値を様々に組み合わせて打ち込んでみてください(例えば、9 11 301 lj)。そして描画される曲線の多様性を観察してください。【以下のカーソルの話はOSX上では関係ないようです。ここから -- 】2 2 2 lj を試してみると、crがプロンプトを左側余白に持って行く最後の瞬間にスクリーン上にカーソルが描画されていることに気付くでしょう。これを消すには、Mopsワード"-curs"でカーソルをオフにする必要があります(この反対が"+curs"でカーソルが再びオンに戻ります)。

リサージュ図形を描く前にカーソルをオフにし、描画が完成したときにオンに戻す、 新しいワードを定義しましょう:
: cleanlj  -curs  lj  +curs   ;
【 -- ここまで】

【PowerMopsではコンソールにMLTEを使っているためMopsウィンドウの上に描画されるとあまり綺麗ではなく、上のcenterの値だとスタックビューにはみ出してしまうので、次のようにQuickEditから実行すると便利です。まずQuckEditを起動して、そこからMopsにTurtleのロードしワードljの定義をコンパイルします。次に" Window ww Test: ww" を実行してテストウィンドウを開きます。これだと小さいので、このテストウィンドウをマウスで512*512程度の大きさにリサイズします。それからそのテストウィンドウが見えるようにしたままQuickEditをアクティブにして、そこから、"9 11 301 lj"等の描画コマンドを送ります。図形はテストウィンドウに描画されるはずです。】

整数値の組み合わせによっては、繰り返しの回数がリサージュ図形の描画を完成させる(または、既に行ったステップの追跡が始まる)には不十分であることもあります。例えば、12 1 1949で試してみてください。 繰り返しの回数を増やすには、PUTMAX:メッセージをBicに送ってそのmaxRepsインスタンス変数を変えることができます。
1000 putmax: bic
次はAnnaオブジェクトで実験してみましょう。今現在ではそれは各辺が60ピクセルの正方形です。CENTER:セレクターを含んだメッセージを送って、AnnaのhomeLocインスタンス変数にスクリーンの中心座標を入れます。
250 160 center: Anna
次にAnnaのPnLocを次のメッセージによって中央に動かします。
home: Anna
Annaを描画しましょう。スクリーン上に正方形が現れます。次にスクリーンをクリアし(ワードCLSを実行します)、Annaをリサイズしてオブジェクトが各20ピクセルの8つの辺をもつようにして、そのオブジェクトを描画します。
20 8 size: Anna
draw: Anna
【以下のカーソル描画の問題についても前述のようにOSXでは現れないようです】

どちらの描画においても、カーソルとMopsプロンプトの存在が図形を汚してしまいます。そこでMopsワードを次のように定義します。:
  • スクリーンをクリアーする
  • カーソル描画をオフにする
  • Annaを描画する
  • プロンプトを左端にもってくる
  • カーソル描画をオンにする

: draw   cls  -curs  draw: anna  cr  +curs   ;


チュートリアル目次へ
前へ < レッスン16 次へ > レッスン18



最終更新:2018年12月09日 20:45