안녕하세요~ 두결입니다.
지난시간에는 2개의 터치한 이미지가 다른 그림일때는 카드를 뒤집어서 뒷면이 나오도록 하고 2개의 터치한 이미지가 같은 그림일때는 원래 이미지 보여주고 맞춘 위치를 저장해보았습니다. 그리고, 같은 그림을 연속으로 터치할때의 처리도 해보았구요~
이번시간에는
1. 이미 맞춘 그림은 터치가 안되도록 처리하기
2. 처음 시작시 5초간 카운트 다운할때는 모든 이미지 카드의 터치가 안되도록 하기
3. 모든 그림 다 맞추었는지 체크하기
위와같이 3가지 기능구현을 해보겠습니다.
▣ 이미 맞춘 그림은 터치가 안되도록 처리하기
먼저, 이미 맞춘 그림은 아예 터치가 안되도록 하는게 좋으니까 그부분 처리해보겠습니다.
// 이미지 터치이벤트
int nPos = i;
imgvCur.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch(motionEvent.getAction())
{
case MotionEvent.ACTION_DOWN:
if(bPairOK[nPos])
{
Toast.makeText(getApplicationContext(),"이미 맞춤!",Toast.LENGTH_SHORT).show();
break;
}
imgvCur.setImageResource(nArrSelectImageID[nArrImagePos[nPos]]);
이미지 터치이벤트에서
bPairOK[nPos]배열값이 true이면, "이미 맞춤"이란 메세지를 띄우고 break; 끝내서 아무 동작도 하지 않도록 하였습니다.
// 같은그림인지 체크해주는 함수
private void CheckSameImage(ImageView imgvFirst, int nFirstID, int nFirstPos,
ImageView imgvSecond, int nSecondID, int nSecondPos)
{
if(nFirstID == nSecondID)
{
// Toast.makeText(getApplicationContext(),"띵동! 같은 이미지입니다.!"+"",Toast.LENGTH_SHORT).show();
bPairOK[nFirstPos]= true;
bPairOK[nSecondPos]= true;
String sMsg;
sMsg = "첫번째 위치 : " + nFirstPos + "두번째 위치 : " + nSecondPos;
Toast.makeText(getApplicationContext(),sMsg,Toast.LENGTH_SHORT).show();
}
else
{
FlipCardAnimation(imgvFirst);
FlipCardAnimation(imgvSecond);
}
}
bPairOK[]배열값은 지난 시간에 한것처럼
위와같이 같은그림을 찾으면 그때 해당 배열의 값을 true로 바꾸어주어서 현재 이미지가 맞춘값인지 아닌지를 체크할수 있게 해줍니다.
실행을 해보면

이미 맞춘 그림을 터치할 때 메세지가 잘보이네요..^^
▣ 처음 시작시 5초간 카운트 다운할때는 모든 이미지 카드의 터치가 안되도록 하기
다음으로 처음 시작시 5초간 카운트 다운할때는 이미지 터치가 안되도록 해보겠습니다.
이것은 변수하나로 간단하게 할수 있습니다.
boolean bGameStart = false;
bGameStart라는 변수를 하나 만들구요~
// 5초 카운트다운 타이머
private void StartCountDownTimer()
{
cdTimer = new CountDownTimer(6000,1000) {
@Override
public void onFinish() {
// blank 이미지 표시하기
for(int i=0;i<nCurImageCount;i++) {
ImageView imgvCur = arrayListImage.get(i);
FlipCardAnimation(imgvCur);
}
bGameStart = true;
}
@Override
public void onTick(long l) {
txtv_CountDown.setText((l / 1000) + "");
}
};
cdTimer.start();
}
5초 카운트 다운 타이머에서 타이머가 끝났을때
bGameStart를 true로 만들어줍니다.
public boolean onTouch(View view, MotionEvent motionEvent) {
switch(motionEvent.getAction())
{
case MotionEvent.ACTION_DOWN:
if(bPairOK[nPos])
{
Toast.makeText(getApplicationContext(),"이미 맞춤!",Toast.LENGTH_SHORT).show();
break;
}
if(!bGameStart)
{
Toast.makeText(getApplicationContext(),"잠시후에 게임이 시작됩니다.!",Toast.LENGTH_SHORT).show();
break;
}
imgvCur.setImageResource(nArrSelectImageID[nArrImagePos[nPos]]);
그리고, 이미지 터치 이벤트에서
bGameStart값이 false이면 "잠시후에 게임이 시작됩니다.!"라는 메세지를 띄워보았습니다.
실행을 해보면

5초 카운트다운이 끝나기전에 이미지를 터치하면
위와같이 메세지가 잘 뜨네요..^^
▣ 모든그림 다 맞추었는지 체크하기
마지막으로 모든 그림을 다 맞추었는지 체크해보도록 하겠습니다.
boolean bNotFindAllPair = false; // 모든 그림을 찾았는지 체크해주는 변수
먼저, 모든 그림을 다 맞추었는지 체크해주는 변수를 하나 만들구요~
// 같은그림인지 체크해주는 함수
private void CheckSameImage(ImageView imgvFirst, int nFirstID, int nFirstPos,
ImageView imgvSecond, int nSecondID, int nSecondPos)
{
if(nFirstID == nSecondID)
{
// Toast.makeText(getApplicationContext(),"띵동! 같은 이미지입니다.!"+"",Toast.LENGTH_SHORT).show();
bPairOK[nFirstPos]= true;
bPairOK[nSecondPos]= true;
// String sMsg;
// sMsg = "첫번째 위치 : " + nFirstPos + "두번째 위치 : " + nSecondPos;
// Toast.makeText(getApplicationContext(),sMsg,Toast.LENGTH_SHORT).show();
// 모든 그림을 찾았는지 체크
bNotFindAllPair = false;
for(int i=0;i<nCurImageCount;i++)
{
if(!bPairOK[i])
{
bNotFindAllPair = true;
}
}
if(!bNotFindAllPair)
{
Toast.makeText(getApplicationContext(),"1단계 성공!!",Toast.LENGTH_SHORT).show();
bGameStart =false;
}
}
else
{
FlipCardAnimation(imgvFirst);
FlipCardAnimation(imgvSecond);
}
}
같은 그림인지 체크해주는 CheckSameImage()함수에서
for문을 이용해서 bPairOK[]의 배열값이 모두 true인지를 체크해서
모두 true라면 모든 그림을 다 맞추었다는 뜻이니까
그때 "1단계 성공!!"이란 메세지를 띄워보았습니다.
자, 여기까지 전체 실행 영상 한번 보겠습니다.

네 1단계는 아주 쉽게 클리어했네요..~^^
전체 소스입니다. 참고하세요~
MainActivity.java
package com.example.dk_imagepair;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.EdgeToEdge;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintSet;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.core.view.WindowInsetsControllerCompat;
import java.util.ArrayList;
import java.util.Random;
public class MainActivity extends AppCompatActivity {
int[] nArrImageID;
int[] nArrSelectImageID;
final int MAX_IMAGECOUNT = 10;
ViewGroup.LayoutParams layoutParams;
ArrayList<ImageView> arrayListImage;
ConstraintLayout constraintLayout;
float[] fImagePosX;
float[] fImagePosY;
int[] nArrImagePos;
int nCurImageCount;
CountDownTimer cdTimer;
TextView txtv_CountDown;
ImageView imgvCur;
ObjectAnimator objectAnimator;
int nFirstTouchImageID = 0;
int nSecondTouchImageID = 0;
ImageView imgvFirstTouch = null;
ImageView imgvSecondTouch = null;
private boolean[] bPairOK ; // 현재 Imageview의 짝을 맞추었는지 저장
int nFirstTouchImagePos = 0;
int nSecondTouchImagePos = 0;
boolean bGameStart = false;
boolean bNotFindAllPair = false; // 모든 그림을 찾았는지 체크해주는 변수
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
// 전체 화면으로 만들기
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
// 시스템 바 안보이게 하기
WindowInsetsControllerCompat windowInsetsController =
WindowCompat.getInsetsController(getWindow(), getWindow().getDecorView());
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars());
// 배경 이미지 설정
SetBackgroundImage();
// 리소스의 이미지ID를 배열에 설정
InitImageArray();
constraintLayout = findViewById(R.id.main);
arrayListImage = new ArrayList<>();
// 동적 ImageView 생성
CreateImageView();
txtv_CountDown = findViewById(R.id.txtvCountDown);
txtv_CountDown.setTextSize(100);
txtv_CountDown.setTypeface(null, Typeface.BOLD);
txtv_CountDown.setGravity(Gravity.CENTER|Gravity.TOP);
txtv_CountDown.setTextColor(Color.parseColor("#FFFFFF"));
// 5초 카운트다운 타이머 생성
StartCountDownTimer();
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
}
// 배경이미지 설정함수
private void SetBackgroundImage()
{
int[] nArrBackgroundImageID = new int[3];
nArrBackgroundImageID[0] = R.drawable.background01;
nArrBackgroundImageID[1] = R.drawable.background02;
nArrBackgroundImageID[2] = R.drawable.background03;
Random random = new Random();
int nSelectBackID = random.nextInt(3);
findViewById(R.id.main).setBackgroundResource(nArrBackgroundImageID[nSelectBackID]);
}
// 리소스의 이미지ID를 배열에 초기화 해주는 함수
private void InitImageArray()
{
nArrImageID = new int[MAX_IMAGECOUNT];
nArrImageID[0] = R.drawable.imagepair_01; nArrImageID[1] = R.drawable.imagepair_02;
nArrImageID[2] = R.drawable.imagepair_03; nArrImageID[3] = R.drawable.imagepair_04;
nArrImageID[4] = R.drawable.imagepair_05; nArrImageID[5] = R.drawable.imagepair_06;
nArrImageID[6] = R.drawable.imagepair_07; nArrImageID[7] = R.drawable.imagepair_08;
nArrImageID[8] = R.drawable.imagepair_09; nArrImageID[9] = R.drawable.imagepair_10;
nCurImageCount = 4;
nArrSelectImageID = new int[nCurImageCount];
bPairOK = new boolean[nCurImageCount];
Random random = new Random();
int nRandom = 0;
// 총 이미지중에 Random값 현재 게임이미지 개수 / 2 개만 뽑아오기
for(int i=0;i<nCurImageCount/2;i++)
{
nRandom = random.nextInt(MAX_IMAGECOUNT);
nArrSelectImageID[i] = nArrImageID[nRandom];
for(int j=0;j<i;j++)
{
if (nArrSelectImageID[i] == nArrSelectImageID[j])
{
i--;
}
}
}
// 동일한 이미지를 2개씩 배열에 복사
for(int i=0;i<nCurImageCount/2;i++)
{
nArrSelectImageID[i+(nCurImageCount/2)] = nArrSelectImageID[i];
}
// 이미지 위치 랜덤으로 설정하기
nArrImagePos = new int[nCurImageCount];
Random randomPos = new Random();
for(int i=0;i<nCurImageCount;i++)
{
nArrImagePos[i] = randomPos.nextInt(nCurImageCount);
for(int j=0;j<i;j++)
{
if (nArrImagePos[i] == nArrImagePos[j])
{
i--;
}
}
}
for (int i = 0; i < nCurImageCount; i++) {
Log.d("[이미지위치 배열]", "nArrImagePos[ " + i + " ] = " + nArrImagePos[i]);
}
}
// 동적으로 ImageView 생성해주는 함수
@SuppressLint("ClickableViewAccessibility")
private void CreateImageView()
{
// ArrayList에 새로운 값 추가
for(int i=0; i<nCurImageCount; i++)
{
ImageView imgvDynamic = new ImageView(getApplicationContext());
arrayListImage.add(imgvDynamic);
}
fImagePosX = new float[nCurImageCount];
fImagePosY = new float[nCurImageCount];
fImagePosX[0] = 0.1f; fImagePosY[0] = 0.3f;
fImagePosX[1] = 0.9f; fImagePosY[1] = 0.3f;
fImagePosX[2] = 0.1f; fImagePosY[2] = 0.67f;
fImagePosX[3] = 0.9f; fImagePosY[3] = 0.67f;
for(int i=0;i<nCurImageCount;i++)
{
ImageView imgvCur = arrayListImage.get(i);
imgvCur.setImageResource(nArrSelectImageID[nArrImagePos[i]]);
imgvCur.setId(View.generateViewId());
imgvCur.setBackgroundResource(R.drawable.round_border_style);
imgvCur.setPadding(7,7,7,7);
constraintLayout.addView(imgvCur);
// ImageView의 가로, 세로 크기 설정
layoutParams = imgvCur.getLayoutParams();
layoutParams.width = 415;
layoutParams.height = 510;
imgvCur.setLayoutParams(layoutParams);
// ImageView의 위치 설정
ConstraintSet constraintSet = new ConstraintSet();
constraintSet.clone(constraintLayout);
constraintSet.connect(imgvCur.getId(), ConstraintSet.TOP, constraintLayout.getId(), ConstraintSet.TOP, 0);
constraintSet.connect(imgvCur.getId(), ConstraintSet.LEFT, constraintLayout.getId(), ConstraintSet.LEFT, 0);
constraintSet.connect(imgvCur.getId(), ConstraintSet.RIGHT, constraintLayout.getId(), ConstraintSet.RIGHT, 0);
constraintSet.connect(imgvCur.getId(), ConstraintSet.BOTTOM, constraintLayout.getId(), ConstraintSet.BOTTOM, 0);
constraintSet.setHorizontalBias(imgvCur.getId(), fImagePosX[i]);
constraintSet.setVerticalBias(imgvCur.getId(), fImagePosY[i]);
constraintSet.applyTo(constraintLayout);
// 이미지 터치이벤트
int nPos = i;
imgvCur.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch(motionEvent.getAction())
{
case MotionEvent.ACTION_DOWN:
if(bPairOK[nPos])
{
Toast.makeText(getApplicationContext(),"이미 맞춤!",Toast.LENGTH_SHORT).show();
break;
}
if(!bGameStart)
{
Toast.makeText(getApplicationContext(),"잠시후에 게임이 시작됩니다.!",Toast.LENGTH_SHORT).show();
break;
}
imgvCur.setImageResource(nArrSelectImageID[nArrImagePos[nPos]]);
if(nFirstTouchImageID ==0)
{
nFirstTouchImageID = nArrSelectImageID[nArrImagePos[nPos]];
imgvFirstTouch = imgvCur;
nFirstTouchImagePos = nPos;
}
else
{
nSecondTouchImageID = nArrSelectImageID[nArrImagePos[nPos]];
imgvSecondTouch = imgvCur;
nSecondTouchImagePos = nPos;
// 동일한 ImageView를 연속으로 터치했을때의 처리
if(imgvFirstTouch == imgvSecondTouch)
{
nSecondTouchImageID = 0;
imgvSecondTouch = null;
nSecondTouchImagePos =0;
Toast.makeText(getApplicationContext(),"연속 터치!",Toast.LENGTH_SHORT).show();
}
else
{
CheckSameImage(imgvFirstTouch, nFirstTouchImageID, nFirstTouchImagePos,
imgvSecondTouch, nSecondTouchImageID, nSecondTouchImagePos); // 같은 그림인지 체크
nFirstTouchImageID = 0;
nSecondTouchImageID = 0;
imgvFirstTouch = null;
imgvSecondTouch = null;
nFirstTouchImagePos = 0;
nSecondTouchImagePos =0;
}
}
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_MOVE:
break;
}
return true;
}
});
}
}
// 5초 카운트다운 타이머
private void StartCountDownTimer()
{
cdTimer = new CountDownTimer(6000,1000) {
@Override
public void onFinish() {
// blank 이미지 표시하기
for(int i=0;i<nCurImageCount;i++) {
ImageView imgvCur = arrayListImage.get(i);
FlipCardAnimation(imgvCur);
}
bGameStart = true;
}
@Override
public void onTick(long l) {
txtv_CountDown.setText((l / 1000) + "");
}
};
cdTimer.start();
}
// 카드 뒤집기 애니메이션
private void FlipCardAnimation(ImageView imgvPCur)
{
objectAnimator = ObjectAnimator.ofFloat(imgvPCur, "rotationY",0f,90f);
objectAnimator.setDuration(100);
objectAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationCancel(@NonNull Animator animator) {
}
@Override
public void onAnimationEnd(@NonNull Animator animator) {
imgvPCur.setImageResource(R.drawable.imagepair_blank);
objectAnimator = ObjectAnimator.ofFloat(imgvPCur, "rotationY",90f,180f);
objectAnimator.setDuration(100);
objectAnimator.start();
}
@Override
public void onAnimationRepeat(@NonNull Animator animator) {
}
@Override
public void onAnimationStart(@NonNull Animator animator) {
}
});
objectAnimator.start();
}
// 같은그림인지 체크해주는 함수
private void CheckSameImage(ImageView imgvFirst, int nFirstID, int nFirstPos,
ImageView imgvSecond, int nSecondID, int nSecondPos)
{
if(nFirstID == nSecondID)
{
// Toast.makeText(getApplicationContext(),"띵동! 같은 이미지입니다.!"+"",Toast.LENGTH_SHORT).show();
bPairOK[nFirstPos]= true;
bPairOK[nSecondPos]= true;
// String sMsg;
// sMsg = "첫번째 위치 : " + nFirstPos + "두번째 위치 : " + nSecondPos;
// Toast.makeText(getApplicationContext(),sMsg,Toast.LENGTH_SHORT).show();
// 모든 그림을 찾았는지 체크
bNotFindAllPair = false;
for(int i=0;i<nCurImageCount;i++)
{
if(!bPairOK[i])
{
bNotFindAllPair = true;
}
}
if(!bNotFindAllPair)
{
Toast.makeText(getApplicationContext(),"1단계 성공!!",Toast.LENGTH_SHORT).show();
bGameStart =false;
}
}
else
{
FlipCardAnimation(imgvFirst);
FlipCardAnimation(imgvSecond);
}
}
}
이번시간은 여기까지만 하도록 하구요~
다음시간에는
1단계 성공시, 다음단계 설정을 위한 팝업창 띄우기를 해보도록 하겠습니다.
그럼, 이만~
감사합니다. ^^
