이번에는 소행성을 폭발 애니메이션과 함께 사라지도록 해보겠습니다.  이 강좌도 이제 거의 막바지에 다왔네요 ^^*



소행성 폭발 애니메이션 리소스 관리 클래스 추가

애니메이션 동작에는 이미지가 여러 장 필요하기 때문에, BitmapList를 상속받아서 [소스 1]과 같이 작성합니다.

[소스 1] ResourceExplodingAsteroid.java
   1 : package app.resources;
   2 : 
   3 : import android.content.res.Resources;
   4 : import android.graphics.Bitmap;
   5 : import android.graphics.BitmapFactory;
   6 : import app.main.R;
   7 : 
   8 : public class ResourceExplodingAsteroid extends BitmapList {
   9 : 
  10 :  private static ResourceExplodingAsteroid _Instance = new ResourceExplodingAsteroid();
  11 : 
  12 :  public static ResourceExplodingAsteroid getInstance(){
  13 :  return _Instance;
  14 :  }
  15 : 
  16 :  private ResourceExplodingAsteroid() {}
  17 : 
  18 :     @Override
  19 :     protected void loadBitmaps() {
  20 :  _Bitmaps = new Bitmap[4];
  21 : 
  22 :  Resources resources = Resource.getInstance().getResources();  
  23 : 
  24 :         _Bitmaps[ 0] = BitmapFactory.decodeResource(resources, R.drawable.asteroid_explode1);
  25 :         _Bitmaps[ 1] = BitmapFactory.decodeResource(resources, R.drawable.asteroid_explode2);
  26 :         _Bitmaps[ 2] = BitmapFactory.decodeResource(resources, R.drawable.asteroid_explode3);
  27 :         _Bitmaps[ 3] = BitmapFactory.decodeResource(resources, R.drawable.asteroid_explode4);
  28 :     }
  29 :     
  30 : }

이미 여러 번 반복된 스타일의 코드이기 때문에, 특별히 설명드릴 만한 내용은 없으니 생략하도록 하겠습니다.



소행성 폭발 애니메이션 처리

소행성의 경우에는 이미 애니메이션 처리가 되어 있습니다.  그런데 이 에니메이션 동작이 상태에 따라서 변경되어야 하는 요구사항이 늘어나게 되었습니다.  따라서, 현재 어떤 애니메이션 동작을 해야 할 지를 결정하는 변수가 있어야 겠습니다.

[소스 2]를 보시면 이번에는 애니메이션에 사용되는 리소스 객체를 고정시키지 않고, 사용하는 것을 볼 수가 있습니다.  즉, 예전에는 ResourceAsteroid.getInstance()를 통해서 애니메이션에 필요한 이미지를 얻어왔지만, 새로 수정된 소스에는 private BitmapList _BitmapList = null; 과 같이 현재 사용될 애니메이션에 필요한 리소스를 동적으로 지정 할 수 있도록 변경하였습니다.

다행히, 애니메이션에 관련된 리소스들은 BimapList에서 상속받아왔기 때문에 동일한 인터페이스를 통해서 접근 할 수가 있어 더욱 코드를 효율적으로 표현 할 수 있게 되었습니다.

