플래시 프로패셔널(CS5 CS5.5 CS6 등)에서 굵은 글씨를 사용하고 싶은데 

이렇게 스타일이 비활성화 상태여서 선택을 못 할 때가 있다.




폰트에 bold스타일이 없는 경우 이렇게 선택할 수 없다.

플래시8 같은 데서 기존에 쓰던 방식으로 글자를 굵게 하려면 아래의 방법을 쓸 수 있다.

굵게 할 텍스트를 선택한 뒤, 메뉴에서 텍스트 - 스타일 - 가상 굵게를 눌러 체크하면 텍스트가 굵게 변하게 된다.




==================================================================================








작동방법

- 마우스를 휘저어 보세요

- 화면을 클릭하고 마우스를 휘저어 보세요

- 오른쪽 아래 구석에 있는 podo로고를 클릭해 보세요

  한 번 누를 때 마다 노란 불빛이 켜졌다가 꺼졌다가를 반복하며

  불이 켜져 있을 때는 화면에 잔상이 남아서 색다른 모양을 볼 수 있습니다.

  

(1차 수정 : podo로고가 두번씩 눌려서 켜졌다가 다시 꺼지는 버그 수정)



(▼ 이곳에 플래시가 삽입되어 있습니다. 일부 환경에서는 보이지 않을 수 있습니다.) 




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.geom.Point;
import flash.utils.ByteArray;
import flash.events.MouseEvent;
import flash.geom.ColorTransform;
import flash.filters.GlowFilter;
 
 
const MAX_UNIT:int = 4096;
 
 
var bmpDatF:BitmapData = new BitmapData(1,1,false,0x0000ff);
var bmpDatB:BitmapData = new BitmapData(stage.stageWidth, stage.stageHeight,false,0x000000);
var canvas:Bitmap = new Bitmap(new BitmapData(stage.stageWidth, stage.stageHeight,false,0xffffff));
var velVec:Vector.<Point> = new Vector.<Point>(MAX_UNIT);
var posVec:Vector.<Point> = new Vector.<Point>(MAX_UNIT);
var colorVec:Vector.<uint> = new Vector.<uint>(MAX_UNIT);
var blueTransform:ColorTransform = new ColorTransform(0.86,0.86,0.86);
 
 
var datumPoint:Point = new Point(0,0);
var theta:Number = 0;
 
velVec.fixed = true;
posVec.fixed = true;
colorVec.fixed = true;
 
for(var i:int=0; i<MAX_UNIT; i++) {
    velVec[i] = new Point(0,0);
    posVec[i] = new Point(0,0);
    colorVec[i] = getColorByHue(i/MAX_UNIT*i/MAX_UNIT*i/MAX_UNIT*i/MAX_UNIT*360);
}
addChild(canvas);
 
 
 
 
var timer:Timer = new Timer(1000/60);
timer.addEventListener(TimerEvent.TIMER, timerHandler);
timer.start();
 
function timerHandler(evt:TimerEvent):void
{
    canvas.bitmapData.lock();
     
    if(podoed)
        canvas.bitmapData.colorTransform(canvas.bitmapData.rect, blueTransform);
    else
        canvas.bitmapData.copyPixels(bmpDatB,bmpDatB.rect,datumPoint);
         
    var dx:Number;
    var dy:Number;
    var direction:Number;
    var color:uint;
    for(var i:int=MAX_UNIT-1; i>=0; i--) {
        dx = stage.mouseX-posVec[i].x;
        dy = stage.mouseY-posVec[i].y;
        direction = Math.atan2(dy,dx);
         
        velVec[i].x += (i/MAX_UNIT*3.6+0.5)*Math.cos(direction);
        velVec[i].y += (i/MAX_UNIT*3.6+0.5)*Math.sin(direction);
         
        posVec[i].x += velVec[i].x;
        posVec[i].y += velVec[i].y;
         
        velVec[i].x *= i/MAX_UNIT*0.14+0.85;
        velVec[i].y *= i/MAX_UNIT*0.14+0.85;
         
        if(Math.abs(dx)<1&&Math.abs(dy)<1) {
            posVec[i].x = stage.mouseX;
            posVec[i].y = stage.mouseY;
            velVec[i].x = 0;
            velVec[i].y = 0;
        }
        canvas.bitmapData.setPixel(posVec[i].x,posVec[i].y,colorVec[i]);
    }
    canvas.bitmapData.unlock();
}
 
 
stage.addEventListener(MouseEvent.MOUSE_DOWN, clickHandler);
function clickHandler(evt:MouseEvent):void
{
    if(evt.stageX>podo.x && evt.stageX<podo.x+podo.width
       && evt.stageY>podo.y && evt.stageY<podo.y+podo.height) {
        podoClicked(null);
        return;
    }
    for(var i:int=0; i<MAX_UNIT; i++) {
        velVec[i].x = 0;
        velVec[i].y = 0;
        posVec[i].x = evt.stageX;
        posVec[i].y = evt.stageY;
        //velVec[i].y = Math.random()*-20;
         
    }
}
 
