暇なので書きましたw
まず始めに以前に書いた KochMorph のコードを再利用したいのでリファクタリングから行います。
FractalMorph
FractalMorph は図形を描画するための基本的なメソッドを実装します。
FractalMorph は BorderedMorph のサブクラスにします。インスタンス変数は、location と angle を持ちます。
BorderedMorph subclass: #FractalMorph instanceVariableNames: 'location angle' classVariableNames: '' package: 'PBE-Fractal'
インスタンス変数をアクセスするメソッドから。accesing プロトコルに書きます。
angle ^ angle
location ^ location
インスタンス変数を設定するメソッドは protected プロトコルに書きます。
Smalltalk ではメソッドのアクセス制限は無いのですが、protected プロトコルに書くことで、
このオブジェクトとサブオブジェクト群からのアクセスのみを推奨している事をコードを読む人に伝えます。
angle: radian angle := radian
location: point location := point
次は初期化メソッドです。初期化メソッドは initialization プロトコルに書きます。
initialize メソッドはオーバーライドするので最初に「super initialize」が必要です。これを絶対に忘れないでください。
initialize super initialize. self angle: 0. self location: self center
最後は描画を行うためのメソッドです。drawing プロトコルに書きます。
また、turnLeft: メソッドは turnRight: メソッドを使って書きます。
forward: amountOfMovement | x y newLocation | x := angle cos * amountOfMovement. y := angle sin * amountOfMovement. newLocation := x @ y translateBy: self location. self addMorph: (LineMorph from: self location to: newLocation color: Color yellow width: 2). self location: newLocation
turnLeft: degree self turnRight: degree negated
turnRight: degree self angle: self angle + (2 * Float pi * degree / 360)
以上です。
FractalMorph は具体的に描画を行うメソッドは持たないので、なにも図形を描画できません。
具体的に描画を行うメソッドはサブオブジェクトで実装します。
KochMorph
以前に実装した KochMorph から実装します。
KochMorph は FractalMorph のサブオブジェクトにします。
FractalMorph subclass: #KochMorph instanceVariableNames: '' classVariableNames: '' package: 'PBE-Fractal'
次に初期化メソッドです。initialization プロトコルに書きます。
オーバーライドするので、最初に super initialize を書きます。
initialize super initialize. self extent: 800 @ 300. self location: 100 @ 200. self drawKoch: 100
コッホ曲線を描画するメソッドを実装します。プロトコルは drawing にします。
drawKoch: n | nn | n > 7 ifTrue: [ nn := n / 3. self drawKoch: nn. self turnLeft: 60. self drawKoch: nn. self turnLeft: -120. self drawKoch: nn. self turnLeft: 60. self drawKoch: nn ] ifFalse: [ self forward: 20 ]
以上です。
ここまで実装したら、Playground で
KochMorph new openInWorld
と打ち込み do it するとコッホ曲線を描画するモーフを表示します。
TriangleMorph
さて本丸のオブジェクト TriangleMorph です。これも FractalMorph のサブオブジェクトにします。
また、描画する三角形の一辺の長さを持つインスタンス変数 lengthOfSide を持ちます。
FractalMorph subclass: #TriangleMorph instanceVariableNames: 'lengthOfSide' classVariableNames: '' package: 'PBE-Fractal'
インスタンス変数をアクセスするメソッドを用意します。accesing プロトコルに書きます。
三角形の高さ、三角形の一辺の半分を求めるメソッドも用意しておきます。
lengthOfSide ^ lengthOfSide
heightOfTriangle ^ (self halfLengthOfSide * 3 sqrt) rounded
halfLengthOfSide ^(self lengthOfSide / 2) rounded
インスタンス変数を設定するメソッドは private プロトコルに書きます。
Smalltalk ではアクセス制限は無いのですが、private プロトコルにすることで、
このメソッドはこのオブジェクト内からのみの呼び出しを推奨していることをコードを読む人に伝えます。
最近の Pharo では private プロトコルにあるメソッドを外部のオブジェクトから呼び出すと警告を受けるかも知れません。(そういう悪い事したことないのでわかりませんw)
lengthOfSide: newLength lengthOfSide := newLength
初期化メソッドです。initialization プロトコルに書きます。
しつこいようですが重要な事なので書きます。
オーバーライドするメソッドなので最初に super initialize を書くのを忘れずに。
モーフの大きさ設定は手抜きなので、大きなピラミッドを描画したい場合は適宜変更してください。
initialize super initialize. self extent: 800 @ 800. self location: self center x @ 100. self lengthOfSide: 100. self drawTriangleRec1: self stepOfTriangles top: self location
定数を返すメソッドを書きます。constants プロトコルに書きます。
コード中にマジックナンバーを書くのは推奨されないため、定数を返すメソッドとして実装するのが良いでしょう。
このメソッドはピラミッドの段数を持ちます。5 となっているので 5 段のピラミッドを描画します。
stepOfTriangles ^5
最後に三角形を描画するメソッドです。drawing プロトコルに書きます。
drawTriangle: は一辺の長さが self lengthOfSide の正三角形を1つ描画します。
drawTriangle: topPoint self angle: 0. self location: topPoint. self turnRight: 60. self forward: self lengthOfSide. self turnRight: 120. self forward: self lengthOfSide. self turnRight: 120. self forward: self lengthOfSide
drawTriangleRec1: top: および drawTriangleRec2: top: は再帰的に三角形を描画することでピラミッドを作ります。
再帰するメソッドはバグって無限ループになると大変な事になるため、イメージを保存してから実行するようにしましょう。一生懸命書いたコードが失われてしまう事があります。
drawTriangleRec1: row top: aPoint row = 0 ifTrue: [ ^self ]. self drawTriangleRec2: row top: aPoint. self drawTriangleRec1: row - 1 top: (aPoint x + self halfLengthOfSide) @ (aPoint y + self heightOfTriangle)
drawTriangleRec2: row top: aPoint row = 0 ifTrue: [ ^self ]. self drawTriangle: aPoint. self drawTriangleRec2: row - 1 top: (aPoint x - self halfLengthOfSide) @ (aPoint y + self heightOfTriangle)
以上です。
Playground に
TriangleMorph new openInWorld
と入力して do it すると三角形のピラミッドを描画するモーフが現れます。