본문 바로가기

Android/Sprite Animation 03

Android Sprite Animation example

안드로이드에서 Sprite Animation예, Part 03

달리는 이미지 30장으로 구성된 spritesheet.png 를 이용하여 애니메이션을 구현함과 동시에 이동할 수 있도록 하면서 화면의 끝에 도달하면 되돌아서서 달리는 효과를 내도록 하였다.

Part 02 는 여기를 참조하세요

사용된 스프라이트 시트

spritesheet.zip


res/layout/main.xml

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/linearLayout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <Button android:id="@+id/button1" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="onBtnStart" android:layout_weight="1" android:text="Start Animation" /> <Button android:id="@+id/button2" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="onBtnStop" android:layout_weight="1" android:text="Stop Animation" /> </LinearLayout> <com.example.androidapp.SpriteView android:id="@+id/spriteView" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>


MainActivity.java

package com.example.androidapp; import android.app.*; import android.content.*; import android.graphics.*; import android.os.*; import android.util.*; import android.view.*; import android.view.*; import android.view.View.*; import android.widget.*; public class MainActivity extends Activity { boolean go; SpriteView spriteView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); spriteView = (SpriteView) findViewById(R.id.spriteView); } public void onBtnStart(View v) { spriteView.startAnimation(); } public void onBtnStop(View v){ spriteView.stopAnimation(); }

}


SpriteView.java

package com.example.androidapp;

import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Rect; import android.util.AttributeSet; import android.view.View; /* spritesheet.png (1440x1480), 5행6열 */ public class SpriteView extends View { int frameWidth; int frameHeight; Bitmap spriteSheet = BitmapFactory.decodeResource(getResources(), R.drawable.spritesheet); Bitmap offScreenBitmap, offScreenInv; Rect offScreenRect; Canvas offScreenCanvas; Rect src = new Rect(); Rect dst = new Rect(); int x, y; boolean go; SpriteThread spriteThread; int speed = 5; public SpriteView(Context context) { super(context); init(); } public SpriteView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init(){ frameWidth = spriteSheet.getWidth()/6; frameHeight = spriteSheet.getHeight()/5; dst.left = dst.top = 0; dst.right = frameWidth; dst.bottom = frameHeight; offScreenBitmap = Bitmap.createBitmap(frameWidth, frameHeight, Config.ARGB_8888); offScreenInv = Bitmap.createBitmap(frameWidth, frameHeight, Config.ARGB_8888); offScreenCanvas = new Canvas(); offScreenCanvas.setBitmap(offScreenBitmap); offScreenRect = new Rect(0,0,frameWidth, frameHeight); } public void startAnimation() { go = true; spriteThread = new SpriteThread(); spriteThread.start(); } public void stopAnimation() { go = false; try { spriteThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Bitmap backBuffer = speed > 0 ? offScreenBitmap : offScreenInv; canvas.drawBitmap(backBuffer,x, 0,null); } /* Sprite Sheet에서 읽어와야할 프레임 이미지의 좌표를 계산하는 쓰레드 */ public class SpriteThread extends Thread { int screenWidth, screenHeight; @Override public void run() { screenWidth = getWidth(); screenHeight = getHeight(); Matrix matrix = new Matrix(); /* 행렬(Matrix)을 이용하여 먼저 뒤집는 효과를 적용하고 이어서 이동효과를 적용한다 * 다중변환 효과를 내기 위해서 여러개의 행렬에 각각 변환효과를 설정한 다음 행렬끼리 곱해야 한다. * 행렬의 곱셈에서 먼저 곱해지는 행렬은 나중에 곱해지는 행렬보다 그 효과가 상대적으로 나중에 나타난다 * preXXX()메소드는 상대적으로 먼저 효과를 적용한다는 의미이므로 행렬곱셈 순서상 상대적으로 뒤에 곱해지고 * postXXX()메소드는 상대적으로 나중에 효과를 적용한다는 의미이므로 행렬곱셈식의 앞쪽에 곱한다. * */ matrix.preScale(-1, 1); /*위의 메소드는 이미지의 원점을 기준으로 거울효과를 내는 방법으로 뒤집는다 * 그러므로 원점의 왼쪽으로 이동하면서 뒤집어지는 것과 같은 효과이다 * 따라서 다음과 같이 우측으로 이미지의 폭만큼 이동해주어야 제자리에서 뒤집어진 효과를 낼 수 있다. */ matrix.postTranslate(frameWidth, 0); while(go) { for(int i=0;i<5;i++) { for(int k=0;k<6;k++) { src.left = k*frameWidth; src.top = i*frameHeight; src.right = src.left+frameWidth; src.bottom = src.top+frameHeight; x += speed; if(x+frameWidth >= screenWidth) { speed = speed > 0 ? -speed : speed; }else if(x<=0){ speed = speed < 0 ? -speed : speed; } offScreenCanvas.drawBitmap(spriteSheet,src,offScreenRect, null); if(speed<0) { offScreenCanvas.setBitmap(offScreenInv); offScreenCanvas.drawBitmap(offScreenBitmap,matrix, null); offScreenCanvas.setBitmap(offScreenBitmap); } postInvalidate(); try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } }// end of inner for() }// end of outer for() }// end of while() }// end of run() }// end of class SpriteThread }