function getColorByHue(angle:Number):uint
{
var hue:Number = (angle+0) % 360;
    var variation:uint = uint((hue % 60)/60*0xff);
    var red:uint, blue:uint, green:uint;
    if (hue<60) {
        red = 0xff;
        blue = 0;
        green = variation;
    }
    else if (hue < 120) {
        red = 0xff - variation
        blue = 0;
        green = 0xff;
    }
    else if (hue < 180) {
        red = 0
        blue = variation;
        green = 0xff;
    }
    else if (hue < 240) {
        red = 0x0;
        blue = 0xff;
        green = 0xff-variation;
    }
    else if (hue < 300) {
        red = variation;
        blue = 0xff;
        green = 0x0;
    }
    else if (hue < 360) {
        red = 0xff;
        blue = 0xff-variation;
        green = 0;
    }
     
    return red<<16|green<<8|blue;
}
 
 
var podo:Sprite = new Podo();
podo.width*=0.40;
podo.height*=0.40;
podo.x = stage.stageWidth-podo.width;
podo.y = stage.stageHeight-podo.height;
stage.addChild(podo);
 
var podoed:Boolean = false;
var podoFilter:GlowFilter = new GlowFilter(0xffff00,1,4,4,4,3);
function podoClicked(evt:MouseEvent):void
{
    if(!podoed) {
        podo.filters = [podoFilter];
        podoed = true;
    }else{
        podo.filters = [];
        podoed = false;
    }
}
===========================================================================







자석과 나침반을 단순하게 구현한 것.

체크박스에 체크를 하면 자석이 나타난다.

막대자석 모양이 나타나지만 완벽하게 구현되어 있지는 않다..



▽이곳에 플래시가 삽입되어 있습니다.





=====================================================================================






Flash Professional에서 프레임에 직접 입력하였다.

스테이지에 btn0부터 btn15까지 16개의 버튼이 미리 배치되어 있다.


키보드 방향키로 상하좌우 이동을 하며 엔터 키로 버튼을 누를 수 있다.

코드는 아래에...


 





윈도우 바탕화면에서 아이콘을 키보드로 포커싱하는 것과 비슷하게 동작하도록 했다.
화면에 배치되어 있는 무비클립 객체들의 위치관계를 파악하여 각 방향으로
유출이 가능한지 여부에 대한 유향그래프를 생성한다.
그렇기 때문에 스테이지에서나 스크립트로 버튼의 배치를 바꿔도 
버튼들의 위치관계를 계산하여 문제없이 키보드 초점이동을 할 수 있다. 


코드 :

Hello SyntaxHighlighter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
import flash.events.KeyboardEvent;
import flash.display.DisplayObject;
import flash.filters.DisplacementMapFilter;
 
const MAX_BTN:int = 16;
const RIGHT:int = 0;
const LEFT:int = 1;
const UP:int = 2;
const DOWN:int = 3;
 
var pressedKey:Array = new Array();
var lastKey:int;
var moveGraph:Array = new Array(MAX_BTN);
var focus:int = 0;
var time:int=0;
 
 
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDown_h);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUp_h);
 
