상세 컨텐츠

본문 제목

JetBoy 따라하기 #4 - 우주선 이동

프로그래밍/Android

by ryujt 2010. 12. 27. 23:38

본문

이번에는 우주선 이동 기능을 추가하도록 하겠습니다.  일단, 우주선을 이동하는 방법이 무엇들이 있는 지 잠시 살펴보고 가겠습니다.



객체 이동의 처리 방법

일반적으로 스마트 폰에서 객체를 이동시키기 위한 인터페이스로는 아래와 같은 3가지 방법을 취할 수가 있습니다.
  • 키보드 이벤트
  • 모션 이벤트 (스크린 터치)
  • 방향 센서

이 중에서 키보드로 이동하는 것이 어려운 기종도 있긴 하겠지만, 상당히 기초적인 방법이기 때문에 함께 설명하도록 하겠습니다.

이러한 이동 처리 문제는 자주 반복되서 사용되기도 하고, 현재 우리가 움직이려는 우주선 객체 내부에 코딩을 하면 코드를 읽기 어려워질 것이므로, 새로운 클래스를 만들어서, 이 기능을 위임하도록 하겠습니다.  그리고, 그 이름을 JoyStick 이라고 하겠습니다.


[그림 1] JoyStick의 초기 설계

우선 [그림 1]과 같이 Ship 객체가 직접 JoyStick을 의존하는 형태로 사용하기로 했습니다.  하지만, 나중에 예제를 작성하는 과정에서 JoyStick이 외부 다른 객체에서 호출되는 일이 없었기 때문에, Ship 내부의 멤버로 선언하여 캡슐화 하였습니다.

일단, JoyStick 제공하는 주요 기능들의 의미를 살펴보겠습니다.
  • public void Tick(long tick)
    • 우리가 현재 사용하고 있는 게임 엔진은 프레임을 주기적으로 그려주고 있습니다.  이 주기마다 Tick이라는 메소드를 실행시켜서 해당 주기 동안 움직여야 할 거리를 계산해 줍니다.
  • public int getX(), public int getY()
    • 객체의 현재 위치를 알려줍니다.
  • public void setSpeed(int value)
    • 객체가 초당 움직이는 픽셀 수를 지정합니다.
    • 대각선으로 움직일 때에는, X축과 Y축 모두 value에 해당하는 속도로 움직이기 때문에, 실제 속도는 √2 만큼 빨라지게 됩니다.  하지만, 큰 문제는 없기 때문에 이런 점은 무시하고 작성하였습니다.
  • public void setBoundaryLimit(boolean useBoundaryLimit, ...)
    • 객체가 이동하다가 경계선에서 멈춰서야 할 경우, useBoundaryLimit를 true로 지정해 줍니다.
    • 생략된 다른 파라메터들은 소스에서 설명하도록 하겠습니다.  (경계영역에 관한 파라메터)
  • public void onKeyDown(GamePlatformInfo platformInfo, int keyCode, KeyEvent msg)
    • JoyStick에게 KeyDown 이벤트가 발생한 것을 알려서 방향을 바꾸는 등의 작업을 하도록 합니다.
  • public void onKeyUp(GamePlatformInfo platformInfo, int keyCode, KeyEvent msg)
    • JoyStick에게 KeyUp 이벤트가 발생한 것을 알려서 방향을 바꾸는 등의 작업을 하도록 합니다.
  • public void onTouchEvent(GamePlatformInfo platformInfo, MotionEvent event)
    • JoyStick에게 Touch 이벤트가 발생한 것을 알려서 방향을 바꾸는 등의 작업을 하도록 합니다.
  • public void PrepareOrientationSensor(Context context)
    • 방향 센서를 사용하겠다고 알리게 됩니다.



키보드 이벤트를 이용한 이동 처리

이해를 돕기 위해서 JoyStick이 적용된 Ship.java의 소스를 먼저 살펴보도록 하겠습니다.

[소스 1] Ship.java
package app.main;

import ryulib.game.GameControl;
import ryulib.game.GameControlGroup;
import ryulib.game.GamePlatformInfo;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.KeyEvent;
import app.resources.ResourceShip;

public class Ship extends GameControl {

	private static final int _ANIMATIONINTERVAL = 100;
	private static final int _SPEED = 150;
	
