몇 일전 저는 뜻하지 않게 감동적인 선물을 받았습니다. "마로의 꿈 - 액션스크립트 3.0으로 배우는 소셜 게임 프로그래밍" 이라는 이명희/김종훈 님이 쓰신 책이였습니다.

몇 번 책선물을 받은 적이 있지만 이번 책은 너무도 특별했습니다. 바로 저자인 이명희님께서 직접 엽서까지 보내서 선물로 주신 겁니다. 사실 이명희님를 만난 적이 없는 것 같습니다.(제가 오프라인 활동을 너무 안하다 보니...) 이명희님께서는 원래 C/C++ , Java등 다른 분야에서 개발하시던 분인데 게임 개발을 위해 ActionScript 3.0을 접하시다가 제 블로그를 알게 되었다고 합니다. 책을 보낸 이유는 제 블로그를 통해 도움을 많이 받아 감사하다는 것이였습니다. 초판 날짜를 보니 아마도 발행되자마자 바로 보내셨더군요. 정말 감동이였습니다.

처음에는 다 그렇듯이 Flash 개발이 쉽다고들 하지만 그것은 어디까지나 Flash IDE를 통해 디자인적 접근이 그러한 것이고 게임처럼 고도의 경험과 기술이 들어가는 분야로 접근하면 다른 언어와 마찬가지로 어려운 것은 사실입니다. 왜냐하면 Flash 게임개발은 그 분야대로 노하우가 필요한 것은 분명하니깐요. 아마도 diebuster(http://diebuster.com)을 방문해서 글을 보신 경험이 있다면 Flash가 결코 만만하지는 않구나라는 생각이 들겁니다. Flash가 대중적이긴하나 VM이기 때문에 속도와 질을 극대화 시키는 것은 쉽지 않거든요. 특히나 게임분야는 말할 것도 없지요.

책 소개를 해야겠네요. 이 책은 "마로의 꿈"이라는 게임을 기반으로 쓰여진 책입니다. 저자가 직접 간단한 소셜게임을 만들었고 그 게임에 녹아있는 각종 스킬을 소개하는 내용을 담았습니다. 마지막에는 게임에 사용된 인공지능 및 소셜게임을 네이버에 등록하는 방법도 소개합니다. 게임은 2D지만 여느 소셜게임처럼 3D 느낌을 다룹니다. 자원생성, 자원관리, 지도제작, 아바타 제작 및 애니메이션등 정말 소셜게임이 필요한 핵심내용을 담고 있습니다. 게임이라는 특성상 진부하고 어려운 내용을 담을 것 같지만 실제로 이 책은 300페이지가 채안되면서도 간단하고 명쾌하게 설명해주고 있어서 처음 소셜게임에 입문하시는 분들에게는 국내서적으로 이만한 책은 없다고 생각합니다.

국내에서 IT서적하면 항상 인기부류인 기초를 다루는 책이 나오는 것이 실상임에도 이런 책이 출판이 될 수 있었다는 것도 참 신기합니다. 요즘 스마트폰 붐으로 약간 침체된듯한 국내 Flash분야에 활기를 불어넣는데 이 책이 일조할 수 있을 것이라 생각합니다.

글쓴이 : 지돌스타(http://blog.jidolstar.com/736)

이번에 남아공 월드컵이 있어 스타플(http://starpl.com) 에서 관련 이벤트를 하고 있습니다.


여기서는 개발자분이라면 다들 궁금해하시는 기술적(?) 설명을 드릴까 합니다.

축구게임은 Flash로 만들었습니다. Flash로 게임제작은 처음해보는 것이라 생각보다 여러 어려움이 있었습니다.
  • 제작툴 : Flash Builder 4.0 Eclipse plug-in 버전
  • 언어 : ActionScript 3.0 (Flex는 사용안함)
  • 동작환경 : Flash Player 10 이상
  • 사용한 공개라이브러리 : Papervision3d(3d엔진), jiglibflash(3D 물리엔진), TweenMax(트윈엔진)
  • 제작기간 : 10일
  • 키워드 : 축구게임엔진, 물리엔진, 3D, 게임상태변화, 사운드, 랭킹시스템, MVC

축구라는 소재를 어떻게 풀어가야할까 고민을 많이 했습니다. 그러다가 3D와 물리엔진을 도입할 필요를 느꼈고 간단하게 Away3d+jiglibflash 또는 Papervision3d+jiglibflash 로 테스트를 해봤습니다. 관련 내용은 이미 http://blog.jidolstar.com/689 에 공개했었고요.

하지만 게임이 만만치 않은게... 저 정도로 끝나지 않는다는 겁니다. 자원관리, 속도향상, 게임상태변화, 사운드등 여러가지 다양한 문제가 있더군요. 하나하나 해결해 가면서 완성해 나갔습니다. 가장 어려웠던 부분은 사운드였습니다. 디자인 부분이야 우리 회사에 막강한 캐릭터 디자이너가 있어서 문제가 없었는데... 사운드는 그런 사람이 전혀 없다보니 자원을 찾고 편집하는데 시간을 너무 소비했죠. 물론 무료를 찾느라고 시간을 다 보낸겁니다. 역시 개발자가 디자인, 음원편집을 할 수 없듯이 그에 적절한 사람을 알아두는 것도 좋을 것 같습니다.

전체적으로는 정말 간단한 게임입니다. 너무 단순해서 10일이나 걸려서 만든게 시간이 아깝다는 생각이 드네요. 다음에 만들면 더 속도를 낼 수 있겠죠? ^^

아래는 스크린 샷입니다. 구경하시죠.




하는 방법은 매우 단순합니다. 공을 찰 지점을 마우스로 선택하고 마우스 Down으로 힘조절을 한뒤 마우스 Up하면 공이 차지는 방식입니다. 공 차는 지점을 정확히 잡고 힘조절을 잘할 필요가 있습니다.

환경적 요소로 골대, 골키퍼, 수비수, 바람등이 있습니다. 레벨이 올라갈때마다 수비수가 늘어나며, 바람도 더 세집니다. 1골당 점수도 높아지죠. 골위치도 랜덤하게 되므로 높은 점수 얻는건 쉽지 않을겁니다. 스타플(http://starpl.com/)에 연계되어 최고점수를 기록하면 자신의 별에 기록되는 기능도 포함합니다.

이 게임은 2D 처럼 보이지만 그건 배경만 그렇고 실제 움직임은 전부 3D입니다. 골대도 안보이지만 3D 골대가 배치 되어 있죠. ^^ 만약 Papervision3D와 jiglibflash와 같은 공개라이브러리를 사용하지 않았다면 10일이라는 짧은 시간안에 이런 게임 만드는 것은 거의 불가능입니다. 나름 고급기술 사용했다는... ㅋ

하지만 Flash에서 3D 엔진과 물리엔진은 속도에 지극히 악영향을 줍니다. 그래서 적절한 합의점을 찾아가야 합니다. 완성본에는 공의 그림자도 모두 표현되어 있었지만 저급 PC에서 FPS가 나오지 않아서 제외시킨게 그 예이죠. 아쉽다는.... 그리고 Papervision3D 보다 Away3dlite를 이용했으면 더 좋았을 뻔 했습니다. 아무래도 Flash Player 10에서 3D API를 제공하기 때문에 이를 이용해서 만들어진 Away3dlite가 퍼포먼스 측면에서는 더 이득일 겁니다. 하지만 표현력에 있어서는 Papervision3D가 더 우세라는...

3D 물리엔진으로 jiglibflash를 사용했습니다. wow엔진이라는 것이 있는데... 이는 망한듯 합니다. 더 이상 업데이트도 안되고요. 그나마 jiglibflash가 튜토리얼도 있고 어느정도 예시도 있어서 사용했죠. jiglibflash는 papervision3d, away3d, away3dlite, sandy3d등 다양한 3D 엔진에 대응하여 물리엔진을 도입할 수 있도록 반쪽짜리 추상층을 제공합니다. 아무튼 이것을 이용하면 별 무리없이 물리엔진과 같은 효과를 만날 수 있죠. 하지만 FPS에 따라서 다르게 결과가 나오는 부분이 있어서 그다지 실용적이지는 못합니다. 말이 물리엔진이지... 그냥 눈속임이라는... 어쨌든 그나마 있어서 유용하게 썼습니다.

이 게임은 아쉽게도 1회성 이벤트 용입니다.

축구게임 이벤트 : http://starpl.com/#/main/event/big/ing/view/48

이벤트용이므로 게임을 즐기시려면 스타플(http://starpl.com)에 가입하셔야 합니다. ^^

글쓴이 : 지돌스타(http://blog.jidolstar.com/691)
게임에서 키보드 제어는 가장 기본이면서 중요하다. 요즘 Flash 관련 게임을 제작해보겠다는 열의를 가지고 이것저것 테스트 해보고 있는데 게임 분야는 워낙 방대하고 알아야할 것도 많아서 계속 도전하고 싶은 충동을 강하게 만든다.

일단 가장 기본적인 슈팅게임을 만들어보겠다는 목표를 세웠다.

원더플(http://wonderfl.net)에 올라오는 다양한 완성된 게임들을 보면서 나름대로 코드를 분석하고 정리하면서 하나씩 완성해 나가고자 한다.

키보드 제어에 대해서는 Hika님의 글이 매우 유용하다.

마우스/키보드의 인터렉션 최적화 2/2

나는 키보드 제어에 대한 기본 지식을 위 글을 통해서 공부했고 뭔가 슈팅게임을 위한 적당한 클래스를 만들어봤야겠다는 생각을 했다. 좀 더 범용적인 클래스가 좋겠다고 했는데.. 마침 원더플에 올라온 KeyMapper 클래스가 눈길을 끌었다.


// Key mapper
//----------------------------------------------------------------------------------------------------
class KeyMapper {
	public var flag:int=0;
	private var _mask:Vector.=new Vector.(256, true);

	function KeyMapper(stage:Stage):void {
		stage.addEventListener("keyDown", function(e:KeyboardEvent):void { flag|=_mask[e.keyCode]; });
		stage.addEventListener("keyUp", function(e:KeyboardEvent):void { flag&=~(_mask[e.keyCode]); });
	}

	public function map(bit:int, ... args):KeyMapper {
		for (var i:int=0; i < args.length; i++) {
			_mask[args[i]]=1 << bit;
		}
		return this;
	}
}

매우 단순하고 아름답기 까지 하다. ㅎㅎ
사용법은 꽤 간단하다. 아래는 사용할 키를 등록하는 방법이다.

// keyboard mapper
_key=new KeyMapper(stage);
_key.map(0, 37, 65).map(1, 38, 87).map(2,39,68); //좌 : Left(37), A(65); 위:Up(38),W(87); 우:Right(39),D(68)

_key.map() 메소드의 첫번째 인자값은 해당 키가 눌려졌을때 참조할 bit위치이다. 2번째 부터는 이 bit위치가 변경되기 위한 키코드를 넣을 수 있다. 가령 0번 bit에 Left키 또는 A키를 눌렀을때 bit가 on될 수 있도록 한다.

사용된 키코드는 KeyboardEvent가 발생할때 이벤트의 keyCode속성에 나오는 코드이다. 이 값은 범용적으로 약속된 값으로 다음 글에서 참조하길 바란다.

키코드값 표

KeyMapper에 등록된 키들은 EnterFrame 이벤트 발생되는 시점에서 다음과 같이 사용하면 된다.

var inkey:int = _key.flag;
//회전
ar=(((inkey & 4)>>2) - (inkey & 1))*0.5; //회전가속
vr += ar; //회전속도
r += vr; //회전값
ar *= .96; //계속 증가 못하도록 방지
vr *= .92; //계속 증가 못하도록 방지
( r < 0 ) ? r += 360 : ( r > 360 ) ? r-=360 : 0; //0~360으로 Normalization

//이동
a = -((inkey & 2)>>1)*1.2; //가속
ax = a * Math.sin((360-r)*D2R); //가속 x성분
ay = a * Math.cos((360-r)*D2R); //가속 y성분 
vx += ax; //속도 x성분
vy += ay; //속도 y성분
x += vx; //위치 x성분
y += vy; //위치 y성분 
ax *= .96; //계속 증가 못하도록 방지
ay *= .96;
vx *= .90;
vy *= .90;



즉 inkey & 4(10진수)는 inkey & 100(2진수)과 같다. 즉 3번째 bit의 값이 on이냐 off이냐에 따라서 3번째으로 지정된(여기에서는 우측이동키 또는 D)키가 눌려졌는지 알 수 있다. 이 값에 shift연산자로 >>2를 하면 눌려졌으면 1, 안눌려졌으면 0을 참조할 수 있게 된다.

이처럼 키보드를 참조하기 위해 if문이 아닌 bit연산으로 참조함으로 이 부분에 있어서 더 빠른 참조가 가능해진다고 본다.

단지 현재 이 KeyMapper 클래스는 키동작의 순서를 담지 않기 때문에 액션대전게임등과 같은 것을 만드려면 그와 관련된 Key동작을 mapping할 수 있는 것이 필요할 것이다.

필자는 이것으로 한대의 비행기를 회전, 이동하는 Flash 애플리케이션을 간단하게 만들어봤다.


보러가기 : http://wonderfl.net/code/53e6c9b9ed9a776dd45b529304937d13ea9398ac

참고로 비행기는 아래 이미지를 참고했으며 출처는 다음 링크에 있다.
http://www.brighthub.com/internet/web-development/articles/11010.aspx



위 이미지를 회전시켜 BitmapData를 만드는 방법은 다음글을 참고한다.
Flash 속도 개선을 위한 실험 - 10만개 입자 유체 시뮬레이션 연장전!


추가사항

hika님께서 댓글로 다음처럼 지적해주셨습니다.

결사반대!
그러니까 80년대에 사용하던 비트or연산 합체는 제발 지양해주세요.
그 원조인 c업계에서도 철폐를 위해 노력하고 있습니다.
코드는 점점 암호화 되고 그걸 다시 가시화하기 위해 엄청난 const를 잡게 됩니다. 나락으로 빠지는 길이죠.
빠른 벡터를 컨테이너로 사용하세요 ^^

var keyDown:Vector.<Boolean> = new Vector.<Boolean>();

stage.addEventListener("keyDown", function(e:KeyboardEvent):void { keyDown[e.keyCode] = true; });
stage.addEventListener("keyUp", function(e:KeyboardEvent):void { keyDown[e.keyCode] = false; });

if( keyDown[Keyboard.UP] ){

if( keyDown[Keyboard.SHIFT] ){
   if( keyDown[Keyboard.SPACE] ){

이러한 코드는 가독성만 좋은게 아닙니다.
http://help.adobe.com/ko_KR/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7d01.html
이 문서를 보세요.

키와 키 코드의 매핑은 장치 및 운영 체제에 따라 다릅니다. 따라서 키 매핑을 사용하여 액션을 트리거해서는 안 됩니다. 대신에 Keyboard 클래스에서 제공하는 미리 정의된 상수 값을 사용하여 적당한 keyCode 속성을 참조해야 합니다. 예를 들어, Shift 키의 키 매핑 대신 Keyboard.SHIFT 상수를 사용하십시오

이러한 멘트가 나옵니다. 플래시플레이어는 운영체제 버전에 따라 키코드값을 적절하게 매핑해주기 때문에 개발한 게임이 맥에서 안도는 사태를 막아줍니다 ^^

여하튼 그 모든걸 떠나서 결국 38, 39를 외우는 것도 무리고 코드를 해석하기 위해 맨날 키코드표를 참조한다는것도 말도 안되고 그 결과 const를 도입해서 느려지는 식입니다.

저 방식은 원더플에 올라오는 수준이거나 데모를 만드는 수준에서만 키셋이 몇개 없을때 통용되는거지 실제 게임에서 유저가 키셋팅을 커스터마이즈하는 것도 흔하고 플래시 특성상 이기종에서 실행되는것도 흔하기 때문에 아니되옵니다 ^^


네.. 중요한건 Adobe문서에 잘 나와있었다는 거죠 ^^;
그래서 기존 KeyMapper를 버리고 새로운 형태로 만들어봤습니다.


class Key {
	static private var _down:Vector.=new Vector.(256, true);
	static private var _stage:Stage;

	static public function start($stage:Stage):void {
		stop();
		if (Capabilities.hasIME) {
			IME.enabled=false;
		}
		if ($stage === null) {
			throw new Error("인자값이 null이면 안됩니다.");
		}
		_stage=$stage;
		_stage.addEventListener("keyDown", KEY_DOWN);
		_stage.addEventListener("keyUp", KEY_UP);
	}

	static public function stop():void {
		if (Capabilities.hasIME) {
			IME.enabled=true;
		}
		if (_stage) {
			_stage.removeEventListener("keyDown", KEY_DOWN);
			_stage.removeEventListener("keyUp", KEY_UP);
		}
	}

	static private function KEY_DOWN($e:KeyboardEvent):void {
		_down[$e.keyCode]=1;
	}

	static private function KEY_UP($e:KeyboardEvent):void {
		_down[$e.keyCode]=0;
	}

	static public function isDown($keyCode:int):int {
		return _down[$keyCode];
	}
}


IME 부분은 한글로 입력되어 제대로된 키코드가 들어오는 것을 방지하기 위함입니다.(이 부분은 좀더 생각해볼 필요가 있을듯..) Vector를 Boolean말고 int로 한 것은 간단한 연산처리가 필요한 경우에 활용하기 위함입니다. 이렇게 해두면 호스트쪽은 아래처럼 참조하면 됩니다.
var a:Number; //inkey:int = _key.flag;
var right:int=Key.isDown(KEY_RIGHT) | Key.isDown(KEY_D);
var left:int=Key.isDown(KEY_LEFT) | Key.isDown(KEY_A);
var up:int=Key.isDown(KEY_UP) | Key.isDown(KEY_W);

// rotation
ar=Number(right - left) * 0.5; //ar=(((inkey & 4)>>2) - (inkey & 1))*0.5;
vr+=ar;
r+=vr;
ar*=.96;
vr*=.92;
(r < 0) ? r+=360 : (r > 360) ? r-=360 : 0;

// move
a=-Number(up) * 1.2; //a = -((inkey & 2)>>1)*1.2;
ax=a * Math.sin((360 - r) * D2R);
ay=a * Math.cos((360 - r) * D2R);
vx+=ax;
vy+=ay;
x+=vx;
y+=vy;
ax*=.96;
ay*=.96;
vx*=.90;
vy*=.90;


이렇게 함으로써 가독성 향상도 되고 운영체제에 따른 다른 키코드에 대한 대응도 되겠네요. 

물론 KEY_DOWN, KEY_UP등은 Keyboard.DOWN, Keyboard.UP값으로 정의했습니다. 

사실... Key.isDown($keyCode:int) 대신 Key.isDown(...args)로 하려고 했는데... 이게 문제인것이 |연산인지 &연산인지 호스트 코드를 작성하는 입장에서는 저 함수명으로는 알기 힘들어지고... 사실 이런 요구가 계속 넘쳐날것 같아서 결국 가장 간단하게 만들어놓고 필요하면 그때그때 대응하는 편이 훨씬 좋다는 판단을 했습니다.

아무튼 좋은거 배웠습니다. 감사합니다.

결과 : http://wonderfl.net/code/23e1ea553ffa7994af88933059c1a55b04e683eb


참고
원더플(wonderfl.net)
마우스/키보드의 인터렉션 최적화 2/2
키코드값 표
Flash 속도 개선을 위한 실험 - 10만개 입자 유체 시뮬레이션 연장전!
원더플(Wonderfl)을 이용해 ActionScript 3.0을 공부하자. - 자동 테스트 환경 구축 소개

글쓴이 : 지돌스타(http://blog.jidolstar.com/672)

+ Recent posts