setFocus(0);
updateMoveGraph();
 
 
function keyDown_h(evt:KeyboardEvent):void
{
    if(getTimer()-time<50 && lastKey==evt.keyCode) return;
    time = getTimer();
    lastKey = evt.keyCode;
    //if(pressedKey[evt.keyCode] == true) return;
        switch(evt.keyCode) {
            case Keyboard.RIGHT:
            case Keyboard.LEFT:
            case Keyboard.UP:
            case Keyboard.DOWN:
                moveFocus(evt.keyCode);
                break;
            case Keyboard.ENTER:
                selectBtn();
                 
        }
    pressedKey[evt.keyCode] = true;
}
 
function keyUp_h(evt:KeyboardEvent):void
{
    pressedKey[evt.keyCode] = false;
    if(evt.keyCode == Keyboard.ENTER) this["btn"+focus].gotoAndStop("over");
}
 
 
function moveFocus(key:uint):void
{
    if(key == Keyboard.RIGHT) {
        setFocus(moveGraph[focus][RIGHT]);
    }
    else if(key == Keyboard.LEFT) {
        setFocus(moveGraph[focus][LEFT]);
    }
    else if(key == Keyboard.UP) {
        setFocus(moveGraph[focus][UP]);
    }
    else if(key == Keyboard.DOWN) {
        setFocus(moveGraph[focus][DOWN]);
    }
     
}
 
 
function updateMoveGraph():void
{
    var i:int, j:int;
    var dx:Number, dy:Number;
     
    for(i=0; i<MAX_BTN; i++) {
        moveGraph[i] = new Array(4);
        moveGraph[i][RIGHT] = -1;
        moveGraph[i][LEFT] = -1;
        moveGraph[i][UP] = -1;
        moveGraph[i][DOWN] = -1;
    }
    for(i=0; i<MAX_BTN; i++) {
        for(j=0; j<MAX_BTN; j++) {
            if(i==j) continue;
             
            dx = this["btn"+i].x - this["btn"+j].x
            dy = this["btn"+i].y - this["btn"+j].y
             
            if(dx<0 && dx*dx>dy*dy) {
                if(moveGraph[i][RIGHT] == -1)  moveGraph[i][RIGHT] = j;
                else if(getNear(this["btn"+i],this["btn"+j],this["btn"+moveGraph[i][RIGHT]]) == 1) {
                    moveGraph[i][RIGHT] = j;
                }
            }
             
            else if(dx>0 && dx*dx>dy*dy) {
                if(moveGraph[i][LEFT] == -1)  moveGraph[i][LEFT] = j;
                else if(getNear(this["btn"+i],this["btn"+j],this["btn"+moveGraph[i][LEFT]]) == 1) {
                    moveGraph[i][LEFT] = j;
                }
            }
             
            else if(dy>0 && dx*dx<dy*dy) {
                if(moveGraph[i][UP] == -1)  moveGraph[i][UP] = j;
                else if(getNear(this["btn"+i],this["btn"+j],this["btn"+moveGraph[i][UP]]) == 1) {
                    moveGraph[i][UP] = j;
                }
            }
             
            else if(dy<0 && dx*dx<dy*dy) {
                if(moveGraph[i][DOWN] == -1)  moveGraph[i][DOWN] = j;
                else if(getNear(this["btn"+i],this["btn"+j],this["btn"+moveGraph[i][DOWN]]) == 1) {
                    moveGraph[i][DOWN] = j;
                }
            }
             
        }
    }
}
 
 
function getNear(src:DisplayObject, dest1:DisplayObject, dest2:DisplayObject):int
{
    var distance1:Number;
    var distance2:Number;
    distance1 = (src.x-dest1.x)*(src.x-dest1.x)+(src.y-dest1.y)*(src.y-dest1.y);
    distance2 = (src.x-dest2.x)*(src.x-dest2.x)+(src.y-dest2.y)*(src.y-dest2.y);
    if(distance1<distance2) return 1;
    else if (distance1>distance2) return -1;
    return 0;
}
 
 
function setFocus(num:int):void
{
    if(num==-1) return;
    this["btn"+focus].gotoAndStop("up");
    focus = num;
    this["btn"+focus].gotoAndStop("over");
}
 
