마침내 주사위
이제 주사위를 그릴 모든 준비가 끝났다. 정6면체의 8개의 꼭지점을 3각형으로 자른 주사위는 24개의 꼭지점을 가진 볼록 14면체이다. 6개의 8각형 큰 면과 8개의 3각형 작은 면을 가진 14면체다. 따라서 주사위를 그리려면 14개의 면을 그려야 한다. 24개의 꼭지점에 번호를 매기고 그 번호로 면을 정의하는 인덱스를 코딩하여야 한다. 나는 프라톤 입체를 그릴 때와 마찬가지로 모형을 만들어 사용하였다. 찰흙과 이쑤시개로 만든 정6면체 모형의 8 귀퉁이에 생긴 3각형 꼭지점에 번호를 붙였다.
아래 그림 <그림1>의 왼쪽 것이 바로 그것이다. 이 경우 번호 매김은 어떤 순서로 하거나 상관이 없다. 나중에 면을 정의하는 인덱스 배열을 만들 때 그 순서를 일관성 있게만 해 주면 된다.
그림 1) 주사위를 그리기 위하여 만든 모형과 플래시로 만든 주사위 스크린 셧
위 그림 <그림1>의 오른 쪽 것이 왼쪽 모형에 따라 만든 주사위 최종 결과물 스크린 셧이다. 이제 이 주사위를 던질 수 있게 만드는 법을 설명한다.
먼저 이 주사위를 생성하는 CreateDice 클래스의에 대해 설명한다. 그 클래스의 빼대는 <표1>에 올려 놓았다. 20개의 속성과 6개 메쏘드 함수로 구성되었다. 20개의 속성 가운데 2개만 public 으로 밖에서 불러 내어 조종할 수 있고 나머지 18개는 private 속성으로 클래스 내부에서만 사용할 수 있다. 메쏘드 함수도 두개만 public이고 나머지 4개는 private로 클래스 안에서만 사용할 수 있다. public 함수중에서 하나는 생성자(constructor) 함수로 클래스 인스턴스를 만들 때 한번만 쓰이는 것이므로 아무때나 밖에서 실행시킬 수 있는 public 함수는 하나뿐이다.
1 |
class CreateDice{ |
2 |
public var mc:MovieClip; |
3 |
private var sizeCube:Number; |
4 |
private var cornerSizeRatio:Number; |
5 |
private var sd :Number ; |
6 |
private var sizeDot:Number; |
7 |
private var colA:Array ; |
8 |
private var colCorner:Array; |
9 |
private var colDot:Number; |
10 |
public var rotMat : Rotation3D ; |
11 |
private var aCube:Array; |
12 |
private var currentCube:Array ; |
13 |
private var aCube2D:Array ; |
14 |
private var corns2D:Array; |
15 |
private var corns2D3:Array; |
16 |
private var cornsIndex8:Array ; |
17 |
private var cornsIndex3:Array ; |
18 |
private var dotsC:Array ; |
19 |
private var dotData:Array; |
20 |
private var distZ:Number; |
21 |
private var isIsometric:Boolean; |
22 |
|
23
|
public function CreateDice(diceMc:MovieClip , diceSize:Number, cornSize:Number , dotSizeR:Number, colorArray:Array, colorCorner:Array,dotCol:Number){//***//} |
24 |
private function init():Void {//***//} |
25 |
private function calDotData(pt3D1:Array):Array {//***//} |
26 |
private function drawFilledPoly(corners, fillC, alp):Void {//***//} |
27 |
private function drawDot (oneDot):Void{//***//} |
28 |
public function showDice(dist:Number, isIso:Boolean):Void {//***//} |
29 |
}//end class def. |
표1) class CreateDice 의 코드의 골자
줄2의 MovieClip 속성 mc 는 주사위가 생성되는 무비클립이다. 따라서 주사위의 병진 운동은 mc._x, mc._y를 변동시켜 스크린 위에서 움직이게 한다. 줄3의 sizeCube는 주사위의 크기로서 초기화할 때 한번 생성자 함수의 인수로 받아 정하면 주사위를 없앨 때까지 바꿀 수 없다. 줄4의 cornerSizeRatio는 주사위의 모서리의 잘린 부분의 크기를 정한다. <그림37>에서 cornerSizeRatio=0.3이다. 줄5의 내부 속성변수 sd=1-cornerSizeRatio 로<그림37>에서 보면 0.7이 된다. 나머지 속성변수를 모두 여기서 설명하지 않겠다. 클래스 안에서 이들 속성이 어떻게 쓰였는가를 보면 그 속성의 의미를 이해할 수 있다.
그림 2) 무비1에 그린 주사위 설계도
가장 중요한 속성은 aCube 라는 배열로 전에 말했던 24개의 꼭지점을 정의하는 데이터 배열이다. 이 x,y,z 성분으로 표시되는 24개의 3차원 점의 배열임에 주의하기 바란다. 주사위의 중심을 3차원공간 자리표의 원점(0,0,0) 에 놓고 이 원점에서 주사위의 변까지의 거리를 1로 잡았을 때의 꼭지점 자리표를 <그림36>의 모형의 번호순으로 기입한 것이다. 생성자 함수를 실행하면 그 일부에서 아래 <표10>의 코드로 기술 되는 aCube 배열이 생성된다.
aCube = new Array( [sd, 1, -1], [1, sd, -1], [1, 1, -sd], [sd, -1, -1], [1, -sd, -1], [1, -1, -sd], [-sd, -1, -1], [-1, -sd, -1], [-1, -1, -sd], [-sd, 1, -1], [-1, sd, -1], [-1, 1, -sd], [sd, 1, 1], [1, sd, 1], [1, 1, sd], [sd, -1, 1], [1, -sd, 1], [1, -1, sd], [-sd, -1, 1], [-1, -sd, 1], [-1, -1, sd], [-sd, 1, 1], [-1, sd, 1], [-1, 1, sd] ); |
표2 주사위의 24개의 꼭지점의 3차원 자리표로 된 배열 (표10)
다음 중요 속성 변수는 주사위의 텍스쳐 데이터인 점들의 위치를 담은 배열 18줄의 dotsC와 그리기 데이터를 담은 19줄의 otData 다. dotsC 는 주사위의 점들의 중심의 자리표를 모은 배열이다. 주사위에는 점이 1+2+3+4+5+6 = 21 개가 있다. 이들의 위치를 다음과 같이 배열에 담았다.
<그림2>의 설계도에 점들의 위치를 표시했는데 는 "2" 와 "4" 만 실선으로 표시된 위치에 점을 그리고 나머지 "1", "3", "5", "6" 은 점선으로 그린 원들의 위치에 그렸다. 그리고 21개의 점들은 ·"1", "2", "3", "4", "5", "6" 면의 점들의 순서대로 배열에 담는다. 즉 "1" 면의 점은 dotsC[0] 에, "2" 면의 점은 dotsC[1], dotsC[2] 에, "3" 면의 점은 dotsC[3], dotsC[4], dotsC[5]에 담는다. 나머지도 마찬가지이다. 줄4~6은 점의 크기를 주사위의 크기에 비례하여 키운다. 줄7~11은 이제 이 주사위의 점을 그리기 위한 텍스쳐 데이터를 만드는 코드다.
그림 3) 주사위의 한점을 그리는데 필요한 8개의 데이터 점.
점(근사원) 하나마다 8개의 3차원점을 사용하기로 한다. <그림3>의 가운데 점이 주사위의 점의 위치를 나타내고 정4각형의 변과 꼭지점에 놓인 8개의 점이 근사원을 그리는데 쓰인다. 원 위의 점을 양끝으로 하고 꼭지점점을 조절점(control point)으로 해서 curveTo를 사용한 곡선 4개로 근사원을 그린다.
1 |
dotsC = new Array([0, 0, -1], [1, 0.4, -0.4], [1, -0.4, 0.4], [-0.5, -1, -0.5], [0, -1, 0], [0.5, -1, 0.5], [-0.5, 1, -0.5], [0.5, 1, -0.5], [0.5, 1, 0.5], [-0.5, 1, 0.5], [-1, 0, 0], [-1, 0.5, -0.5], [-1, -0.5, -0.5], [-1, -0.5, 0.5], [-1, 0.5, 0.5], [-0.5, -0.5, 1], [0, -0.5, 1], [0.5, -0.5, 1], [0.5, 0.5, 1], [0, 0.5, 1], [-0.5, 0.5, 1]); |
2 |
for (var i=0; i<21; i++) { |
3 |
for (var j=0; j<3; j++) { |
4 |
dotsC[i][j] = dotsC[i][j]*sizeCube/2; |
5 |
} |
6 |
} |
7 |
dotData = new Array( 21); |
8 |
for (var i= 0; i<21; i++) |
9 |
dotData[i] = new Array[[0,0,0], [0,0,0], [0,0,0], [0,0,0], [0,0,0], [0,0,0], [0,0,0], [0,0,0]]; |
10 |
for (var i= 0; i<21; i++) |
11 |
dotData[i] = calDotData(dotsC[i]); |
표3 주사위의 점들을 그리기 위한 코드
<표3>의 줄9에 정의된 8요소 배열에 이 8개의 3차원 점들을 담는다. 그리고 모두 21개의 점에 대해서 이 데이터점을 생성한다. (<표3> 줄10, 11 참조) 이것을 손으로 일일이 코딩하는 것은 힘들 뿐 아니라 자칫 에러를 유발할 수 있으므로 이것을 피하기 위하여 아래의 코드와 같은 생성함수를 만들어 <표3> 줄11에서 시행한다.
아래의 <표4>에 올려 놓은 CalDotData 함수는 인수로 받은 근사원의 중심이 어느 평면에 놓여 있나를 판별한 다음 이 평면에 근사원 중심점 주변에 8개의 점을 생성하여 반환하는 함수다.
1 |
private function calDotData(pt3D1:Array):Array { |
2 |
var pt3DA = [[0,0,0], [0,0,0], [0,0,0], [0,0,0], [0,0,0], [0,0,0], [0,0,0], [0,0,0]]; |
3 |
if (Math.abs (pt3D1[0])==(sizeCube/2)) |
4 |
{pt3DA[0] =[pt3D1[0], pt3D1[1] + sizeDot, pt3D1[2]]; |
5 |
pt3DA[1] = [pt3D1[0], pt3D1[1] + sizeDot, pt3D1[2]+sizeDot]; |
6 |
pt3DA[2] = [pt3D1[0], pt3D1[1], pt3D1[2]+sizeDot]; |
7 |
pt3DA[3] = [pt3D1[0], pt3D1[1] -sizeDot, pt3D1[2]+sizeDot]; |
8 |
pt3DA[4] = [pt3D1[0], pt3D1[1] -sizeDot, pt3D1[2]]; |
9 |
pt3DA[5] = [pt3D1[0], pt3D1[1] -sizeDot, pt3D1[2]-sizeDot]; |
10 |
pt3DA[6] = [pt3D1[0], pt3D1[1], pt3D1[2]-sizeDot]; |
11 |
pt3DA[7] = [pt3D1[0], pt3D1[1] +sizeDot, pt3D1[2]-sizeDot]; |
12 |
} |
13 |
else |
14 |
{if( Math.abs (pt3D1[1])==(sizeCube/2)) |
15 |
{pt3DA[0] = [pt3D1[0] + sizeDot, pt3D1[1], pt3D1[2]]; |
16 |
pt3DA[1] = [pt3D1[0] + sizeDot, pt3D1[1], pt3D1[2]+ sizeDot]; |
17 |
pt3DA[2] = [pt3D1[0], pt3D1[1], pt3D1[2]+sizeDot]; |
18 |
pt3DA[3] = [pt3D1[0] -sizeDot, pt3D1[1], pt3D1[2]+sizeDot]; |
19 |
pt3DA[4] = [pt3D1[0] -sizeDot, pt3D1[1], pt3D1[2]]; |
20 |
pt3DA[5] = [pt3D1[0] -sizeDot, pt3D1[1], pt3D1[2]-sizeDot]; |
21 |
pt3DA[6] = [pt3D1[0], pt3D1[1], pt3D1[2]-sizeDot]; |
22 |
pt3DA[7] = [pt3D1[0] +sizeDot, pt3D1[1], pt3D1[2]-sizeDot]; |
23 |
} |
24 |
else |
25 |
{pt3DA[0] =[pt3D1[0], pt3D1[1] + sizeDot, pt3D1[2]]; |
26 |
pt3DA[1] = [pt3D1[0]+sizeDot , pt3D1[1] + sizeDot, pt3D1[2]]; |
27 |
pt3DA[2] = [pt3D1[0]+sizeDot , pt3D1[1], pt3D1[2]]; |
28 |
pt3DA[3] = [pt3D1[0]+sizeDot , pt3D1[1] - sizeDot, pt3D1[2]]; |
29 |
pt3DA[4] = [pt3D1[0], pt3D1[1] - sizeDot, pt3D1[2]]; |
30 |
pt3DA[5] = [pt3D1[0]-sizeDot , pt3D1[1] - sizeDot, pt3D1[2]]; |
31 |
pt3DA[6] = [pt3D1[0]-sizeDot , pt3D1[1], pt3D1[2]]; |
32 |
pt3DA[7] = [pt3D1[0]-sizeDot , pt3D1[1] + sizeDot, pt3D1[2]]; |
33 |
} |
34 |
} |
35 |
return pt3DA; |
36 |
} |
표4 calDotData 함수의 코드. 점의 위치를 인수로 받아서 그 주변의 8개의
점을 생성하여 반환한다.(12)
이 마디는 너무 길어지므로 다음 강좌에서 이어서 설명한다.