그림짝맞추기 앱개발

그림짝맞추기 앱만들기 10 - 2단계 초기화하기, 2단계 6개 동적 ImageView생성하기, 2단계 카운트다운 타이머 로직 수정하기

두결앱개발 2025. 12. 24. 09:56
반응형
SMALL

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

 

지난시간에는  팝업창에 현재 게임단계 및 성공메세지를 표시하고, 팝업화면 닫기 버튼 및 다음단계 이동버튼까지 추가해보았습니다.

 

이번시간에는

그림짝맞추기 2단계를 구현해보도록 하겠습니다.

 


▣  2단계 초기화하기

먼저, 2단계 초기화 부터 해보겠습니다.

// 새게임 시작
private void NewGame()
{
    InitImageArray(); //초기화
}

 

새게임하면 InitImageArray() 초기화 함수를 호출하였습니다.

 

// 리소스의 이미지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]);
    }

}

 

InitImageArray()함수인데 여기에 2단계 로직을 넣어보겠습니다.

switch(nGameStage)
{
    case 1:
        nCurImageCount = 4; // 1단계 이미지 개수 4개
        break;
    case 2:
        nCurImageCount = 6; // 2단계 이미지 개수 6개
        break;
}

 

여기에서는 위와같이 이미지 개수만 다르게 설정하면 될것 같네요...

 


▣  2단계 6개 동적 ImageView생성하기

 

// 새게임 시작
private void NewGame()
{
    InitImageArray(); // 초기화
    CreateImageView(); // 동적 ImageView 생성
}

 

 

다음으로 CreateImageView()를 호출하였습니다.

// 동적으로 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;
            }
        });
    }
}

 

이게 CreateImageView()함수인데요..

여기에서도 2단계 로직을 넣어보겠습니다.

 

private void CreateImageView()
{
    // ArrayList 초기화
    if(!arrayListImage.isEmpty())
    {
        for(int i=0;i<arrayListImage.size();i++ )
        {
            ImageView imgvCur = arrayListImage.get(i);
            if(imgvCur !=null)
            {
                constraintLayout.removeView(imgvCur);
            }
        }
        arrayListImage.clear();
    }

    // ArrayList에 새로운 값 추가
    for(int i=0; i<nCurImageCount; i++)
    {
        ImageView imgvDynamic = new ImageView(getApplicationContext());
        arrayListImage.add(imgvDynamic);
    }

 

먼저, 1단계만 있을때는 ArrayList를 초기화할필요가 없었는데..

2단계를 시작할때는 이미 ArrayList가 있는 상태이기 때문에 위와같이 초기화 해주고 ConstraintLayout.removeView()로 

모든 ImageView를 삭제해주었습니다.

 

switch(nGameStage)
{
    case 1:
        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;
        break;
    case 2:
        fImagePosX[0] = 0.1f; fImagePosY[0] = 0.2f;
        fImagePosX[1] = 0.9f; fImagePosY[1] = 0.2f;
        fImagePosX[2] = 0.1f; fImagePosY[2] = 0.5f;
        fImagePosX[3] = 0.9f; fImagePosY[3] = 0.5f;
        fImagePosX[4] = 0.9f; fImagePosY[4] = 0.8f;
        fImagePosX[5] = 0.9f; fImagePosY[5] = 0.8f;
        break;
}

 

그리고, 게임단계에따라서 이미지의 위치를 설정해주었습니다.

 


▣  2단계 카운트다운 타이머 로직 수정하기

 

다음으로

// 새게임 시작
private void NewGame()
{
    InitImageArray(); // 초기화
    CreateImageView(); // 동적 ImageView 생성
    StartCountDownTimer();  // 5초 카운트다운 타이머 생성
}

 

새게임시작할때 StartCoundDownTimer()를 호출하였습니다.

 

// 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초 카운트다운 타이머인데요..

여기에서도 2단계로직을 넣어보면

 

// 5초 카운트다운 타이머
private void StartCountDownTimer()
{
    // 타이머가 이미 있으면 종료하기
    if(cdTimer !=null)
    {
        cdTimer.cancel();
        cdTimer = null;
    }

 

카운트 다운 타이머가 이미 있으면 종료하는 로직 추가하였습니다.

 

 

여기까지 잘 되는지 한번 실행해보겠습니다.

 

 

네 1단계가 끝나면 2단계 6개 이미지도 잘 보이네요..^^

 

 

이번시간은 여기까지만 하구요~

다음시간은 2단계 완료하고 3단계 8개 이미지까지 해보도록 해보겠습니다.

 

그럼, 이만~

감사합니다. ^^

 

반응형
LIST