일반적으로 키보드를 감추기 위해  [myTextField resignFirstResponer] 메소드를 사용하실 겁니다.
UIViewController가 전환할때는 기존 ViewController에 떠 있던 키보드가 자동으로 감춰집니다. 

하지만  firstResponder의 출처를 찾기가 곤란한 경우도 있습니다. 가령.. 저의경우 
중간에 네트워크가 중지되거나 점검페이지등을 붙일때 Controller가 아닌 UIView를 직접 사용해 window의 최상위에 붙이게 되는 경우가 있는데, 이때 ViewController에 키보드가 보여져 있으면 이 페이지 위에 키보드가 그대로 남게 되는 경우가 발생합니다.

꼭 위와 같은 경우가 아니더라도 키보드가 어디를 기준으로 보이든지 감춰줄 수 있는 메서드가 필요했습니다.
저는 아래 메서드를 공통으로 사용할 수 있는 클래스(가령 AppDelegate)에 정의해놓고 언제든지 키보드를 감출 수 있도록 합니다.
여기서 호출할 메소드는 hideKeyboard  입니다. _hideKeyboardRecursion은 제귀함수로 직접 호출하지는 않습니다.

//키보드를 사라지게 하기 위해 사용하는 재귀함수 

- (void)_hideKeyboardRecursion:(UIView*)view 

{

if ([view conformsToProtocol:@protocol(UITextInputTraits)]) 

{

[view resignFirstResponder];

}

if ([view.subviews count]>0

{

for (int i = 0; i < [view.subviews count]; i++) 

{

[self _hideKeyboardRecursion:[view.subviews objectAtIndex:i]];

}

}

}


//키보드 감추기

- (void)hideKeyboard 

{

UIWindow *tempWindow;


for (int c=0; c < [[[UIApplication sharedApplication] windows] count]; c++) 

{

tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:c];

for (int i = 0; i < [tempWindow.subviews count]; i++) 

{

[self _hideKeyboardRecursion:[tempWindow.subviews objectAtIndex:i]];

}

}

}


혹시 부족한 점 있으면 보완 부탁드릴께요. 

글쓴이 : 지돌스타(http://blog.jidolstar.com/727)
게임에서 키보드 제어는 가장 기본이면서 중요하다. 요즘 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