Android Card Game example Part 10
Android Card Game example Part 10
카드게임에서 카드를 모두 맞추면 경과시간, 틀린횟수 등을 화면에 출력하는 예
숫자가 포함된 이미지로부터 해당 숫자를 부분적으로 읽어와서 출력하는 예를 포함
CardGameActivity.java
package test.android.cardgame;
import android.app.Activity;
import android.os.Bundle;
public class CardGameActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
CardGameView view = new CardGameView(this);
setContentView(view);
}
}
CardGameView.java
package test.android.cardgame;
import java.util.Random;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
public class CardGameView extends View {
Bitmap bgImg;
Bitmap backsideImg;
Card [][] card = new Card[2][3];
// 게임상태의 구분
int STATUS_INIT = 0;
int STATUS_READY = 1;
int STATUS_GAME_ON = 2;
int STATUS_END = 3;
int status; // 게임의 상태
Card selCard1, selCard2;
int cnt_fails;
long time_start, time_end;
boolean scoreCompleted;
public CardGameView(Context context) {
super(context);
bgImg = BitmapFactory.decodeResource(getResources(), R.drawable.background);
shuffleCards(); // 카드 섞기
status = STATUS_INIT;
CardGameThread gameThread = new CardGameThread(this);
gameThread.start();
}
private void shuffleCards() {
int[] src = {1,2,3,1,2,3};
int[] dest = new int[6];
int dst_idx = 0;
int n = src.length;
Random rd = new Random();
for(int i=0;i<src.length;i++) {
int tmp = rd.nextInt(n--);
dest[dst_idx++] = src[tmp];
for(int k=tmp;k<n;k++) {
src[k] = src[k+1];
}
}
card[0][0] = new Card(getContext(), dest[0]);
card[0][1] = new Card(getContext(), dest[1]);
card[0][2] = new Card(getContext(), dest[2]);
card[1][0] = new Card(getContext(), dest[3]);
card[1][1] = new Card(getContext(), dest[4]);
card[1][2] = new Card(getContext(), dest[5]);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(bgImg, 0, 0, null);
for(int y=0;y<2;y++) {
for(int x=0;x<3;x++) {
card[y][x].draw(canvas, 35+x*90, 150+y*130);
}
}
if(status==STATUS_INIT){
Bitmap btnStart = BitmapFactory.decodeResource(getResources(), R.drawable.btn_start);
int bw = btnStart.getWidth();
int bh = btnStart.getHeight();
int cw = canvas.getWidth();
int ch = canvas.getHeight();
canvas.drawBitmap(btnStart, cw/2-(bw/2), ch/2-(bh/2), null);
}else if(status==STATUS_END) {
Bitmap restart = BitmapFactory.decodeResource(getResources(), R.drawable.restart);
int bw = restart.getWidth();
int bh = restart.getHeight();
int cw = canvas.getWidth();
int ch = canvas.getHeight();
canvas.drawBitmap(restart, cw/2-(bw/2), ch/2-(bh/2), null);
writeResult(canvas);
}
}
private void writeResult(Canvas canvas) {
Bitmap tgn = BitmapFactory.decodeResource(getResources(), R.drawable.typography_num);
int elapse = (int)((time_end - time_start)/1000);
String strElapse = String.valueOf(elapse);
Paint paint = new Paint();
paint.setTextSize(30);
paint.setColor(Color.RED);
canvas.drawText("Elapsed Time : ", 20, 30, paint);
for(int i=0;i<strElapse.length();i++) {
int num = Integer.valueOf(strElapse.charAt(i)+"");
num = num==0 ? 10 : num;
int endPx = num*26;
int beginPx = (num-1)*26;
int endPy = 42;
int beginPy = 0;
canvas.drawBitmap(tgn,new Rect(beginPx, beginPy, endPx, endPy), new Rect(i*26+220, 0, (i+1)*26+220, 42), null);
//Log.i("경과시간(초):", ""+elapse);
}
paint.setColor(Color.WHITE);
canvas.drawText("Fails : "+cnt_fails+" times", 20, 55, paint);
scoreCompleted = true;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if(status==STATUS_INIT) {
startGame();
status=STATUS_READY;
}else if(status==STATUS_READY) {
//쓰레드를 이용하여 5초동안 카드의 앞면을 보여주고 이어서 카드의 뒷면이 보이도록 화면을 전환한다
//이 상태 동안은 이용자의 터치 이벤트에는 반응하지 않는다
}else if(status==STATUS_GAME_ON) {
int x = (int) event.getX();
int y = (int) event.getY();
Card card = touchedCard(x,y);
if(card==null) return false;
card.status = Card.STATUS_TMPSHOW;
if(selCard1==null) {
selCard1 = card;
}
else {
selCard2 = card;
}
}else if(status==STATUS_END) {
cnt_fails = 0;
time_start = time_end = 0;
scoreCompleted = false;
shuffleCards();
startGame();
status=STATUS_READY;
}
invalidate(); // 선택된 즉시 화면을 갱신하므로 2개의 카드가 서로 다르더라도 일단 카드의 앞면이 보이게 됨
return super.onTouchEvent(event);
}
public void startGame() {
for(int y=0;y<2;y++) {
for(int x=0;x<3;x++) {
card[y][x].status = Card.STATUS_SHOW;
}
}
}
public void upsideDown() {
for(int y=0;y<2;y++) {
for(int x=0;x<3;x++) {
card[y][x].status = Card.STATUS_CLOSE;
}
}
}
private Card touchedCard(int px, int py) {
for(int y=0;y<2;y++) {
for(int x=0;x<3;x++) {
if(card[y][x].isTouched(px, py)) return card[y][x];
}
}
return null;
}
public void checkMatch() {
if(status==STATUS_END || selCard1 == null || selCard2 == null) return;
if(selCard1.color == selCard2.color) {
selCard1.status = selCard2.status = Card.STATUS_MATCHED;
}else{ // 2개의 카드가 서로 일치하지 않을 경우 잠깐동안만 2개 카드의 앞면이 나타나도록 sleep 한다.
cnt_fails++;
try{
Thread.sleep(300);
}catch(InterruptedException ie){}
selCard1.status = selCard2.status = Card.STATUS_CLOSE;
}
selCard1 = selCard2 = null;
postInvalidate(); // User Thread가 UI Thread에게 화면갱신을 요청함
}
public boolean isAllMatch() {
if(status==STATUS_END) return true;
for(int y=0;y<2;y++) {
for(int x=0;x<3;x++) {
if(card[y][x].status != Card.STATUS_MATCHED) {
return false;
}
}
}
time_end = System.currentTimeMillis();
status = STATUS_END;
return true;
}
}
Card.java
package test.android.cardgame;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Rect;
public class Card {
static int COLOR_RED = 1;
static int COLOR_GREEN = 2;
static int COLOR_BLUE = 3;
static int STATUS_CLOSE = 1;
static int STATUS_SHOW = 2;
static int STATUS_TMPSHOW = 3;
static int STATUS_MATCHED = 4;
Bitmap backsideImg;
Bitmap bitmap;
int color;
int status;
Rect region = new Rect();
public Card(Context ctx, int color){
this.status = STATUS_CLOSE;
this.color = color;
if(backsideImg==null)
backsideImg = BitmapFactory.decodeResource(ctx.getResources(), R.drawable.backside);
if(color==COLOR_RED)
bitmap = BitmapFactory.decodeResource(ctx.getResources(), R.drawable.front_red);
else if(color==COLOR_GREEN)
bitmap = BitmapFactory.decodeResource(ctx.getResources(), R.drawable.front_green);
else if(color==COLOR_BLUE)
bitmap = BitmapFactory.decodeResource(ctx.getResources(), R.drawable.front_blue);
}
public void draw(Canvas c, int x, int y){
region.left = x;
region.top = y;
region.right = x + 80;
region.bottom = y + 115;
if(status != STATUS_CLOSE) c.drawBitmap(bitmap, x, y, null);
else c.drawBitmap(backsideImg, x, y, null);
}
public boolean isTouched(int x, int y) {
return region.contains(x, y);
}
}
CardGameThread.java
package test.android.cardgame;
public class CardGameThread extends Thread {
CardGameView view;
public CardGameThread(CardGameView view) {
this.view = view;
}
@Override
public void run() {
while(true) {
if(view.status==view.STATUS_READY){ // 게임 시작에 앞서 모든 카드 앞면이 5초간 보이게 한다.
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
view.upsideDown();
view.status=view.STATUS_GAME_ON;
view.time_start = System.currentTimeMillis();
}
view.checkMatch();
view.isAllMatch();
view.postInvalidate();
}
}
}
사용된 숫자 이미지 파일