Warning: opendir(/var/www/html/wp-content/mu-plugins): Failed to open directory: Permission denied in /var/www/html/wp-includes/load.php on line 981
이전에 사용하던 이 ProcessIndicator 를 Starling 용으로 만들어 보았습니다. 스탈링의 DisplayObject 와 기존 DisplayObject 는 거의 대동소이하므로 아무생각 없이 패키지만 스탈링으로 바꾸었습니다. 결과는…
잘 나오는데.. 어라 뭔가 이상하다~~~ 보통 이런 인디케이터의 경우 슬라이스의 각만큼 회전을 해야 합니다. 그런데 이 회전을 시키는 부분이 기존의 플래시와 스탈링이 약간 다릅니다. 기존의 rotation 은 360 즉 일반적인 각도로 회전하지만 스탈링의 rotation 은 라디안 값으로 회전합니다. 간단한거지만 아는데 반나절 걸렸음;;;; 그래서 원래 소스를 아래와 같이 변경 해야 합니다.
[as3]
rotation = rotation + (360 / slices) % 360; // degree 로 계산
rotation = deg2rad(( rad2deg(rotation) + (360 / slices)) % 360); // radian 으로 계산
[/as3]
어떤분들은 degree 와 radian 을 왔다갔다 할 필요가 있는지 궁굼해 하 실 수 있는데. 네, 없습니다. 처음부터 기준을 radian 으로 나눠 주면 저렇게 복잡하게 할 필요는 없습니다. 다만 spinnerSkin 을 플래시의 Shape 으로 만들기 때문에 이때는 degree 기준으로 슬라이스를 만들어야 합니다. 결국 조삼모사~ (제가 바꾸기 귀잖아서 그런거 절대 아님.)
전체 소스는 아래와 같습니다.
[as3]
package
{
import flash.display.BitmapData;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.TimerEvent;
import flash.utils.Timer;
import starling.display.DisplayObjectContainer;
import starling.display.Image;
import starling.events.Event;
import starling.textures.Texture;
import starling.utils.deg2rad;
import starling.utils.rad2deg;
public class ProcessIndicator extends DisplayObjectContainer
{
private var _spinnerSkin:Image;
private var timer:Timer;
private var slices:int;
private var radius:int;
private var _image:Image;
public function ProcessIndicator(slices:int = 12, radius:int = 6)
{
super();
this.slices = slices;
this.radius = radius;
spinnerSkin = makeSpinner();
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}
private function onAddedToStage(event:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
timer = new Timer(1000/30);
timer.addEventListener(TimerEvent.TIMER, onTimer, false, 0, true);
timer.start();
}
private function onRemovedFromStage(event:Event):void
{
removeEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
timer.reset();
timer.removeEventListener(TimerEvent.TIMER, onTimer);
timer = null;
}
private function onTimer(event:TimerEvent):void
{
spinnerSkin.rotation = deg2rad(( rad2deg(spinnerSkin.rotation) + (360 / slices)) % 360);
}
private function makeSpinner():Image
{
var i:int = slices;
var degrees:int = 360 / slices;
var slider:flash.display.Sprite = new flash.display.Sprite;
while (i–)
{
var slice:Shape = getSlice();
slice.alpha = Math.max(0.2, 1 – (0.1 * i));
var radianAngle:Number = (degrees * i) * Math.PI / 180;
slice.rotation = -degrees * i;
slice.x = (Math.sin(radianAngle) * radius)+radius*2;
slice.y = (Math.cos(radianAngle) * radius)+radius*2;
slider.addChild(slice);
}
var bitamp:BitmapData = new BitmapData(slider.width, slider.height, true, 0);
bitamp.draw(slider);
var texture:Texture = Texture.fromBitmapData(bitamp, false, false);
var spinner:Image = new Image(texture);
spinner.pivotX = spinner.width >> 1;
spinner.pivotY = spinner.height >> 1;
return spinner;
}
private function getSlice():Shape
{
var slice:Shape = new Shape();
slice.graphics.beginFill(0x222222);
slice.graphics.drawRoundRect(-1, 0, 2, radius, radius*2, radius*2);
slice.graphics.endFill();
return slice;
}
//=====================================================================
//
// getter & setter
//
//=====================================================================
public function get spinnerSkin():Image
{
return _spinnerSkin;
}
public function set spinnerSkin(value:Image):void
{
if(_spinnerSkin == value)
{
return;
}
if(_spinnerSkin)
{
removeChild(_spinnerSkin);
}
_spinnerSkin = value;
if(this._spinnerSkin && this._spinnerSkin.parent != this)
{
_spinnerSkin.visible = true;
_spinnerSkin.touchable = false;
addChild(_spinnerSkin);
}
}
}
}
[/as3]
원래 이번 포스팅의 목적은 radian 과 degree 의 집중분석이었으나 연속 포스팅으로 텐션이 떨어져서 소스 공유 정도로 마무리 하겠습니다.
[button url=”https://sewonist.com/wp-content/uploads/2013/03/ProcessIndicator.zip”]Download ProcessIndicator.zip[/button]
]]>Particle Designer 는 복잡한 파티클 효과를 GUI를 통해 간단히 제작 할 수 있도록 해주는 프로그램입니다. 이미 다양한 프리셋을 제공하므로 자신이 필요로 하는 효과와 유사한 효과를 기본으로 수정/저장 할 수 있습니다. 또 Starling 외에 cocos2d 등 다양한 플렛폼을 지원합니다. 다만 유료라는 점과 맥용 뿐이라는게 사용에 조금 걸림돌이긴 합니다. 제작사 사이트에서 파일저장이 되지 않는 무료버전을 다운받아 체험 해 볼 수 있습니다.
엄청난 수의 프리셋이 준비되어 있습니다.
썸네일을 클릭하면 상세설정을 할 수 있습니다.
선택한 파티클을 저장합니다. Starling에서 사용하기 위해서는 pex 포멧으로 저장 해야 합니다. 이때 옵션에 Embed texture가 있는데 Starling 에서는 텍스쳐를 따로 지정해 줘야 하므로 선택을 해제 하고 저장 합니다.
Particle Designer 가 유료라는 점과 특히 맥 전용이라는 점은 윈도우 유저에게 큰 문제가 아닐 수 없습니다. 무료버전으로는 파일 저장도 못하므로 테스트도 해 볼 수가 없습니다. Particle Editor는 이러한 고민을 단번에 해결 해 줍니다. Particle Designer 와 거의 유사한 옵션을 온라인에서 수정/저장 할 수 있습니다.
Particle Designer 와 같은 프리셋은 없으므로 제작은 조금 불편하지만 Particle Designer 의 상세설정을 보고 약간의 노고다를 하면 윈도우에서도 파티클을 만들 수 있습니다.
이제 옵션을 수정해서 필요로 하는 파티클 효과를 만들고 파일을 저장합니다. Particle Editor 에서 파일을 저장하면 particle.pex 와 texture.png 파일이 저장되는 것을 볼 수 있습니다. particle.pex는 각 설정을 담은 XML 파일이고 texture.png 는 파티클에 사용 할 텍스쳐 이미지 입니다.
Starling에서 파티클을 사용하기 위해서는 Particle System 을 따로 다운 받아야 합니다. Particle System 은 아래 링크에서 다운 받을 수 있습니다.
Starling Extension: Particle System
소스를 다운받고 기존의 starling 패키지에 복사해 줍니다. 그럼 이제 Starling 에서 파티클을 사용 할 준비가 완료되었습니다. 간단하게 예제소스를 살펴 보도록 하겠습니다.
[as3]
//===========================================================
//
// Starling implements
//
//===========================================================
import starling.core.Starling;
import starling.display.Image;
import starling.display.Sprite;
import starling.events.Event;
import starling.events.Touch;
import starling.events.TouchEvent;
import starling.extensions.ParticleDesignerPS;
import starling.textures.Texture;
internal class Game extends Sprite
{
[Embed(source="../embeds/particle.pex", mimeType="application/octet-stream")]
private const ParticleRef:Class;
[Embed(source="../embeds/texture.png")]
private const TextureRef:Class;
[Embed(source="../embeds/space.png")]
private const SpaceRef:Class;
[Embed(source="../embeds/ship.png")]
private const ShipRef:Class;
private var _space:Image;
private var _ship:Image;
private var _shipPosX:Number;
private var _particle:ParticleDesignerPS;
public function Game()
{
addEventListener(Event.ADDED_TO_STAGE, onAddedStage);
}
private function onAddedStage(event:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, onAddedStage);
initGame();
initParticle();
initListener();
}
private function initGame():void
{
_space = new Image(Texture.fromBitmap(new SpaceRef));
addChild(_space);
_ship = new Image(Texture.fromBitmap(new ShipRef));
_ship.x = _shipPosX = stage.stageWidth – _ship.width >> 1;
_ship.y = 60;
addChild(_ship);
}
private function initParticle():void
{
var config:XML = XML(new ParticleRef);
var texture:Texture = Texture.fromBitmap(new TextureRef);
_particle = new ParticleDesignerPS(config, texture);
_particle.emitterX = _ship.x + _ship.width / 2;
_particle.emitterY = _ship.y + _ship.height;
addChildAt(_particle, 1);
Starling.juggler.add(_particle);
_particle.start();
}
private function initListener():void
{
addEventListener(TouchEvent.TOUCH, onTouch);
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(event:Event):void
{
var targetX:Number = _shipPosX – (_ship.width/2);
_ship.x += (targetX – _ship.x) * .1;
_particle.emitterX = _ship.x + _ship.width / 2;
_particle.emitterY = _ship.y + _ship.height;
if(_space.y < 0){
_space.y += .5;
} else {
_space.y = -600;
}
}
private function onTouch(event:TouchEvent):void
{
var touch:Touch = event.getTouch(stage);
if(touch) _shipPosX = touch.globalX;
}
}
[/as3]
소스는 크게 어려운 부분은 없습니다. 처음에 필요한 자원을 임베드하고 이를 이용해서 초기화를 합니다. 파티클을 초기화 하는 부분만 보도록 하겠습니다.
[as3]
private function initParticle():void
{
var config:XML = XML(new ParticleRef);
var texture:Texture = Texture.fromBitmap(new TextureRef);
_particle = new ParticleDesignerPS(config, texture);
_particle.emitterX = _ship.x + _ship.width / 2;
_particle.emitterY = _ship.y + _ship.height;
addChildAt(_particle, 1);
Starling.juggler.add(_particle);
_particle.start();
}
[/as3]
Particle Designer 에서 저정한 particle.pex 와 texture.png를 이용해 파티클 시스템을 만듭니다. emitter는 파티클을 방출하는 방출기 입니다. emitterX, emitterY를 이용해 방출기의 위치를 조절 할 수 있습니다. 파티클 시스템을 다 만들었으면 마지막으로 Starling의 juggler 에 파티클 시스템을 등록 시켜 줍니다. juggler 는 Starling의 애니메이션 시스템으로 IAnimatable 인터페이스를 가진 클래스의 애니메이션을 실행시켜주는 역활을 합니다.
이제 파티클 시스템의 start함수를 실행하면 멋지게 불을 뿜는 파티클을 볼 수 있습니다.
Particle Designer 와 Starling을 이용하여 파티클을 만들어 보았습니다. 파티클을 이용하면 일반적으로 만들기 어려운 여러 효과들을 만들 수 있습니다. 또 게임에 적절히 이용하면 시각적으로 상당한 이펙트를 줄 수 있습니다. pex 파일을 열어보시면 알겠지만 Particle Designer 가 만들어주는 이 파일은 어떻게 파티클을 만들지에 대한 설정파일에 불과 합니다. 다만 이 설정이 생각보다 어렵지요.^^ 더 멋진 효과를 만들기 위해서는 차근차근 각 설정 옵션들을 테스트 해 볼 필요가 있습니다.
파티클을 Starling에 적용시키는 것 자체는 크게 어렵지 않으니 지금 한번 멋진 효과를 만들어 보시기 바랍니다.
[button url=”https://sewonist.com/wp-content/uploads/2013/01/StarlingParticle.zip”]Download Sources[/button]
]]>