	public Ship(GameControlGroup gameControlGroup) {
		super(gameControlGroup);
	
	}

	private Canvas _Canvas = null;
	private Paint _Paint = null;
	
	private JoyStick _JoyStick = new JoyStick(_SPEED);
	
	private AnimationCounter _AnimationCounter = 
		new AnimationCounter(
				_ANIMATIONINTERVAL, 
				ResourceShip.getInstance().getCount()
		);
	
	@Override
	protected void onStart(GamePlatformInfo platformInfo) {
		_Canvas = platformInfo.getCanvas();
		_Paint = platformInfo.getPaint();
		
		_JoyStick.setBoundaryLimit(
				true, 
				0, 0, _Canvas.getWidth(), _Canvas.getHeight(),
				ResourceShip.WIDTH, ResourceShip.HEIGHT
		);
	}
	
	@Override
	protected void onTick(GamePlatformInfo platformInfo) {
		long tick = platformInfo.getTick();
		
		_AnimationCounter.Tick(tick);
		_JoyStick.Tick(tick);
	}
	
	@Override
	protected void onDraw(GamePlatformInfo platformInfo) {
		_Canvas.drawBitmap(
				ResourceShip.getInstance().getBitmap(_AnimationCounter.getIndex()), 
				_JoyStick.getX(), _JoyStick.getY(), 
				_Paint
		);
	}
	
	@Override
	protected boolean onKeyDown(GamePlatformInfo platformInfo, int keyCode, KeyEvent msg) {
		_JoyStick.onKeyDown(platformInfo, keyCode, msg);
		return true;
    }

	@Override
    protected boolean onKeyUp(GamePlatformInfo platformInfo, int keyCode, KeyEvent msg) {
		_JoyStick.onKeyUp(platformInfo, keyCode, msg);
		return true;
    }
    
}
24: JoyStick의 생성자의 파라메터를 통해서 초당 몇 픽셀 씩 움직여야 하는 지를 전달하고 있습니다.

37-41: 우주선이 넘어 설 수 없는 공간의 한계를 정의하고 있습니다.

38: 이미 언급한 것처럼 우주선이 움직일 수 있는 영역을 제한 할 것인지를 결정합니다.  true이기 때문에 우주선이 다음에 오는 파라메터가 가르키는 영역 안에서만 움직입니다.  만약 이것을 false로 변경하면, 우주선은 화면 밖으로까지 움직일 수 있게 됩니다.

39: 우주선이 움직일 수 있는 영역입니다.  (left, top, right, bottom) 형식입니다.

40: 우주선의 가로 세로 크기입니다.  영역을 넘어가느냐 마느냐를 결정 할 때 우주선의 크기도 영향을 주기 때문입니다.

49: 주기적으로 Tick() 메소드를 호출하여, 얼마나 움직여야 하는 지를 계산하도록 합니다.

56: 계산된 결과 getX(), getY() 좌표에 우주선을 표시합니다.

61-65: 키보드가 눌려졌을 때, 실행되는 메소드 입니다.  63: 라인을 통해서 JoyStick 객체에게 전달합니다.  키보드 이벤트를 통해서 우주선이 어느 방향으로 움직여야 할지가 전달됩니다.

67-71: 키보드가 떼졌을 때 실행되는 메소드 입니다.  69: 라인을 통해서 JoyStick 객체에게 전달합니다.  아까 전달된 방향 설정을 취소하게 됩니다.  "이제 키보드를 누르지 않으니까, 우주선을 멈춰!"라는 의미가 됩니다.

여기서 주의 할 점은, 우리가 사용하는 게임 엔진(게쪽)은 키보드와 모션 이벤트를 사용하고자 할 때, 아래와 같은 메소드로 각각의 이벤트를 사용한다고 알려줘야 한다는 점 입니다.
  • GamePlatform.setUseKeyEvent(true);   
  • GamePlatform.setUseMotionEvent(true);

예제에서는 Main.java에 아래와 같이 추가되어 있습니다.
        _GamePlatform = new GamePlatform(this);
        _GamePlatform.setLayoutParams(
        		new LinearLayout.LayoutParams(
        				ViewGroup.LayoutParams.FILL_PARENT, 
        				ViewGroup.LayoutParams.FILL_PARENT, 
        				0.0F
        		)
        );
        _GamePlatform.setUseKeyEvent(true);
        _GamePlatform.setUseMotionEvent(true);