function selectBtn():void
{
    if(pressedKey[Keyboard.ENTER] != true) {
        this["btn"+focus].gotoAndStop("down");
    }
     
    if(focus==0) {
        //...
    }
    if(focus==1) {
        //...
    }
    if(focus==2) {
        //...
    }
    if(focus==3) {
        //...
    }
     
    //...
    //...
    //...
}


===================================================







저해상도 RGB모니터효과 플래시.


- 순서

1. 플래시

2. 미리보기

3. 소스코드




1. 플래시






2. 미리보기













3. 소스코드


package  {
	import flash.display.BitmapData;
	import flash.display.Bitmap;
	import flash.display.MovieClip;
	import flash.net.FileReference;
	import flash.net.FileFilter;
	import flash.events.Event;
	import flash.utils.ByteArray;
	import flash.display.Loader;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.display.DisplayObjectContainer;	
	
	public class TVeffect extends MovieClip{
		
		public function TVeffect() {
			
			var file:FileReference = new FileReference();
			file.addEventListener(Event.SELECT,onSelected);
			var loadedBytes:ByteArray;
			var image:Loader = new Loader();
			var container:MovieClip = new MovieClip();
			
			var tf1:TextField = new TextField();
			tf1.autoSize = TextFieldAutoSize.LEFT;
			tf1.x = tf1.y = 200;
			tf1.text = "화면을 눌러서 그림파일을 선택하세요.";
			addChild(tf1);
			var tf2:TextField = new TextField();
			tf2.autoSize = TextFieldAutoSize.LEFT;
			tf2.x = tf2.y = 450;
			tf2.text = "http://tibyte.kr";
			addChild(tf2);
			addChild(container);
			
			stage.addEventListener(MouseEvent.CLICK, onClick);
			function onClick(evt:MouseEvent):void
			{
				file.browse([new FileFilter("image file (JPG, JPEG, GIF, PNG)","*.jpg;*.jpeg;*.gif;*.png")]);
			}
			function onSelected(evt:Event):void
			{
				evt.target.load();
				evt.target.addEventListener(Event.COMPLETE, onCompleted);
			
			}
			
			function onCompleted(evt:Event):void
			{
				loadedBytes = evt.target.data;
				image.contentLoaderInfo.addEventListener(Event.INIT,onInited);
				image.loadBytes(loadedBytes);
			}
			
			
			function onInited(evt:Event):void
			{
				removeChildAll(container);
				var bmp:Bitmap = evt.target.content as Bitmap;
				container.addChild(bmp);
				for(var i_x:int = 0; i_x<bmp.bitmapData.width; i_x++){
					for(var i_y:int = 0; i_y<bmp.bitmapData.height; i_y++) {
						bmp.bitmapData.setPixel(i_x,i_y,bmp.bitmapData.getPixel(i_x,i_y)&0x0000ff<<(i_x%3)*8);
					}
				}
			}
			
			function removeChildAll(container:DisplayObjectContainer):void
			{
				for(var i:int=0; i<container.numChildren; i++) {
					container.removeChildAt(i);
				}
			}
				
		}
	
	}
	
}

 









정상파 발생 플래시입니다. 소리를 들어보세요.

(화면에 표시되는 내용은 스피커에 전달될 샘플링 데이터를 나타낸 것으로 정상파와는 맞지 않습니다.)







소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.text.TextField;
import flash.events.MouseEvent;
import flash.text.TextFormat;
import flash.text.TextFormatAlign;
import flash.text.TextFieldAutoSize;
import flash.media.Sound;
import flash.events.SampleDataEvent;
 
var mySound:Sound = new Sound();
 
