SqueakByExample:11.8
완전한 예제
주사위(die)를[1] 던지기 위해 모프를 디자인 해봅시다. 모프를 클릭하면, 신속한 루프(quick loop)에서 주사위의 모든 면들의 값들을 디스플레이하고, 다시 클릭을 하면 그 에니메이션을 멈춥니다.
morph 대신에 BorderedMorph의 서브클래스로서 주사위(die)를 정의합니다. 그 이유는 우리가 경계(border)를 활용할 것이기 때문입니다.
클래스 11.27: 주사위 모프(the die morph) 정의하기
BorderedMorph subclass: #DieMorph
instanceVariableNames: 'faces dieValue isStopped'
classVariableNames: ''
poolDictionaries: ''
category: 'SBE--Morphic'
인스턴스 변수 faces는 주사위 면들의 개수를 기록하며, 우리는 9개의 면까지 주사위의 면들을 만들 수 있습니다. dieValue는 현재 디스플레이된 면의 값을 기록하며, isStopped는 주사위의 애니메이션이 멈출 경우 true가 됩니다. 주사위(die) 인스턴스를 만들기 위해, 우리는 faces를 정의합니다: n faces로 새로운 주사위 (die)를 만들기 위해 DieMorph의 클래스 side(the class side)에 있는 n 메서드를 정의합니다.
메서드 11.28: 우리가 좋아하는 면의 개수로 새로운 주사위를 만들기
DieMorph class»faces: aNumber
↑ self new faces: aNumber
초기화 메서드(initialize method)는 평상시의 방법으로 인스턴스 사이트(the instance side)에서 정의됩니다. New는 새롭게 만들어진 인스턴스에 initialize를 발송한다는 것을 기억해 주십시오.
메서드 11.29: DieMorph의 인스턴스들을 초기화 하기
DieMorph»initialize
super initialize.
self extent: 50 @ 50.
self useGradientFill; borderWidth: 2; useRoundedCorners.
self setBorderStyle: #complexRaised.
self fillStyle direction: self extent.
self color: Color green.
dieValue := 1.
faces := 6.
isStopped := false
우리는 주사위(die)에 훌륭한 외관을 부여하기 위해 몇 가지 BorderedMorph의 메서드를 사용합니다: 상승효과(raised effect), 모서리 다듬기(rounded corners)와 함께 굵은 경계(thick border) 그리고 보이는 면에 컬러 경사도(gradient).
우리는 인스턴스 메서드 faces를 다음과 같이 유효한 파라미터를 점검하기위해 정의합니다:
메서드 11.30: 주사위 면들의 개수를 설정하기
DieMorph»faces: aNumber
"Set the number of faces"
(aNumber isInteger
and: [aNumber > 0]
and: [aNumber <= 9])
ifTrue: [faces := aNumber]
주사위가 만들어 졌을 때, 발송된 메시지들의 순서를 리뷰하는 것이 좋습니다. 예를 들어, 우리가 DieMorph face:9을 평가함으로써 시작한다면:
- 클래스 메서드 DieMorph class»faces:는 DieMorph 클래스에 new를 발송합니다.
- new를 위한 메서드는 (Behavior로부터 DieMorph에 의해 상속된) 새로운 인스턴스를 만들고 초기화 메시지(the initialize message)를 그 인스턴스에 발송합니다.
- DieMorph에서의 초기화 메서드(the initialize method)는 초기 값 6으로 faces를 설정합니다.
- DieMorph class»new는 새로운 인스턴스에 메시지 faces:9을 발송하는 클래스 메서드 DieMorph class»faces:로 리턴합니다.
- 인스턴스 변수를 9로 설정하며, 인스턴스 메서드 DieMorph»faces:가 지금 실행됩니다.
drawOn: 을 정의하기 전에, 우리는 디스플레이된 표면(face)에 점(dots)을 배치하기 위한 몇 가지 메서드가 필요합니다.
메서드 11.31: die의 faces에 점들(points)를 배치하기 위한 9개의 메서드
DieMorph»face1
↑{0.5@0.5}
DieMorph»face2
↑{0.25@0.25 . 0.75@0.75}
DieMorph»face3
↑{0.25@0.25 . 0.75@0.75 . 0.5@0.5}
DieMorph»face4
↑{0.25@0.25 . 0.75@0.25 . 0.75@0.75 . 0.25@0.75}
DieMorph»face5
↑{0.25@0.25 . 0.75@0.25 . 0.75@0.75 . 0.25@0.75 . 0.5@0.5}
DieMorph»face6
↑{0.25@0.25 . 0.75@0.25 . 0.75@0.75 . 0.25@0.75 . 0.25@0.5 . 0.75@0.5}
DieMorph»face7
↑{0.25@0.25 . 0.75@0.25 . 0.75@0.75 . 0.25@0.75 . 0.25@0.5 . 0.75@0.5 . 0.5@0.5}
DieMorph »face8
↑{0.25@0.25 . 0.75@0.25 . 0.75@0.75 . 0.25@0.75 . 0.25@0.5 . 0.75@0.5 . 0.5@0.5 . 0.5@0.25}
DieMorph »face9
↑{0.25@0.25 . 0.75@0.25 . 0.75@0.75 . 0.25@0.75 . 0.25@0.5 . 0.75@0.5 . 0.5@0.5 . 0.5@0.25 . 0.5@0.75}
이 메서드들은 각 표면(face)을 찍을 점(dots)의 좌표(coordinates)의 컬렉션들을 정의합니다. 좌표(coordinates)는 1x1 스퀘어 이며, 우리는 단순히 실제의 점(dots)을 배치 하기 위해 그것들을 측량할 필요가 있습니다.
drawOn: 메서드는 두 가지 일들을 수행합니다: 이것은 수퍼발송(super-send)으로 주사위 배경(die background)을 그리고, 그 다음 점(dots)를 그립니다.
메서드 11.32: 주사위 모프(die morph) 그리기
DieMorph»drawOn: aCanvas
super drawOn: aCanvas.
(self perform: ('face' , dieValue asString) asSymbol)
do: [:aPoint | self drawDotOn: aCanvas at: aPoint]
이 메서드의 두 번째 부분은 스몰토크의 반영 능력(the reflective capacities)을 사용합니다. Face의 dots를 그리는 것은 각 좌표를 위해 drawDotOn:at: 메시지를 발송함으로써, face를 위해, faceX 메서드를 통해 주어진 컬렉션(collection)에 반복적용(iteration)을 하는 단순한 작업입니다. 정확한 faceX 메서드를 콜하기 위해, 우리는 여기 ('face', dieValueasString) asSymbol 문자열로부터 구축된 메시지를 발송하는 perform: 메서드를 사용합니다. 여러분은 이 perform:quite의 사용을 규칙적으로 마주치게 될 것입니다.
메서드 11.33 표면(face)에 단일 점(dot)을 그리기
DieMorph»drawDotOn: aCanvas at: aPoint
aCanvas
fillOval: (Rectangle
center: self position + (self extent * aPoint)
extent: self extent / 6)
color: Color black
좌표들이 [0:1] interval 에 정상화되기 때문에, 우리는 우리의 die: self extent * aPoint의 치수(diemensions)들로 그 좌표들을 조정(scale)합니다.
우리는 워크스페이스로 부터 주사위(die) 인스턴스를 이미 만들었습니다:
(DieMorph faces: 6) openInWorld.
디스플레이된 표면(face)을 변경하기 위해, 우리는 myDie dieValue:4로서 우리가 사용할 수 있는 accessor를 만듭니다.
메서드 11.34: 주사위(die)의 현재 값을 설정하기
DieMorph»dieValue: aNumber
(aNumber isInteger
and: [aNumber > 0]
and: [aNumber <= faces])
ifTrue:
[dieValue := aNumber.
self changed]
이제 우리는 모든 표면(faces)을 신속하게 보여드리기 위해 에니메이션 시스템(animation system)을 사용할 것입니다:
메서드 11.35: 주사위(die)에 에니메이션(움직임) 효과 주기
DieMorph»stepTime
↑ 100
DieMorph»step
isStopped ifFalse: [self dieValue: (1 to: faces) atRandom]
이제 주사위가 돌아갑니다. 클릭으로 에니메이션을 시작하거나 멈추기 위해 우리가 이전에 마우스 이벤트에 관해 배운 것을 사용하게 될 것입니다. 먼저, 마우스 이벤트(mouse events)의 수신(reception)을 활성화합니다:
메서드 11.36: 에니메이션을 시작하고 멈추기 위해 마우스 클릭 취급(handling)하기
DieMorph»handlesMouseDown: anEvent
↑ true
DieMorph»mouseDown: anEvent
anEvent redButtonPressed
ifTrue: [isStopped := isStopped not]
우리가 주사위(die)를 클릭하면, 그 주사위가 돌아가게 됩니다.
Notes
- ↑ NB: One die, two dice