에뮬레이터를 통해서 제대로 동작하는 것을 제가 확인해봤으니, 여러분들도 한 번 테스트 해 보시기 바랍니다.   JoyStick의 구현은 다른 이벤트 처리를 설명한 이후 한꺼번에 설명하도록 하겠습니다.



모션 이벤트를 이용한 이동 처리

모션 이벤트를 이용할 때에는 주로 화면 전체를 활용하는 방법과, 화면에 이동과 관련된 컨트롤을 띄워서 이것이 눌러졌을 때 처리하는 방법이 있습니다.  여기서는 화면의 일부분을 이용해서 해당 부분이 눌러지면 우주선을 그 위치에 옮겨지도록 하겠습니다.

[그림 2] 모션 이벤트를 이용한 이동이 예

모션 이벤트를 이용한 이동에서는 우주선을 위 아래로만 움직일 수 있도록 해봤습니다.  키보드 이벤트의 경우처럼 사방으로 움직여도 되지만,  코드를 단순하게 하여 설명하기 위해서 입니다.

위 아래로 그어진 빨간선 안쪽에서 눌러지면 이동, 그 밖의 영역은 레이저 발사를 하도록 할 예정이었습니다.  지금의 예제에서는 이동까지만 구현 할 것 입니다.

[소스 2]는 모션 이벤트를 적용한 Ship.java의 내용입니다.

[소스 2] 모션 이벤트를 적용
	@Override
    protected boolean onTouchEvent(GamePlatformInfo platformInfo, MotionEvent event) {
		int x = (int) event.getX();

		if (x <= ResourceShip.WIDTH) {
			_JoyStick.onTouchEvent(platformInfo, event);
		} else {
			// TODO Fire();
		}
		
		return true;
    }
중요한 부분만 추려서 올렸습니다.

5: [그림 2]를 통해 설명한 대로, 우주선의 크기만큼의 빨간선 왼쪽 영역이 눌러질 때만 우주선을 이동합니다.

6: 우주선 이동을 위해서 모션 이벤트가 발생했다는 것을 JoyStick 객체에게 알립니다.  내부에서는 눌러진 Y 축 좌표로 우주선이 지정된 속도만큼씩 이동하도록 되어 있습니다.

8: 만약 [그림 2]의 빨간선의 오른쪽이 눌러졌다면, 레이저를 발사하도록 합니다.  이 구현은 이미 말쓴드린대로 생략합니다.



방향 센서를 이용한 이동

마지막으로 지금 개발하는 게임이 최종적으로 선택한 방향 센서를 이용한 이동입니다.  우선 [소스 3]과 같이 Ship.java를 수정합니다.  완성된 다음에는 장비를 이리 저리 기울여보면 우주선이 기울인 방향으로 움직이게 됩니다.

[소스 3] 방향 센서를 적용한 Ship.java
package app.main;

import ryulib.game.GameControl;
import ryulib.game.GameControlGroup;
import ryulib.game.GamePlatformInfo;
import android.graphics.Canvas;
import android.graphics.Paint;
import app.resources.Resource;
import app.resources.ResourceShip;

public class Ship extends GameControl {

	private static final int _ANIMATIONINTERVAL = 100;
	private static final int _SPEED = 150;
	
	public Ship(GameControlGroup gameControlGroup) {
		super(gameControlGroup);
	
	}

	private Canvas _Canvas = null;
	private Paint _Paint = null;
	
	private JoyStick _JoyStick = new JoyStick(_SPEED);
	
	private AnimationCounter _AnimationCounter = 
		new AnimationCounter(
				_ANIMATIONINTERVAL, 
				ResourceShip.getInstance().getCount()
		);
	
	@Override
	protected void onStart(GamePlatformInfo platformInfo) {
		_Canvas = platformInfo.getCanvas();
		_Paint = platformInfo.getPaint();
		
		_JoyStick.PrepareOrientationSensor(Resource.getInstance().getContext());

		_JoyStick.setBoundaryLimit(
				true, 
				0, 0, _Canvas.getWidth(), _Canvas.getHeight(),
				ResourceShip.WIDTH, ResourceShip.HEIGHT
		);
	}
	