var t:Number = 0;
var amplitude:Number = 0.25;
var graph_amplitude:Number = 50/amplitude;
var bmpDat:BitmapData = new BitmapData(400,200,false,0x0);
var bmp:Bitmap = new Bitmap(bmpDat);
bmp.y=50;
addChild(bmp);
 
 
var tfield:TextField = new TextField();
tfield.text = "화면을 누르면 시작.";
tfield.x = 120;
tfield.y = 100;
tfield.autoSize = TextFieldAutoSize.LEFT;
tfield.selectable = false;
var tformat:TextFormat = tfield.getTextFormat();
tformat.color = 0x33cc33;
tformat.align = TextFormatAlign.CENTER;
tfield.setTextFormat(tformat);
addChild(tfield);
stage.addEventListener(MouseEvent.CLICK, mouse_h);
 
 
function sineWaveGenerator(event:SampleDataEvent):void {
    t+=2;
    bmpDat.fillRect(new Rectangle(0,0,400,200),0x0);
    var wave:Number;
    for ( var c:int=0; c<2048; c++ ) {
        wave = getWave(c+event.position,t);
        event.data.writeFloat(wave);
        event.data.writeFloat(wave);
        if(c<800){
            bmpDat.setPixel(c,wave*graph_amplitude+100,0x00ff00);
        }
    }
    bmp.bitmapData = bmpDat;
 
}
 
 
function getWave(p:Number,t:Number):Number
{
    return (Math.sin(0.420*(Number(p+t)/Math.PI/2))+Math.sin(0.420*(Number(p)/Math.PI/2)))*amplitude;
}
 
function mouse_h(evt:MouseEvent):void
{
    mySound.addEventListener(SampleDataEvent.SAMPLE_DATA,sineWaveGenerator);
    mySound.play();
    removeChild(tfield);
}








플래시디벨롭에서 새 AIR AS3 Projector를 만들고 Test Project를 실행했더니

이런 오류가 발생했다.


Starting AIR Debug Launcher...

invalid application descriptor: Unknown namespace: http://ns.adobe.com/air/application/3.5





Flashdevelop.org의 커뮤니티에서 해결책을 찾을 수 있었는데,

우선 cmd창에 adt -version을 실행해보았다.
3.5가 출력되어야 하는데 2.7이 출력된다.



Path 환경변수를 확인해 보니 AIR SDK 2.7버전이 지정되어 있었다.

그것을 adl.exe가 위치해 있는 경로인 플래시디벨롭 폴더\Tools\flexsdk\bin으로 갱신해줬다.





다시 cmd에서 adt의 버전을 확인해보니 3.5가 나온다!







디벨롭에서 에어창이 제대로 뜨는 것을 확인.











 1. 플래시


자세한 설명은 아래에 있습니다.







2. 데이터&설명


지구에서 관측되는 화성의 움직임을 플래시로 나타내 본 것입니다.

아래와 같은 조건들을 설정했습니다.


- 공전궤도 모양

원(평면)으로 가정


- 공전궤도 반지름

지구 : 1
화성 : 1.5


-공전속도

지구 : 1.88

화성 : 1


- 궤도경사와 승교점경도

지구 : 7.3˚ 349˚
화성 : 5.7˚ 50˚


- 천구의 중심

태양 (중심을 지구로 잡으면 투영면이 움직여서 알아보기가 불편하고,

태양으로 잡아도 화성의 역행 움직임이 나타나는 모양을 설명하기에는

큰 차이가 없기 때문에 편의상 태양을 기준으로 함.) 


- 관찰자의 고도

황도를 기준으로 pi/13 라디안



지구와 화성의 공전궤도면이 일치하지 않기 때문에

화성이 충 부근에서 역행을 할 때 α모양이나 s모양이 나타나게 됩니다.


