반도체 Study/C#

C# - WinForm을 이용한 기억력 게임

잇(IT) 2024. 6. 25. 17:23
728x90

C#의 Winform을 이용하여 기억력 게임을 만들어 보았다.

 

게임은 크게 1초, 0.5초 0.25초 간격의 난이도를 가지고 있다.

아래 GIF 파일들은 실제 게임을 실행하는 중요 부분들만 캡처한 것이고, 그 외 상세한 부분들은 글과 코드를 통해 설명할 것이다.


속도 선택

가장 먼저 게임 속도를 선택하게 되면 게임 속도가 선택에 맞게 설정된다.


속도 1 게임 실행

1단계 게임을 실행하게 되면 1초의 속도로 기억력 게임이 시작되고 속도 1 점수에 해당하는 곳에 최고 점수가 기록된다.


속도 2 게임 실행

속도 2를 선택하게 되면 0.5초 간격의 난이도로 게임이 시작되고, 속도 2에 해당하는 점수판에 최고 속도가 기록된다.


속도 3 게임 실행

속도 3을 선택하게 되면 0.25초 간격의 난이도로 기억력 게임이 시작되고, 속도 3에 해당하는 점수판에 최고 점수가 기록된다.


게임 종료 버튼

게임 중에 게임 종료 버튼을 누르게 되면 게임이 종료되고 1단계로 초기화 된다.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using System.Windows.Forms;

namespace game
{
    public partial class Form1 : Form
    {
        //class
        Random random = new Random();
        List<int> stageRan = new List<int>();
        List<int> chooseButton = new List<int>();

        //var
        int highScoreOne = 0;
        int highScoreTwo = 0;
        int highScoreThree = 0;
        int currentScore = 0;
        int stageNum = 1;
        int gameSpeed = 500;
        //선택 횟수를 세기 위함
        int chooseCount = 0;
        
        //flag
        bool gameIng = false;
        bool chooseIng = false;

        //index
        int currentIndex = 0;

        System.Timers.Timer blinkTimer;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            SetForm();
            blinkTimer = new System.Timers.Timer();
            blinkTimer.Interval = gameSpeed;
            blinkTimer.Elapsed += ShowButton;
        }

        private void GameStart_Click(object sender, EventArgs e)
        {
            if(!gameIng)
            {
                gameIng = true;
                //스테이지에 따라서 함수 호출
                Stage.Text = stageNum + "단계 도전 중!!!!!!!";
                StageStart(stageNum);
            }
        }

        private void Up_Click(object sender, EventArgs e)
        {
            if (chooseIng == true)
            {
                if(chooseCount < stageRan.Count )
                {
                    chooseButton.Add(1);
                    chooseCount++;
                    CheckAndEndGame();
                }
            }
        }

        private void Down_Click(object sender, EventArgs e)
        {
            if (chooseIng == true)
            {
                if (chooseCount < stageRan.Count)
                {
                    chooseButton.Add(2);
                    chooseCount++;
                    CheckAndEndGame();
                }
            }
        }

        private void Left_Click(object sender, EventArgs e)
        {
            if (chooseIng == true)
            {
                if (chooseCount < stageRan.Count)
                {
                    chooseButton.Add(3);
                    chooseCount++;
                    CheckAndEndGame();
                }
            }
        }

        private void Right_Click(object sender, EventArgs e)
        {
            if (chooseIng == true)
            {
                if(chooseCount < stageRan.Count)
                {
                    chooseButton.Add(4);
                    chooseCount++;
                    CheckAndEndGame();
                }
            }
        }

        private void GameFinish_Click(object sender, EventArgs e)
        {
            stageNum = 1;
            GameStart.Text = stageNum + "단계 시작";
            Stage.Text = stageNum + "단계 시작 대기 중.....";
            gameIng = false;
            chooseIng = false;
            currentScore = 0;
            CurrentScore.Text = currentScore.ToString();
            chooseIng = false;
            gameIng = false;
            chooseCount = 0;
            chooseButton.Clear();
            stageRan.Clear();
            OXTest.Text = "스테이지 결과";
            Speed.Enabled = true;
        }


        //-------User Function-------
        private void SetForm()
        {
            Stage.Text = "게임 시작 전...";
            CurrentScore.Text = "0";
            HighScore.Text = "0";
            GameStart.Text = "1단계 시작";
            GameFinish.Text = "게임 종료";
            Up.Text = "UP";
            Down.Text = "DOWN";
            Left.Text = "LEFT";
            Right.Text = "RIGHT";
            OXTest.Text = "스테이지 결과";
        }