	@Override
	protected void onTick(GamePlatformInfo platformInfo) {
		long tick = platformInfo.getTick();
		
		_AnimationCounter.Tick(tick);
		_JoyStick.Tick(tick);
	}
	
	@Override
	protected void onDraw(GamePlatformInfo platformInfo) {
		_Canvas.drawBitmap(
				ResourceShip.getInstance().getBitmap(_AnimationCounter.getIndex()), 
				_JoyStick.getX(), _JoyStick.getY(), 
				_Paint
		);
	}
	
}
하이 라이트된 37: 라인처럼 PrepareOrientationSensor() 메소드를 호출하여 센서를 준비하도록 하면 됩니다.  센서에 대한 구현 코드는 JoyStick 클래스 내부에 캡슐화되어 있기 때문에 더 이상 신경 쓸 것이 없습니다.  

실제 게임은 이 코드를 이용하여 작성해 나가도록 하겠습니다.



JoyStick 클래스 작성

이제 핵심 주인공인 JoyStick 클래스를 구현해보도록 하겠습니다.  우선 키보드 이벤트, 모션 이벤트 그리고 센서의 처리가 게임 마다 그 구현이 달라질 수 있을 것이라 예상이 됩니다.  따라서, 달라지는 부분과 달라지지 않는 부분을 [그림 3]과 같이 분리하도록 하겠습니다.  

즉, 각각의 이벤트 처리부분만 다른 클래스로 떼내는 작업입니다.

[그림 3] 변하지 않는 인터페이스 부분과 변동이 예상되는 구현 부분을 분리

그리고, 실제 구현은 [소스 4]와 [소스 5]와 같습니다.  지금까지 설명되지 않은 것들이 다소 섞여 있습니다.  설명을 간략하게 하기 위해서, 중요한 것만을 간추려서 설명했기 때문입니다.  

또한, 지금 설명한 모든 이벤트 처리가 모두 구현되어 있습니다.  그리고, 그 중에서 실제 사용하는 것은 방향 센서 뿐임을 기억하시기 바랍니다.  여러분들이 키보드 이벤트를 적용하고 싶다면, 위에서 설명한 대로 Ship.java의 소스만 수정하시면 됩니다.

[소스 4] JoyStickInterface.java
package app.main;

public abstract class JoyStickInterface {
	
	public JoyStickInterface() {
		super();
	}
	
	public JoyStickInterface(int speed) {
		super();
		
		_Scroll.setSpeed(speed);
	}

	protected int _X = 0;
	protected int _Y = 0;
	
	private int _LeftLimit = 0;  
	private int _TopLimit = 0;  
	private int _RightLimit = 0;  
	private int _BottomLimit = 0;
	
	private int _ObjectWidth = 0;
	private int _ObjectHeight = 0;
	
	private boolean _UseBoundaryLimit = false;
	
	protected int _DX = 0;
	protected int _DY = 0;
	
	private Scroll _Scroll = new Scroll();
	
	public void setBoundaryLimit(boolean useBoundaryLimit, 
			int leftLimit, int topLimit, 
			int rightLimit, int bottomLimit, 
			int objectWidth, int objectHeight) {
		
		_UseBoundaryLimit = useBoundaryLimit;
		_LeftLimit = leftLimit;
		_TopLimit = topLimit;
		_RightLimit = rightLimit;
		_BottomLimit = bottomLimit;
		_ObjectWidth = objectWidth;
		_ObjectHeight = objectHeight;
	}
	
	public void Tick(long tick) {
		int temp = _Scroll.Move(tick);
		_X = _X + (_DX * temp);
		_Y = _Y + (_DY * temp);
		
		if (_UseBoundaryLimit == false) return;
		
		if (_X < _LeftLimit) {
			_X = _LeftLimit;
		} else if (_X > (_RightLimit-_ObjectWidth)) {
			_X = _RightLimit-_ObjectWidth;
		}
		
		if (_Y < _TopLimit) {
			_Y = _TopLimit;
		} else if (_Y > (_BottomLimit-_ObjectHeight)) {
			_Y = _BottomLimit-_ObjectHeight;
		}
	}
	
	public int getX() {
		return _X;		
	}
	
	public void setX(int value) {
		_X = value;
	}
	
	public int getY() {
		return _Y;
	}

	public void setY(int value) {
		_Y = value;
	}
	
