Egloos 728x90

구글 애널리틱스


2013/01/05 01:26

터치한 방향을 향해 일정한 스피드로 이동하기 ▷▷프로젝트-Cream-A



※혹시나해서 미리 말합니다만 '일정한 스피드'라는 것이 '프레임 독립적'으로 일정하다는 의미는 아닙니다.

화면상의 이미지를 이동시키려면 x/y 좌표를 변경시켜서 그립니다. 이 작업을 일정하게 연속으로 하면 천천히 움직이는 것처럼 보이죠.

일정하게 3의 거리를 이동한다고 하면, 좌우로 움직이면 y좌표의 수치를 3만큼 빼거나 더하고, 상하로 이동시킬 땐 x좌표 수치를 3만큼 빼거나 더하면 되니 간단합니다. 그런데 그런 직각 위치가 아닌 45도 대각선으로 이동시키려면 어떻게 해야 할까요?

물론 x와 y 모두 3을 더하는 건 정답이 아닙니다. 수치상으로는 같은 3이지만 실제 거리상으로 보면 그것보다 길어지게 됩니다. 뭐 일단 그건 미뤄두고, 이번엔 45도가 아니라 15도로 이동시키려면 어떻게 해야 할까요? 50도로 이동시킬 때는요? 33도로 이동시킬 때는 어떻게 해야 할까요?

모든 각도를 향해 동일한 거리만큼만 이동한다고 하면, 그 도착점들을 모두 이으면 동그란 구 형태가 될 것입니다. 여기까지는 저도 이론적으로는 이해했습니다. 그런데 문제는 그 값을 어떻게 구해야 될 지를 도저히 모르겠더군요.

정답은 '터치한 방향으로 이미지 향하게 하기'와 마찬가지로 삼각함수에 있었습니다. 여러분 게임 개발자(뿐만 아니라 모든 프로그래머) 꿈꾸는 분들은 모두 학교 다닐 때 수학이랑 물리학 공부 열심히 하세요. 안 그럼 저처럼 나이 먹고 피똥 쌉니다. ㅡㅠㅡ

관련 내용은 지난 번과 마찬가지로 '시작하세요! 액션스크립트 3.0 애니매이션 / 키스 피터스 지음, 윤도선 옮김 / 위키북스'를 통해 익혔습니다.

사용할 삼각함수는 사인과 코사인입니다. Math.cos 메서드와 Math.sin 메서드를 사용하면 되는데, 둘다 인수로 각도(라디안)을 요구합니다. 각도는 지난 번 '터치한 방향으로 이미지 향하게 하기'에서 이용한 아크탄젠트, 즉 Math.atan2 메서드를 사용하는 방법 그대로입니다.

일단 지속적으로 움직여야 하기 때문에 스레드로 움직이게 하기 위해 Runnable 인터페이스를 구현한 클래스를 작성했습니다.

	--*
	 * 이미지의 좌표를 계속해서 갱신토록 한다.
	 * @author 별소리
	 *
	 --
	class Mover implements Runnable
	{
		private volatile boolean running;
		private Thread moverThread;
		
		
		--*
		 * 기본 생성자
		 --
		public Mover()
		{
			arrowSpeed = 5f;
		}
		
		
		@Override
		public void run()
		{
			while(running) {
				
				if ( ! surfaceHolder.getSurface().isValid() ) {
					continue;
				}
				
				String text = "x="+ touchX +", y="+ touchY;
				Log.d("Touch", text);
				
				Canvas canvas = surfaceHolder.lockCanvas();
				canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
				
				drawText(canvas, text);
				drawArrow(canvas);
				
				surfaceHolder.unlockCanvasAndPost(canvas);
			}
		}
		
		
		--*
		 * 스레드 실행
		 --
		public void resume()
		{
			running = true;
			moverThread = new Thread(this);
			moverThread.start();
		}
		
		
		--*
		 * 스레드 정지
		 --
		public void pause()
		{
			running = false;
			while (true) {
				try {
					moverThread.join();
					break;
				} catch (InterruptedException e) {
					// 재시도
				}
			}
		}
	}

스레드 관리를 위한 로직은 '시작하세요! 안드로이드 게임 프로그래밍 / 마리오 제흐너 지음, 유윤선 옮김 / 위키북스'의 내용을 참조했습니다.(그러고보니 참고한 책들이 다 위키북스 책이네요. 저 책장사 아닙니다ㅋ)

액티비티가 시작되거나 사라질 때 스레드도 시작되거나 정지될 수 있도록 관련 코드도 액티비티 클래스에 추가합니다.

	@Override
	protected void onResume()
	{
		super.onResume();
		
		this.mover.resume();
	}
	
	@Override
	protected void onPause()
	{
		super.onPause();
		
		this.mover.pause();
	}
	
	
	--*
	 * @param canvas
	 * @param text
	 --
	private void drawText(Canvas canvas, String text)
	{
		Paint p = new Paint();
		p.setColor(Color.WHITE);
		p.setTextSize(33);
		canvas.drawText(text, width / 2 - (p.measureText(text) / 2), height / 2, p);
	}
	
	
	--*
	 * 이미지 그리기
	 * @param canvas
	 --
	private void drawArrow(Canvas canvas)
	{
		float deltaX = touchX - arrowX;	//touchX - arrowX
		float deltaY = touchY - arrowY;	//touchY - arrowY
		double radians = Math.atan2(deltaY, deltaX);
		Log.d("Touch", "radians="+ radians);
		float rotation = (float) (radians * 180 / Math.PI);
		
		float velocityX = (float) (Math.cos(radians) * arrowSpeed);
		float velocityY = (float) (Math.sin(radians) * arrowSpeed);
		arrowX += velocityX;
		arrowY += velocityY;
		
		canvas.save();
		canvas.rotate(rotation, arrowX, arrowY);
		canvas.drawBitmap(arrow, arrowX - (arrow.getWidth() / 2), arrowY - (arrow.getHeight() / 2), null);
		canvas.restore();
	}

어느만큼 이동해야 할 지가 필요하기 때문에 arrowSpeed를 곱해줍니다. arrowSpeed가 이동력이라고 생각하시면 됩니다.

지난 번에는 터치 리스너에서 이것저것 작업을 했는데, 이번에는 스레드로 다 옮겨가서 횡~해졌습니다.

		surfaceView.setOnTouchListener(new View.OnTouchListener()
		{
			
			@Override
			public boolean onTouch(View v, MotionEvent event)
			{					
				touchX = event.getX();
				touchY = event.getY();
				
				return true;
			}
		});

지난 번과 마찬가지로 기타 코드는 생략했습니다.

이렇게 두가지를 알았으니 남은 건 대포가 포탄을 뻥뻥 쏴대게 만들면 됩니다. 그런데, 지금까지 샘플 코드 만들면서 대포 이미지가 없어서 친구 사진을 대신 사용했는데, 그 친구가 자기가 불을 뿜는 걸로 만들길 원하는군요....

다음 번에는 제 친구가 불을 뿜는 모습을 보실 수 있을 지도 모르겠습니다....

여하튼 다음은 직선 궤도로 날아가는 탄, 그 다음에는 아마 곡선으로 발사되는 탄을 만들어볼 것 같습니다.


덧글

댓글 입력 영역

애드센스336x280

알라딘TTB-Egloos(하단-일반)



이 이글루를 링크한 사람 (블랙)

36