그림짝맞추기 앱개발

그림짝맞추기 앱만들기 07 - 이미 맞춘 그림은 터치가 안되도록 처리하기, 처음 시작시 5초간 카운트 다운할때는 모든 이미지 카드의 터치가 안되도록 하기, 모든 그림 다 맞추었는지 체크하기

두결앱개발 2025. 12. 19. 05:05
반응형
SMALL

안녕하세요~ 두결입니다.

 

지난시간에는  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단계 성공시, 다음단계 설정을 위한 팝업창 띄우기를 해보도록 하겠습니다.

 

 

그럼, 이만~

감사합니다. ^^

반응형
LIST