    public int getSpeed() {
    	return _Scroll.getSpeed();
    }
    
    public void setSpeed(int value) {
    	_Scroll.setSpeed(value);
    }

	public void setLeftLimit(int value) {
		this._LeftLimit = value;
	}

	public int getLeftLimit() {
		return _LeftLimit;
	}
    
	public void setTopLimit(int value) {
		this._TopLimit = value;
	}

	public int getTopLimit() {
		return _TopLimit;
	}

	public void setRightLimit(int value) {
		this._RightLimit = value;
	}

	public int getRightLimit() {
		return _RightLimit;
	}

	public void setBottomLimit(int value) {
		this._BottomLimit = value;
	}

	public int getBottomLimit() {
		return _BottomLimit;
	}

	public void setObjectWidth(int value) {
		this._ObjectWidth = value;
	}

	public int getObjectWidth() {
		return _ObjectWidth;
	}

	public void setObjectHeight(int value) {
		this._ObjectHeight = value;
	}

	public int getObjectHeight() {
		return _ObjectHeight;
	}

	public void setUseBoundaryLimit(boolean value) {
		this._UseBoundaryLimit = value;
	}

	public boolean isUseBoundaryLimit() {
		return _UseBoundaryLimit;
	}

}
15-16: 객체를 표시 할 (X, Y) 좌표 입니다.

18-21: 객체가 벗어 날 수 없는 제한 공간 지정입니다.  (주로 화면 크기)

23-24: 객체의 가로/세로 크기 입니다.

26: 객체의 제한 공간을 사용 할 것인지를 나타냅니다.

28-29: 객체가 움직이는 방향을 표시합니다.  현재 2D 게임을 만들고 있기 때문에, 두 개의 변수만이 필요합니다.  (미분의 dx, dy 를 생각해서 작명하였습니다)  부호만 결정하면 되기 때문에 크기는 항상 1 또는 0 입니다.

48-50: 속도에 맞춰서 객체의 위치 좌표를 변경합니다.  이때, 방향을 알리는 _DX, _DY를 곱해서 더합니다.

52: 제한 공간을 사용하지 않는다면 다음 코드들을 무시합니다.

54-64: 객체가 제한 공간을 넘어서면 한계 값으로 변경하여, 벗어나지 못하도록 합니다.


[소스 5] JoyStick.java
package app.main;

import ryulib.game.GamePlatformInfo;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.view.KeyEvent;
import android.view.MotionEvent;

public class JoyStick extends JoyStickInterface implements SensorEventListener {

	private static final int _ANGLE_LIMIT = 10;

	public JoyStick() {
		super();
		
	}

	public JoyStick(int speed) {
		super(speed);
		
	}
	
	public void PrepareOrientationSensor(Context context) {
	    SensorManager _SensorManager;
	    Sensor _Sensor;    
	    
		_SensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
		_Sensor = _SensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
		
        if (_Sensor != null) {
        	_SensorManager.registerListener(this, _Sensor, SensorManager.SENSOR_DELAY_GAME);
        }
    }

	private int _TargetY = 0;
	private boolean _IsMoving = false;
	
	@Override
	public void Tick(long tick) {
		super.Tick(tick);
		
		if (_IsMoving) {
			if ((_DY < 0) && (_Y <= _TargetY)) {
				_IsMoving = false;
				_DY = 0;
				_Y = _TargetY;
			}
			
			if ((_DY > 0) && (_Y >= _TargetY)) {
				_IsMoving = false;
				_DY = 0;
				_Y = _TargetY;
			}
		}
	}
	
	public void onKeyDown(GamePlatformInfo platformInfo, int keyCode, KeyEvent msg) {
		switch (keyCode) {
			case KeyEvent.KEYCODE_DPAD_LEFT: _DX = -1; break;
	
			case KeyEvent.KEYCODE_DPAD_RIGHT: _DX = +1; break;
	
			case KeyEvent.KEYCODE_DPAD_UP: 
			case KeyEvent.KEYCODE_Q: _DY = -1; break;
	
			case KeyEvent.KEYCODE_DPAD_DOWN:
			case KeyEvent.KEYCODE_W: _DY = +1; break;
		}
    }