        private void StageStart(int stageNum)
        {
            Speed.Enabled = false;
            int ranNum = 0;
            for(int i = 0; i< stageNum; i++)
            {
                ranNum = random.Next(1,5);
                stageRan.Add(ranNum);
            }
            BlinkButton();
            chooseIng = true;
        }

        private void BlinkButton()
        {
            blinkTimer.Start();
        }

        private async void ShowButton(object sender, ElapsedEventArgs e)
        {
            Up.BackColor = Color.White;
            Down.BackColor = Color.White;
            Left.BackColor = Color.White;
            Right.BackColor = Color.White;

            await Task.Delay(gameSpeed/2);

            if (currentIndex < stageRan.Count)
            {
                int ranNum = stageRan[currentIndex];

                switch (ranNum)
                {
                    case 1:
                        Up.BackColor = Color.Black;
                        Down.BackColor = Color.White;
                        Left.BackColor = Color.White;
                        Right.BackColor = Color.White;
                        break;
                    case 2:
                        Up.BackColor = Color.White;
                        Down.BackColor = Color.Black;
                        Left.BackColor = Color.White;
                        Right.BackColor = Color.White;
                        break;
                    case 3:
                        Up.BackColor = Color.White;
                        Down.BackColor = Color.White;
                        Left.BackColor = Color.Black;
                        Right.BackColor = Color.White;
                        break;
                    case 4:
                        Up.BackColor = Color.White;
                        Down.BackColor = Color.White;
                        Left.BackColor = Color.White;
                        Right.BackColor = Color.Black;
                        break;
                }
                currentIndex++;
            }
            else
            {
                blinkTimer.Stop();
                currentIndex = 0;
            }
        }

        private void TEST_OX()
        {
            bool areEqual1 = stageRan.SequenceEqual(chooseButton);
            if(areEqual1) 
            {
                OXTest.Text = stageNum + "단계 정답입니다!!!!!!!";
                stageNum++;
                GameStart.Text = stageNum + "단계 시작";
                Stage.Text = stageNum + "단계 시작 대기 중.....";
                currentScore++;
                CurrentScore.Text = currentScore.ToString();
                switch (gameSpeed)
                {
                    case 500:
                        MaxScoreOne(currentScore);
                        break;
                    case 250:
                        MaxScoreTwo(currentScore);
                        break;
                    case 125:
                        MaxScoreThree(currentScore);
                        break;
                }
                
                 
            }
            else
            {
                Speed.Enabled = true;
                OXTest.Text = stageNum + "단계 오답입니다...";
                stageNum = 1;
                GameStart.Text = stageNum + "단계 시작";
                Stage.Text = stageNum + "단계 시작 대기 중.....";
                currentScore = 0;
                CurrentScore.Text = currentScore.ToString();
                switch (gameSpeed)
                {
                    case 500:
                        MaxScoreOne(currentScore);
                        break;
                    case 250:
                        MaxScoreTwo(currentScore);
                        break;
                    case 125:
                        MaxScoreThree(currentScore);
                        break;
                }
            }
        }

        private void CheckAndEndGame()
        {
            if (chooseCount == stageRan.Count)
            {
                chooseIng = false;
                gameIng = false;
                TEST_OX();
                chooseCount = 0;
                chooseButton.Clear();
                stageRan.Clear();
                
            }
        }
        
        private void MaxScoreOne(int score)
        {
            if (highScoreOne < score)
            {
                highScoreOne = score;
            }
            HighScore.Text = highScoreOne.ToString();
        }

        private void MaxScoreTwo(int score)
        {
            if(highScoreTwo < score)
            {
                highScoreTwo = score;
            }
            HighScore2.Text = highScoreTwo.ToString();
        }

        private void MaxScoreThree(int score)
        {
            if(highScoreThree < score)
            {
                highScoreThree = score;
            }
            HighScore3.Text = highScoreThree.ToString();
        }

        private void Speed_SelectedIndexChanged(object sender, EventArgs e)
        {
            string ss = Speed.SelectedItem.ToString();
            switch (ss)
            {
                case "1":
                    gameSpeed = 500;
                    break;
                case "2":
                    gameSpeed = 250;
                    break;
                case "3":
                    gameSpeed = 125;
                    break;
            }
            blinkTimer.Interval = gameSpeed;
        }
    }
}

위 코드는 기억력 게임의 전체 코드에 해당한다. (아직 함수를 조금 더 세분화 하고 함수명 선어에 있어서 지저분한 부분이 많아 수정할 부분이 많아 보이긴 한다.)

 