예전에 만들었던 것(http://www.tibyte.kr/126)은 두 행성의 공전궤도를 평면상에 둬서 

이런 현상을 확인할 수 없었는데 이번에 입체로 구현해보았습니다.



3. 코드 구현


(1)

Vector3D객체에 각 천체들의 위치벡터를 저장한 후

눈으로 직접 보기 위해 Sprite객체를 움직일 때는 아래와 같은 코드를 사용함.


earth.x = earthPoint.x + sunPoint.x;

earth.y = Math.sin(viewAng)*(earthPoint.y)+sunPoint.y +

 Math.cos(viewAng)*(earthPoint.z)+sunPoint.z;


viewAng는 시점의 고도이며, 이 값에 따라 위치벡터의 y,z값이 Sprite의 y값에 적용됩니다.

모니터는 2D니까 3차원 좌표를 2차원 좌표로 변환해야 하기 때문임.



(2)

공전궤도를 기울이는 함수 inclineObt()


function inclineObt(vec3D:Vector3D,xy:Number=0, zx:Number=0):Vector3D

{

var transVec3D:Vector3D = new Vector3D();

var matrix:Matrix = new Matrix(0,0,0,0);

matrix.a = vec3D.x;

matrix.b = vec3D.z;

matrix.rotate(zx);  //

transVec3D.x = matrix.a;

transVec3D.z = matrix.b;

matrix.a = transVec3D.x;

matrix.b = vec3D.y;

matrix.rotate(xy);

transVec3D.x = matrix.a;

transVec3D.y = matrix.b;

transVec3D.w = vec3D.w;

return transVec3D;

}


궤도경사와 승교점고도 수치에 맞게 공전궤도를 기울인다.

Matrix클래스의 rotate메서드는 이차원 회전행렬 

( cos -sin)
( sin  cos) 를 대상 행렬 앞에 곱함.




(3)

천구면에 투영된 화성의 위치를 구하는 함수


function calcProjPoint(vec1:Vector3D, vec2:Vector3D):Vector3D

{

var direcVec3D:Vector3D = vec2.clone();

direcVec3D.decrementBy(vec1);

var a:Number = direcVec3D.x;

var b:Number = direcVec3D.y;

var c:Number = direcVec3D.z;

var d:Number = vec1.x;

var e:Number = vec1.y;

var f:Number = vec1.z;

/* 이차방정식의 근의 공식으로 투영된 외행성의 위치를 구한다*/

var product:Number = calcQuadratic(a*a+b*b+c*c, 2*(a*d+b*e+c*f), d*d+e*e+f*f-sphereRad*sphereRad);

direcVec3D.scaleBy(product);

return direcVec3D.add(vec1);


}


천구면은 편의상 중심점을 태양의 중심으로 맞춤.

sphereRad 는 천구의 반지름값이므로 투영된 화성의 상은 태양으로부터 항상 sphereRad위치에 있게 됨.

천구면에 투영된 화성의 위치벡터는 (지구의위치벡터 + p*지구에서화성을바라보는벡터) 이므로 p값을 먼저 구해야 함.


즉, 지구벡터+p*(화성-지구벡터)의 거리는 sphereRad와 같으므로

거리 = 거리 방정식을 세워보면 위 코드와 같은 방법으로 p(product)값을 구할 수 있다. (calcQuadratic은 근의 공식으로 이차방정식의 (큰)해를 구하는 함수) 



(4) 

3D천구 뼈대를 그리는 부분


var polygons:Vector.<Vector.<Vector3D>> = new Vector.<Vector.<Vector3D>>(19);

var model2D:Vector.<Vector.<Point>> = new Vector.<Vector.<Point>>(19);

for(var i_lati:int = 0; i_lati<19; i_lati++) {

polygons[i_lati] = new Vector.<Vector3D>(36);

model2D[i_lati] = new Vector.<Point>(36);

for(var j_longi:int = 0; j_longi<36; j_longi++) {

polygons[i_lati][j_longi] = new Vector3D();

model2D[i_lati][j_longi] = new Point();

//초기위치 

polygons[i_lati][j_longi].z = radius*Math.sin(getLatitude(i_lati));

polygons[i_lati][j_longi].x = radius*Math.cos(getLatitude(i_lati))*Math.cos(getLongitude(j_longi));

polygons[i_lati][j_longi].y = radius*Math.cos(getLatitude(i_lati))*Math.sin(getLongitude(j_longi));

//시점에따른 변환

model2D[i_lati][j_longi].x = polygons[i_lati][j_longi].x + central.x;

model2D[i_lati][j_longi].y = Math.sin(viewAng)*(polygons[i_lati][j_longi].y)+central.y +

Math.cos(viewAng)*(polygons[i_lati][j_longi].z)+central.z;

}

}

function getLatitude(index:int):Number{return (index*10-90)/180*Math.PI;}

function getLongitude(index:int):Number{return (index*10)/180*Math.PI;} 



Vector에  Vector3D객체와 Point객체를를 2차원으로 할당하고

Vector3D에는 위도를 10도단위로 한층씩 훑어가면서 경선을 이루게 될 36개의 점의 xyz 3차원 좌표를 저장.

Point에는 2차원인 모니터에 표시하기 위해 위에서 구한 xyz좌표를 xy좌표로 변환 .











재미로하는 10년간의 행운그래프 입니다.

운이 별로 좋지 않게 나오면 노력으로 메꾸세요.


사용방법 : 태어난 년도와 이름을 적고 확인버튼을 누르세요.

마우스 오른쪽 버튼으로 언어전환을 할 수 있습니다. (fp11.2)









코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package
{
    import adobe.utils.CustomActions;
    import flash.display.BitmapData;
    import flash.display.DisplayObject;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Point;
    
    /**
     * ...
     * @author tibyte.kr
     */
    public class Main extends Sprite
    {
        private var form1:Form1;
        private var drawingContainer:Sprite = new Sprite();
        
        public function Main():void
        {
            if (stage)
                init();
            else
                addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        private function init(e:Event = null):void
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            // entry point
            stage.addEventListener(MouseEvent.RIGHT_CLICK, rightClick_h);
            form1 = new Form1();
            form1.name_input.text = "";
            form1.interfaceText.mouseEnabled = false;
            
            addChild(form1);
            addChild(drawingContainer);
            
            form1.ok_btn.addEventListener(MouseEvent.CLICK, btnClick_h);
        }
        
        private function rightClick_h(evt:MouseEvent):void
        {
            form1.title.gotoAndStop(form1.title.currentFrame % 2 + 1);
            form1.interfaceText.gotoAndStop(form1.interfaceText.currentFrame % 2 + 1);
        }
        
        private function calcData(year:intname:String):Array
        {
            var dataArray:Array = new Array(11);
            var md5:String = MD5.getMD5(name + year);
            var seed:int =parseInt("0x"+md5.slice(2, 6));
            var bmp:BitmapData = new BitmapData(220, 1);
            var luck:int;
            var offsets:Array = new Array(6);
            for (var j:int = 0; j < 6; j++)
            {
                offsets[j] = new Point(20*(new Date().getUTCFullYear()%30), 0);
            }
            
            /* 행운값 추출 */
            bmp.perlinNoise(120, 1, 6, seed,falsetrue, 7, true, offsets);
            for (var i:int = 0; i < 11; i+=1)
            {
                luck = Math.floor((Math.max(10, Math.min(80, (bmp.getPixel(i*20, 0) >> 16) / 255 * 100)) - 10) * (5 / 4));
                dataArray[i] = luck;
            }
            return dataArray.concat();
        }
        
        private function drawData(data:Array, dest:Sprite, form:Form1):void
        {
            dest.graphics.clear();
            
            /* 보조선 */
            dest.graphics.lineStyle(0.1, 0x666666);
            for (var i:int = 0; i < 11; i++)
            {
                dest.graphics.moveTo(calcX(i, form), calcY(100, form));
                dest.graphics.lineTo(calcX(i, form), calcY(0, form));
            }
            
            /* 그래프 */
            dest.graphics.lineStyle(2, 0xcc0033);
            dest.graphics.moveTo(calcX(0, form), calcY(data[0], form));
            for (var i:int = 1; i < 11; i++)
            {
                dest.graphics.lineStyle(2, 0xcc0033);
                dest.graphics.lineTo(calcX(i, form), calcY(data[i], form));
            }
        }
        
        private function calcY(value:int, form:Form1):Number
        {
            return form.point2_mc.y - (form.point2_mc.y - form.point1_mc.y) / 100 * value;
        }
        
        private function calcX(index:int, form:Form1):Number
        {
            return form.point1_mc.x + (form.point2_mc.x - form.point1_mc.x) / 10 * index;
        }
        
        private function btnClick_h(evt:MouseEvent):void
        {
            if (form1.name_input.text == "")
                return;
            var dataArray:Array = calcData(form1.age_input.value, form1.name_input.text);
            drawData(dataArray, drawingContainer, form1);
        
        }
    }
 
}

















 코딩을 하면서 각종 상황에 대한 테스트가 필요했기 때문에

Valve社의 게임에서 볼 수 있는 것과 비슷한 콘솔 창을 구현하기로 했다.  


 콘솔 창은 싱글턴 패턴으로 프로그래밍했는데

액션스크립트는 생성자 함수의 접근제한자로 private를 둘 수 없기 때문에

해당 클래스 파일의 패키지 외부에 클래스 하나를 더 두고

싱글턴 클래스 생성자의 매개변수로 그 클래스 타입을 넣어주어야 한다.

아래와 같은 모양이다.


package {

public class Singleton {

private static var instance...

public function Singleton(block:SingletonBlocker)

{

if (block == null) throw new Error...

}

public static function getInstance()...

}

}

class SingletonBlocker{}



 프로젝트의 클래스에서 콘솔 창에 뭔가를 표시하는 함수를 호출하면 

콘솔창이 없을 경우 새로 창을 띄우고 있으면 그 창에 내용을 출력한다.


 콘솔 창은 NativeWindow클래스를 사용하여 새 윈도우를 띄우게 되는데,

이 윈도의 크기가 원하는 대로 되지 않았다. 액션스크립트 도움말을 보면 

NativeWindow객체의 stage.stageWidth 나 Height속성을 조절하면 창 크기가 

그에 맞게 바뀐다고 하는데 전혀 그렇지가 않는 것이었다..


 해결책은 역시 도움말에 나와있었는데  

_mainWindow.stage.scaleMode = StageScaleMode.NO_SCALE;

_mainWindow.stage.align = StageAlign.TOP_LEFT;

이 두 구문이 있어야 제대로 창크기 조절이 된다.



코드를 컴파일후 실행시키니 제대로 출력이 나왔다.






 다음은 게임에서 사용할 월드 데이터 파일을 제작하는 간단한 툴을 만드는 것이었다.

FileStream클래스와 File클래스로 파일쓰기를 한다.


File객체를 만들 때, 파일쓰기 하려는 위치가 어플리케이션이 있는 폴더라면

var file:File = File.applicationDirectory;

와 같이 초기화해야 한다고 해서 그렇게 해 보니 보안문제로 오류가 났다.-_-;


이 경우에는 

var file:File = new File(File.applicationDirectory.nativePath);

file = file.resolvePath("하위폴더"+File.separator+파일이름+".확장자");

요렇게 하니까 되더라..


 그 다음 이렇게 해서 생성된 월드 데이터파일에 어플리케이션을 연결해 보기로 했다.

이 작업은 그리 어렵지 않게 할 수 있다.

if(NativeApplication.nativeApplication.isSetAsDefaultApplication("확장자")==false)

NativeApplication.nativeApplication.setAsDefaultApplication("확장자");

연결이 되어 있지 않으면 '이 어플리케이션'을 해당 file의 연결 프로그램으로 설정한다.

단, 응용 프로그램 설명자(xml파일)의 fileTypes노드에 파일의 정보가 선언되어 있어야 한다.


 빌드를 하니 128x128 아이콘 파일의 크기가 맞지 않는다는 오류가 계속 뜨는데

src폴더 내의 파일을 수정해도 빌드만 하면 다시 129x129크기의 파일로 바뀌어 버렸다.

bin-debug폴더에 들어있는 파일을 지우니 제대로 빌드가 되었다.



(▲ 데이터파일의 아이콘이 바뀐 모습. 실행하면 맵에디터가 열리고 해당 파일을 불러들인다.) 



하나 빼먹은 게 있어 추가로 적는데,

프로그램 연결은 연결프로그램으로 쓸 어플리케이션이 컴퓨터에 설치되어 있는 상태여야 한다. (디버그모드에서는 확인할 수 없다.)








 

+ Recent posts