	public void onKeyUp(GamePlatformInfo platformInfo, int keyCode, KeyEvent msg) {
		switch (keyCode) {
			case KeyEvent.KEYCODE_DPAD_LEFT: if (_DX == -1) _DX =0; break;
		
			case KeyEvent.KEYCODE_DPAD_RIGHT: if (_DX == +1) _DX =0; break;
	
			case KeyEvent.KEYCODE_DPAD_UP: 
			case KeyEvent.KEYCODE_Q: if (_DY == -1) _DY =0; break;
			
			case KeyEvent.KEYCODE_DPAD_DOWN:
			case KeyEvent.KEYCODE_W: if (_DY == +1) _DY =0; break;
		}
    }

	public void onTouchEvent(GamePlatformInfo platformInfo, MotionEvent event) {
		_TargetY = (int) event.getY();
		_IsMoving = true;
		
		if (_TargetY > _Y) _DY = 1;
		else if (_TargetY < _Y) _DY = -1;
		else _IsMoving = false;
	}

	@Override
	public void onAccuracyChanged(Sensor sensor, int accuracy) {
		
	}
	
	@Override
	public void onSensorChanged(SensorEvent event) {
		int x = (int) event.values[SensorManager.DATA_Y];
		int y = (int) event.values[SensorManager.DATA_Z];
		
		if (x < -_ANGLE_LIMIT) _DX = -1;
		else if (x > _ANGLE_LIMIT) _DX = 1;
		else _DX = 0;
		
		if (y < -_ANGLE_LIMIT) _DY = 1;
		else if (y > _ANGLE_LIMIT) _DY = -1;
		else _DY = 0;
	}
	
}
14: 방향 센서가 얼마나 기울어져야 인식하는 가를 나타냅니다.  최소 10도 정도 기울여야만 인식합니다.

26-36: 방향 센서를 사용하겠다는 선언입니다.  추후 취소 메소드를 추가 할 예정입니다.

38: 앞에서 설명한 모션 이벤트를 통해서 어디까지 이동해야 하는 지를 저장합니다.  Y 축으로만 움직이기 때문에 하나의 변수만 선언하였습니다.  눌러진 곳으로 바로 우주선을 이동하면 순간 이동처럼 보이기 때문에 목표를 저장해 두고, 목표를 향해서 속도만큼씩 접근하는 방법을 사용합니다.

39: 목표를 향해서 움직이고 있는 중인지 여부를 나타냅니다.

41-58: 모션 이벤트를 통해서 이동 할 때의 처리를 추가하기 위해서 부모 클래스의 Tick() 메소드를 재정의 하고 있습니다.

45-57: 모션 이벤트를 통해서 이동 중일 때만 실행합니다.

46: _DY가 음수 즉, 위로 이동 중이면서, 목표보다 멀리 갔거나 같을 경우에는 47-49: 라인을 실행합니다.  즉, 더 이상 이동 중이 아님을 선언하고, _Y를 목표치로 지정합니다.

52-56: 반대로 아래 쪽으로 움직일 경우도 유사하게 처리합니다.

60-72: 방향키가 눌러졌을 때, (_DX, _DY) 값을 변경하여 방향을 설정합니다.  위/아래 방향키의 경우에는 Q와 W키가 눌러졌을 때도 반응하게 합니다.

74-86: 키가 눌려졌을 때의 지정을 취소합니다.  키마다 개별적으로 지정하고 취소해야 합니다.  키를 여러 개 중복해서 누를 수가 있기 때문입니다.  예를 들어 위쪽과 오른쪽을 함께 누르면 대각선 방향으로 움직여야 합니다.

88-95: 모션 이벤트 처리 부분입니다.  목표 위치가 현재 위치보다 크냐 작으냐를 통해서 방향을 설정하고 있습니다.

103-114: 센서의 처리 과정입니다.  게임이 가로로 표시되기 때문에 좌표가 서로 얼갈려 있음을 유의하시기 바랍니다.  (DATA_Y-->x, DATA_Z --> y) 



정리

여기까지 이동에 관한 세 가지 방법을 살펴보고 적용해 봤습니다.  다음에는 충돌 테스트를 통해서 우주선과 소행선이 서로 부디쳤을 경우를 구현 해보도록 하겠습니다.

예제의 최종 모습은 아래의 비디오를 통해서 확인하실 수가 있습니다.  (http://www.youtube.com/watch?v=unBLNb8qwow)



소스




관련글 더보기