아래 코드들을 상세 분석해보겠다.

        Random random = new Random();
        List<int> stageRan = new List<int>();
        List<int> chooseButton = new List<int>();

        //var
        int highScoreOne = 0;
        int highScoreTwo = 0;
        int highScoreThree = 0;
        int currentScore = 0;
        int stageNum = 1;
        int gameSpeed = 500;
        //선택 횟수를 세기 위함
        int chooseCount = 0;
        
        //flag
        bool gameIng = false;
        bool chooseIng = false;

        //index
        int currentIndex = 0;
        
		System.Timers.Timer blinkTimer;

무작위 버튼 깜빡임을 위한 Random 함수를 선언하였다.

랜덤으로 생성된 값을 넣을 List와 추후 입력된 버튼값을 넣을 두개의 List를 선언 한다 -> 추후 랜덤으로 저장된 값과 버튼 입력으로 저장된 값을 비교할 것이다.

 

그 외 변수들은 작성된 이름과 같이 속도에 대한 점수, 현재 점수, 스테이지, 게임 속도에 관한 변수들이 작성되어 있고, flag의 경우 게임 상태를 구분하기 위해 작성한 것이다.

 

currentIndex는 List 비교시 인덱스 위치를 구분하기 위해 사용한다.

public Form1()
{
    InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
    SetForm();
    blinkTimer = new System.Timers.Timer();
    blinkTimer.Interval = gameSpeed;
    blinkTimer.Elapsed += ShowButton;
}

Form1_Load는 Form이 Load 될 때 실행되며, Timer를 실행시키고 있다.

blinkTimer는 버튼 깜빡임에 대한 Timer를 뜻한다.

 

private void GameStart_Click(object sender, EventArgs e)
{
    if(!gameIng)
    {
        gameIng = true;
        //스테이지에 따라서 함수 호출
        Stage.Text = stageNum + "단계 도전 중!!!!!!!";
        StageStart(stageNum);
    }
}

해당 함수는 Game 시작 버튼을 누르게 되면 실행되는 함수에 해당한다.

실행 상태 관련 flag를 변경시키고, StageStart 함수를 호출한다.

 

private void StageStart(int stageNum)
{
    Speed.Enabled = false;
    int ranNum = 0;
    for(int i = 0; i< stageNum; i++)
    {
        ranNum = random.Next(1,5);
        stageRan.Add(ranNum);
    }
    BlinkButton();
    chooseIng = true;
}

GameStart를 누르게 되면 호출되는 StageStart 버튼은 각 스테이지가 시작되는 코드를 나타내고 있다.

스테이지 진행 중 게임속도가 변경되는 것을 방지하기 위해 Speed 버튼은 false로 변경한다.

위 코드는 Random 클래스를 통해 각 스테이지에 맞게 무작위 숫자를 생성하여 배열에 넣고 추후에 버튼에 할당하게 된다.

 

또한 BlinkButton()(버튼이 깜빡이게 하는 함수)함수가 호출된 이후 chooseIng flag가 true 즉, 버튼 입력값이 저장되도록 한다.

 

private void BlinkButton()
{
    blinkTimer.Start();
}
.....

private void Form1_Load(object sender, EventArgs e)
{
    SetForm();
    blinkTimer = new System.Timers.Timer();
    blinkTimer.Interval = gameSpeed;
    blinkTimer.Elapsed += ShowButton;
}

.....

private async void ShowButton(object sender, ElapsedEventArgs e)
{
    Up.BackColor = Color.White;
    Down.BackColor = Color.White;
    Left.BackColor = Color.White;
    Right.BackColor = Color.White;

    await Task.Delay(gameSpeed/2);

    if (currentIndex < stageRan.Count)
    {
        int ranNum = stageRan[currentIndex];

        switch (ranNum)
        {
            case 1:
                Up.BackColor = Color.Black;
                Down.BackColor = Color.White;
                Left.BackColor = Color.White;
                Right.BackColor = Color.White;
                break;
            case 2:
                Up.BackColor = Color.White;
                Down.BackColor = Color.Black;
                Left.BackColor = Color.White;
                Right.BackColor = Color.White;
                break;
            case 3:
                Up.BackColor = Color.White;
                Down.BackColor = Color.White;
                Left.BackColor = Color.Black;
                Right.BackColor = Color.White;
                break;
            case 4:
                Up.BackColor = Color.White;
                Down.BackColor = Color.White;
                Left.BackColor = Color.White;
                Right.BackColor = Color.Black;
                break;
        }
        currentIndex++;
    }
    else
    {
        blinkTimer.Stop();
        currentIndex = 0;
    }
}

Stage가 시작된 뒤 BlinkButton이 실행되게 되면, blinkTimer.Elapsed에 의해 ShowButton이 실행되게 된다.

728x90