[소스 2] Asteroid.java
   1 : package app.main;
   2 : 
   3 : import ryulib.game.GameControl;
   4 : import ryulib.game.GamePlatformInfo;
   5 : import ryulib.game.HitArea;
   6 : import ryulib.graphic.Boundary;
   7 : import android.graphics.Bitmap;
   8 : import android.graphics.Canvas;
   9 : import android.graphics.Paint;
  10 : import app.resources.BitmapList;
  11 : import app.resources.ResourceAsteroid;
  12 : import app.resources.ResourceExplodingAsteroid;
  13 : 
  14 : public class Asteroid extends GameControl {
  15 : 
  16 :  private static final int _ANIMATIONINTERVAL = 100;
  17 :  private static final int _SPEED = 100;
  18 :  private static final int _HORIZONTAL_MARGINE = 5;
  19 :  private static final int _VERTICAL_MARGINE   = 5;
  20 : 
  21 :  public Asteroid(int x, int y) {
  22 :  super(null);
  23 : 
  24 :  _X = x;
  25 :  _Y = y;
  26 : 
  27 :  _HitArea.Add(_HitBoundary);
  28 :  }
  29 : 
  30 :  private Canvas _Canvas = null;
  31 :  private Paint _Paint = null;
  32 : 
  33 :  private int _X = 0;
  34 :  private int _Y = 0;
  35 :  private Scroll _Scroll = new Scroll(_SPEED);
  36 : 
  37 :  private BitmapList _BitmapList = null;
  38 :  private AnimationCounter _AnimationCounter = 
  39 :  new AnimationCounter(
  40 :  _ANIMATIONINTERVAL, 
  41 :  ResourceAsteroid.getInstance().getCount()
  42 :  );
  43 : 
  44 :  // 충돌 검사 할 때 자신이 차지하고 있는 영역을 알려준다.  
  45 :  private HitArea _HitArea = new HitArea();
  46 : 
  47 :  // Boundary는 Rect와 유사한 기능을 한다.  
  48 :  private Boundary _HitBoundary = new Boundary(0, 0, 0, 0);
  49 : 
  50 :  @Override
  51 :  protected HitArea getHitArea() {
  52 :  if (isExploding()) return null;
  53 : 
  54 :  _HitBoundary.setBoundary(
  55 :  _X + _HORIZONTAL_MARGINE, 
  56 :  _Y + _VERTICAL_MARGINE, 
  57 :  _X + ResourceAsteroid.SIZE - _HORIZONTAL_MARGINE*2, 
  58 :  _Y + ResourceAsteroid.SIZE - _VERTICAL_MARGINE*2
  59 :  );
  60 : 
  61 :  return _HitArea;
  62 :  }
  63 : 
  64 :  public void Explode() {
  65 :  _AnimationCounter.Clear();
  66 :  _AnimationCounter.setSize( ResourceExplodingAsteroid.getInstance().getCount() );
  67 :  _AnimationCounter.setAutoRewind(false);
  68 : 
  69 :  _BitmapList = ResourceExplodingAsteroid.getInstance();
  70 :  }
  71 : 
  72 :  @Override
  73 :  protected void onStart(GamePlatformInfo platformInfo) {
  74 :  _Canvas = platformInfo.getCanvas();
  75 :  _Paint = platformInfo.getPaint();
  76 : 
  77 :  _BitmapList = ResourceAsteroid.getInstance();
  78 :  }
  79 : 
  80 :  @Override
  81 :  protected void onTick(GamePlatformInfo platformInfo) {
  82 :  long tick = platformInfo.getTick();
  83 : 
  84 :  _AnimationCounter.Tick(tick);
  85 : 
  86 :  if (isExploding() == false) {
  87 :  // 초당 _Scroll.getSpeed() 만큼의 속도로 운석을 이동 한다.
  88 :  _X = _X - _Scroll.Move(tick);
  89 : 
  90 :  // 화면에서 사라지면 삭제 한다.
  91 :  if (_X < (-ResourceAsteroid.SIZE)) this.Delete(); 
  92 :  }
  93 :  }
  94 : 
  95 :  @Override
  96 :  protected void onDraw(GamePlatformInfo platformInfo) {
  97 :  Bitmap bitmap = _BitmapList.getBitmap(_AnimationCounter.getIndex());
  98 : 
  99 :  if (bitmap != null) {
 100 :  _Canvas.drawBitmap(bitmap, _X, _Y, _Paint);
 101 :  } else {
 102 :  this.Delete();
 103 :  }
 104 :  }
 105 : 
 106 :  public boolean isExploding() {
 107 :  return _BitmapList == ResourceExplodingAsteroid.getInstance();
 108 :  }
 109 : 
 110 : }

52: 만약 소행성이 폭발 중이면 더 이상 충돌 테스트가 필요 없습니다.  따라서, HitArea를 null로 하여 리턴합니다.

64-70: 소행성을 폭발 시킵니다.

65-67: AnimationCounter 객체를 폭발 애니메이션에 맞춰서 변경합니다.  폭발의 경우에는 반복되는 애니메이션이 아니기 때문에 setAutoRewind(false)를 통해서 한 번만 진행하도록 합니다.

69: 현재 진행되는 애니메이션에서 사용하는 리소스를 지정합니다.

86: 폭발 중이 아닐 때믄 소행성을 왼쪽으로 계속 움직이도록 합니다.

97: 현재 애니메이션 동작에서 필요한 이미지를 가져옵니다.  폭발의 경우에는 더 이상 이미지가 없을 때, null이 리턴됩니다.

102: 더 이상 진행 할 에니메이션이 없으면 소행성 객체를 삭제 합니다.

106-108: 현재 애니메이션이 폭발 중을 표현하고 있는 지를 리턴해 줍니다.



정리

지금까지 소행성을 폭발시키는 애니메이션 동작에 대해서 설명하였습니다.  아래는 이미 공개한 바가 있는 동영상 녹화 자료입니다.  지금까지의 작업이 모두 포함되어 있는 소스를 실행 시킨 것 입니다.  참고하시기 바랍니다.


다음에는 음향 효과를 입히는 작업에 대해서 설명하도록 하겠습니다.



소스