반응형

만들어진 앱은 앱스토어 및 플레이스토어에 업로드.

앱스토어 : https://apps.apple.com/us/app/simple-sudoku-puzzle/id1567879220

 

‎Simple Sudoku Puzzle

‎Thousands of Sudoku puzzles to explore. Install to get started now! Whether you want to relax or keep your mind alive-have a good time! Choose the level you want. Play easier levels to challenge your brain, or try the expert level to get a real workout

apps.apple.com

플레이스토어 : https://play.google.com/store/apps/details?id=com.hnine.Sudoku 

 

Sudoku - Google Play 앱

언제 어디서나 스도쿠 퍼즐을 즐기십시오.

play.google.com

 

 

하나의 클래스로 처음에 작업 했다가 코드가 길어져 Partial class를 사용 하여 3개의 파일로 분리 정리함.

Partial class에 대해 궁금하다면 요기를 클릭.

 

BoardHandler.cs 작성

기본적으로 게임 View에 해당하는 전반적인 모든 것들을 연결하고 기능을 담고 있는 파일.

using System;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;

public enum Status
{
    PlayMode,
    MemoMode
}

public partial class BoardHandler : MonoBehaviour
{
    public static string HISTORY = "HISTORY";
    [SerializeField] HistoryManger historyManger;
    [SerializeField] UnityAdsManager adsManager;

    [Header("Theme Color")]
    [SerializeField] List<ColorSet> ListColor;
    [SerializeField] List<Image> Img_BGs;
    [SerializeField] List<Image> Img_Grids;
    [SerializeField] List<Image> ListButtons;
    [SerializeField] List<Image> ListButtonIcons;
    [SerializeField] List<Text> ListButtonsTexts;
    [SerializeField] List<Image> ListToastBGs;
    [SerializeField] List<Text> ListToastTexts;

    [Header("Game")]
    [SerializeField] Status MyStatus;
    [SerializeField] Dificulty dificulty;
    [SerializeField] int Life = 3;
    [SerializeField] int _hint = 3;
    [SerializeField] int ThemeNum = 0;
    public static bool isPlay;
    [SerializeField] float playTime;
    [SerializeField] GridLayoutGroup GLG_Holder;
    [SerializeField] VerticalLayoutGroup VLG;
    [SerializeField] HorizontalLayoutGroup HLG;
    [SerializeField] GameObject PrefabItem;
    [SerializeField] CellItem PrefabCellItem;
    int[,] solvedGrid = new int[9, 9];
    string s;
    [SerializeField] float spacing, padding, round;
    [SerializeField] List<CellItem> List_CellItem;
    int hideCount = 30;
    CellItem targetCellItem = null;

    [Space(10)]
    [Header("UI")]
    [SerializeField] Button Btn_Memo;
    [SerializeField] GameObject GO_TxtMemo, GO_TxtPlay, GO_AD;
    [SerializeField] Image Img_MemoBG;
    [SerializeField] Image[] Imgs_HolderBG;
    [SerializeField] Button[] Btns_Nums;
    [SerializeField] CanvasGroup CG_SelectDificult;
    [SerializeField] Button Btn_Normal, Btn_Medium, Btn_Hard, Btn_Expert, Btn_NewGame, Btn_Hint, Btn_Del, Btn_Theme, Btn_Pause;
    [SerializeField] CanvasGroup CG_Board;
    [SerializeField] RectTransform RT_Borad, RT_Top, RT_Bot, RT_BotUIHolder, RT_TopUIHolder;
    [SerializeField] Text Txt_Level, Txt_Mistake, Txt_PlayTime, Txt_Hint, Txt_Record;
    [SerializeField] UnityEngine.EventSystems.EventSystem eventSystem;
    [SerializeField] List<Text> ListNumCountTxt;
    float screenW, screenH;
    float boardW;
    Vector2 screenSize;

    static float calNum = Mathf.PI / 180;
    public static AnimationCurve SineInOut90 = new AnimationCurve(
        new Keyframe(0, 0, Mathf.Tan(5 * calNum), Mathf.Tan(5 * calNum)),
        new Keyframe(0.12f, 0.06f, Mathf.Tan(52 * calNum), Mathf.Tan(52 * calNum)),
        new Keyframe(0.4f, 0.72f, Mathf.Tan(50 * calNum), Mathf.Tan(50 * calNum)),
        new Keyframe(1f, 1f, Mathf.Tan(1 * calNum), Mathf.Tan(1 * calNum))
    );

    int usedHint = 0;
    public int SetHint
    {
        get
        {
            return _hint;
        }
        set
        {
            _hint = value;

            if (_hint == 0)
            {
                GO_AD.SetActive(true);
                Txt_Hint.gameObject.SetActive(false);
            }
            else
            {
                GO_AD.SetActive(false);
                Txt_Hint.gameObject.SetActive(true);
                Txt_Hint.text = _hint.ToString();
            }
        }
    }

    public int SetLife
    {
        get
        {
            return Life;
        }
        set
        {
            Life = value;
            Txt_Mistake.text = "Mistake : " + (3 - Life).ToString() + "/3";
        }
    }


    [Space(10)]
    [Header("Complete")]
    [SerializeField] CanvasGroup CG_Complete;
    [SerializeField] Button Btn_CompleteReGame;

    [Space(10)]
    [Header("Game Over")]
    [SerializeField] CanvasGroup CG_GameOver;
    [SerializeField] Button Btn_GameOverNewGame, Btn_GameOverRePlay, Btn_GameCompleteRePlay;

    [Space(10)]
    [Header("Toast Popup")]
    [SerializeField] ToastPopupHandler Toast;

    [Space(10)]
    [Header("New Game")]
    [SerializeField] NewGamePopupHandler NewGamePopup;


    void Start()
    {
        Application.targetFrameRate = 30;
        screenSize = new Vector2(Screen.width, Screen.height);
        resetAll();
        ThemeNum = PlayerPrefs.GetInt("ThemeNum");
        setTheme();
        Btn_Memo.onClick.AddListener(() =>
        {
            if (MyStatus == Status.PlayMode)
                toMemoMode();
            else if (MyStatus == Status.MemoMode)
                toPlayMode();
        });
        for (int i = 0; i < Btns_Nums.Length; i++)
        {
            int idx = i + 1;
            Btns_Nums[i].transform.GetChild(0).GetComponent<Text>().text = idx.ToString();
            Btns_Nums[i].onClick.AddListener(() => checkNumber(idx));
        }
        // Btn_Easy.onClick.AddListener(() => selectDificult(0));
        Btn_Normal.onClick.AddListener(() => selectDificult(1));
        Btn_Medium.onClick.AddListener(() => selectDificult(2));
        Btn_Hard.onClick.AddListener(() => selectDificult(3));
        Btn_Expert.onClick.AddListener(() => selectDificult(4));
        Btn_NewGame.onClick.AddListener(NewGamePopup.Open);
        Btn_CompleteReGame.onClick.AddListener(resetAll);
        Btn_GameOverNewGame.onClick.AddListener(resetAll);
        Btn_Hint.onClick.AddListener(HintOpen);
        Btn_Del.onClick.AddListener(resetCell);
        Btn_Theme.onClick.AddListener(() => changeTheme());
        Btn_Pause.onClick.AddListener(pauseCheck);

        NewGamePopup.Btn_NewGame.onClick.AddListener(NewGamePopupOpen);

        NewGamePopup.Btn_RePlay.onClick.AddListener(() => openFullAD("rePlay"));
        Btn_GameCompleteRePlay.onClick.AddListener(() => openFullAD("rePlay"));
        Btn_GameOverRePlay.onClick.AddListener(() => openFullAD("rePlay"));
    }

    // 전면광고 호출
    void openFullAD(string type = "hint")
    {
        // rePlay // hint
        adsManager.AdsShow(type);
    }

    void pauseCheck()
    {
        if (isPlay)
        {
            isPlay = false;
            Btn_Pause.gameObject.transform.GetChild(0).gameObject.SetActive(true);
            Btn_Pause.gameObject.transform.GetChild(1).gameObject.SetActive(false);
            for (int i = 0; i < List_CellItem.Count; i++)
            {
                int idx = i;
                List_CellItem[i].RT.DOLocalRotate(new Vector3(0, 90, 0), 0.25f).SetEase(Ease.InCubic).SetDelay(i * 0.005f).OnComplete(() =>
                {
                    List_CellItem[idx].Txt.gameObject.SetActive(false);
                    List_CellItem[idx].GO_Memo.SetActive(false);
                    List_CellItem[idx].RT.DOLocalRotate(new Vector3(0, 180, 0), 0.25f).SetEase(Ease.OutCubic);
                });
            }
        }
        else
        {
            isPlay = true;
            Btn_Pause.gameObject.transform.GetChild(0).gameObject.SetActive(false);
            Btn_Pause.gameObject.transform.GetChild(1).gameObject.SetActive(true);
            for (int i = 0; i < List_CellItem.Count; i++)
            {
                int idx = i;
                List_CellItem[i].RT.DOLocalRotate(new Vector3(0, 90, 0), 0.25f).SetEase(Ease.InCubic).SetDelay(i * 0.005f).OnComplete(() =>
                {
                    if (List_CellItem[idx].IsOpen)
                        List_CellItem[idx].Txt.gameObject.SetActive(true);
                    if (!List_CellItem[idx].IsOpen)
                        List_CellItem[idx].GO_Memo.SetActive(true);
                    List_CellItem[idx].RT.DOLocalRotate(new Vector3(0, 0, 0), 0.25f).SetEase(Ease.OutCubic);
                });
            }
        }
        setTheme();
    }

    public void NewGamePopupOpen()
    {
        // resetAll();
        adsManager.ShowNewGameAd();
    }

    // 레벨에 따라 주어지는 힌트갯수를 세팅함
    void setHint()
    {
        if (dificulty == Dificulty.Easy) { }
        else if (dificulty == Dificulty.Normal)
            SetHint = 3;
        else if (dificulty == Dificulty.Medium)
            SetHint = 3;
        else if (dificulty == Dificulty.Hard)
            SetHint = 5;
        else if (dificulty == Dificulty.Expert)
            SetHint = 7;
    }

    // 시도했던 게임을 다시 할 경우
    public void RePlayGame()
    {
        Debug.Log("RePlay");
        isPlay = false;
        SetLife = 3;
        setHint();
        playTime = 0;
        CG_Complete.gameObject.SetActive(false);
        CG_GameOver.gameObject.SetActive(false);
        for (int i = 0; i < List_CellItem.Count; i++)
        {
            int idx = i;
            List_CellItem[i].RT.DOLocalRotate(new Vector3(0, 90, 0), 0.25f).SetEase(Ease.InCubic).SetDelay(i * 0.005f).OnComplete(() =>
            {
                if (!List_CellItem[idx].IsOrigin == true)
                {
                    List_CellItem[idx].Txt.gameObject.SetActive(false);
                    List_CellItem[idx].IsOpen = false;
                }
                else
                {
                    List_CellItem[idx].Txt.gameObject.SetActive(true);
                }
                List_CellItem[idx].GO_Memo.SetActive(false);
                List_CellItem[idx].RT.DOLocalRotate(new Vector3(0, 0, 0), 0.25f).SetEase(Ease.OutCubic);
                isPlay = true;
                setTheme();// reset Theme
                toPlayMode();
            });
            List_CellItem[i].Txt.color = ListColor[ThemeNum].Clr_CellTextOrigin;
        }

    }

    // 새로 게임을 진행 할 경우
    public void resetAll()
    {
        // Debug.Log("ResetAll");
        toPlayMode();
        isPlay = false;
        SetLife = 3;
        SetHint = 3;
        playTime = 0;
        CG_Complete.gameObject.SetActive(false);
        CG_GameOver.gameObject.SetActive(false);
        CG_SelectDificult.gameObject.SetActive(true);
        CG_SelectDificult.alpha = 0;
        CG_SelectDificult.DOFade(1, 0.3f).SetEase(SineInOut90);
        for (int i = 0; i < List_CellItem.Count; i++)
        {
            List_CellItem[i].Btn.onClick.RemoveAllListeners();
            List_CellItem[i].List_MemoNums.Clear();
            Destroy(List_CellItem[i].RT.gameObject);
        }
        List_CellItem.Clear();
    }

    // 메모 모드로 집입 할 경우 처리
    void toMemoMode()
    {
        MyStatus = Status.MemoMode;

        // 버튼 상태 변경
        GO_TxtMemo.SetActive(false);
        GO_TxtPlay.SetActive(true);
        Img_MemoBG.color = ListColor[ThemeNum].Clr_MemoMode;

        // 모드를 구분하기 위한 이미지 컬러 조절
        for (int i = 0; i < Imgs_HolderBG.Length; i++)
            Imgs_HolderBG[i].color = ListColor[ThemeNum].Clr_MemoMode;
    }

    // 노멀(플레이모드)모드로 진입 할 경우 처리
    void toPlayMode()
    {
        MyStatus = Status.PlayMode;

        // 버튼 상태 변경
        GO_TxtMemo.SetActive(true);
        GO_TxtPlay.SetActive(false);
        Img_MemoBG.color = ListColor[ThemeNum].Clr_ButtonBG;

        // 모드를 구분하기 위한 이미지 컬러 조절
        for (int i = 0; i < Imgs_HolderBG.Length; i++)
            Imgs_HolderBG[i].color = ListColor[ThemeNum].Clr_PlayMode;
    }


    // 해당 셀을 터치하거나 마우스로 클릭했을 경우
    void clickedItem(CellItem item)
    {
        if (item.IsOpen)
        {
            for (int i = 0; i < List_CellItem.Count; i++)
            {
                if (List_CellItem[i].IsOpen && List_CellItem[i].MyNum == item.MyNum)                    // 셀의 숫자가 열려있는 경우 클릭하게 되면?,
                    List_CellItem[i].Img.color = ListColor[ThemeNum].Clr_FocusedSameNum;
                else                                                                                    // 셀의 숫자가 열려있는 경우 클릭한 셀을 제외한 나머지 셀들은,
                    List_CellItem[i].Img.color = ListColor[ThemeNum].Clr_UnFocused;
            }
        }
        else                                                                                            // 클릭한 셀이 열려있지 않은 경우(가려진 경우) 눌리게 되면?
        {
            for (int i = 0; i < List_CellItem.Count; i++)
                List_CellItem[i].Img.color = ListColor[ThemeNum].Clr_UnFocused;
        }
        item.Img.color = ListColor[ThemeNum].Clr_Focused;
        targetCellItem = item;

        // 클릭된 셀을 기준으로 가로세로로 포커싱되게 처리.
        int cnt = 0;
        for (int i = 0; i < 9; i++)
        {
            for (int j = 0; j < 9; j++)
            {
                if (targetCellItem.MyPos.x == i && targetCellItem.MyPos.y == j) { }                     // 클릭된 카드는 제외하고 나머지 셀들은,
                else
                {
                    if (targetCellItem.MyNum != List_CellItem[cnt].MyNum)                               // 클릭된 셀의 숫자와 다른 나머지 셀들은,
                    {
                        if (i == targetCellItem.MyPos.x || j == targetCellItem.MyPos.y)                 // 클릭된 셀과 가로나 세로가 줄이 맞는 셀이면,
                            List_CellItem[cnt].Img.color = ListColor[ThemeNum].Clr_FocusLine;
                        else                                                                            // 클릭된 셀과 가로나 세로가 맞지 않는 셀이면,
                            List_CellItem[cnt].Img.color = ListColor[ThemeNum].Clr_UnFocused;
                    }
                }
                cnt++;
            }
        }
    }

    // 힌트를 클릭했을 때
    public void HintOpen()
    {
        if (MyStatus == Status.PlayMode)
        {
            if (targetCellItem != null && !targetCellItem.IsOpen)
            {
                if (_hint > 0)
                {
                    SetHint--;
                    usedHint++;
                    checkNumber(targetCellItem.MyNum);
                }
                else
                {
                    // Toast.Popup("No more hint");
                    openFullAD("hint");
                }
            }
            else
            {
                Toast.Popup("Select blank cell.");
            }
        }
        else
        {
            Toast.Popup("change to play mode.");
        }
    }

    // 숫자키를 입력받았을 때, 처리되는 부분
    void checkNumber(int idx)
    {
        if (MyStatus == Status.PlayMode) // 노멀모드에서 처리
        {
            if (targetCellItem != null && !targetCellItem.IsOpen)                                       // 선택한 셀이 있고 열려있지 않을 경우
            {
                if (idx != targetCellItem.MyNum)                                                        //! 입력받은 숫자와 선택한 셀의 숫자가 맞지 않은경우 (틀렸을 경우)
                {
                    // 숫자가 틀렸을 경우 생명이 하나 줄고 틀린숫자가 빨강으로 표기된다.
                    Life--;
                    if (Life == 0)
                    {
                        Txt_Mistake.text = "Mistake : " + (3 - Life).ToString() + "/3";
                        gameOver();
                    }
                    else
                    {
                        Txt_Mistake.text = "Mistake : " + (3 - Life).ToString() + "/3";
                        Toast.Popup("Wrong Number T.T");
                        targetCellItem.Txt.text = idx.ToString();
                        targetCellItem.Txt.gameObject.SetActive(true);
                        targetCellItem.Txt.DOColor(ListColor[ThemeNum].Clr_CellRed, 0.3f).SetEase(SineInOut90);
                    }
                }
                else                                                                                    //? 맞았을 경우
                {
                    // 숫자가 맞았을 경우 해당 숫자가 열린다.
                    targetCellItem.RT.eulerAngles = new Vector3(0, 180, 0);
                    targetCellItem.RT.DOLocalRotate(new Vector3(0, 90, 0), 0.25f).SetEase(Ease.InCubic).OnComplete(() =>
                    {
                        targetCellItem.IsOpen = true;
                        targetCellItem.Txt.text = idx.ToString();
                        targetCellItem.Txt.gameObject.SetActive(true);
                        targetCellItem.Txt.fontStyle = FontStyle.Bold;
                        targetCellItem.Txt.DOColor(ListColor[ThemeNum].Clr_CellText, 0.3f).SetEase(SineInOut90);
                        targetCellItem.RT.DOLocalRotate(new Vector3(0, 0, 0), 0.25f).SetEase(Ease.OutCubic);
                        setNumberCount();

                        // 열린 숫자와 같은 숫자를 표기한다.
                        clickedItem(targetCellItem);

                        // 선택한 셀에 힌트로 적었던 메모를 모두 삭제한다.
                        targetCellItem.GO_Memo.SetActive(false);

                        memoNumberReset_AfterOpenCell(idx);

                        // 오픈되지 않은 남은 셀의 갯수 체크!!
                        int cnt = 0;
                        for (int i = 0; i < List_CellItem.Count; i++)
                            if (!List_CellItem[i].IsOpen)
                                cnt++;
                        if (cnt == 0) // 셀이 모두 열렸을 경우 게임 끝~~~
                            gameComplete();
                    });
                }
            }
            else
            {
                Toast.Popup("This block is already open.\nPlease select a blank.");
            }
        }
        else if (MyStatus == Status.MemoMode)                                                           // 메모 모드에서 숫자를 입력했을 경우 처리.
        {
            if (targetCellItem != null && !targetCellItem.IsOpen)
            {
                if (targetCellItem.List_MemoNums[idx - 1].activeInHierarchy)
                    targetCellItem.List_MemoNums[idx - 1].SetActive(false);
                else
                    targetCellItem.List_MemoNums[idx - 1].SetActive(true);
            }
            else
            {
                Toast.Popup("This block is already open.\nPlease select a blank.");
            }
        }
    }

    // 클릭된 셀을 기준으로 메모해둔 숫자를 사라지도록 처리하기 위한 부분
    void memoNumberReset_AfterOpenCell(int idx)
    {
        int cnt = 0;
        for (int i = 0; i < 9; i++)
        {
            for (int j = 0; j < 9; j++)
            {
                if (targetCellItem.MyPos.x == i && targetCellItem.MyPos.y == j) { }                     // 클릭된 카드는 제외하고 나머지 셀
                else
                {
                    if (targetCellItem.MyNum != List_CellItem[cnt].MyNum)                               // 클릭된 셀의 숫자와 다른 나머지 셀들은,
                        if (i == targetCellItem.MyPos.x || j == targetCellItem.MyPos.y)                 // 클릭된 셀과 가로나 세로가 줄이 맞는 셀이면, 메모해둔 숫자중에 해당 숫자는 사라지도록 처리
                            List_CellItem[cnt].List_MemoNums[idx - 1].SetActive(false);
                }
                cnt++;
            }
        }
        // 클릭된 셀의 숫자가 오픈 될 경우 같은 그룹에 있는 셀에 메모해둔 숫자가 오픈된 숫자와 같을 경우
        for (int i = 0; i < List_CellItem.Count; i++)
            if (targetCellItem.MyGroup == List_CellItem[i].MyGroup)
                List_CellItem[i].List_MemoNums[idx - 1].SetActive(false);
    }

    // 모든 셀의 숫자를 맞추고 게임이 완료되는 상황
    void gameComplete()
    {
        print("Complete!");
        isPlay = false;
        for (int i = 0; i < List_CellItem.Count; i++)
        {
            int ii = i;
            List_CellItem[ii].Img.DOColor(ListColor[ThemeNum].Clr_Focused, 1f).SetDelay(0.005f * i).SetEase(SineInOut90);
            List_CellItem[ii].RT.DOLocalRotate(new Vector3(0, 360, 0), 1f, RotateMode.FastBeyond360).SetDelay(0.005f * i).SetEase(SineInOut90).OnComplete(() =>
            {
                List_CellItem[ii].Img.DOColor(ListColor[ThemeNum].Clr_UnFocused, 1f).SetEase(SineInOut90);
            });
        }
        Invoke("viewRecord", 2.3f);
        eventSystem.enabled = false;
    }

    void viewRecord()
    {
        eventSystem.enabled = true;
        CG_Complete.gameObject.SetActive(true);
        CG_Complete.alpha = 0;
        CG_Complete.DOFade(1, 0.3f).SetEase(SineInOut90);

        string _dificult = dificulty.ToString() + "_record";
        Debug.Log("난이도 : " + _dificult);
        int _history = PlayerPrefs.GetInt(_dificult);

        if (_history > 0)
        {
            Debug.Log("my history time : " + _history);

            if (_history >= Mathf.RoundToInt(playTime))
            {
                Txt_Record.text = "<size=50>Level : " + dificulty.ToString() + "</size>" + "\n<size=90>Game Clear!!</size>\n\n<color=#00aeff>=== New Record ===</color>\n" + GetTimeStr(Mathf.RoundToInt(playTime));
                PlayerPrefs.SetInt(_dificult, Mathf.RoundToInt(playTime));
            }
            else
            {
                Txt_Record.text = "<size=50>Level : " + dificulty.ToString() + "</size>" + "\n<size=90>Game Clear!!</size>\n\n<color=orange>=== Best Record ===</color>\n" + GetTimeStr(Mathf.RoundToInt(_history)) + "\n\n<color=#00aeff>=== My Record ===</color>\n" + GetTimeStr(Mathf.RoundToInt(playTime));
            }
        }
        else
        {
            Txt_Record.text = "<size=50>Level : " + dificulty.ToString() + "</size>" + "\n<size=90>Game Clear!!</size>\n\n<color=#00aeff>=== New Record ===</color>\n" + GetTimeStr(Mathf.RoundToInt(playTime));
            PlayerPrefs.SetInt(_dificult, Mathf.RoundToInt(playTime));
        }
        historyManger.SaveHistory(dificulty.ToString(), GetTimeStr(Mathf.RoundToInt(playTime)), (3 - Life).ToString(), usedHint.ToString());
    }

    // 생명이 다 되서 게임오버가 되는 상황
    void gameOver()
    {
        isPlay = false;
        CG_GameOver.gameObject.SetActive(true);
        CG_GameOver.alpha = 0;
        CG_GameOver.DOFade(1, 0.3f).SetEase(SineInOut90);
    }

    // 선택 된 셀의 숫자를 지우는 함수.
    void resetCell()
    {
        if (targetCellItem != null && !targetCellItem.IsOpen)
        {
            targetCellItem.IsOpen = false;
            targetCellItem.Txt.gameObject.SetActive(false);
        }
        else if (targetCellItem == null)
            Toast.Popup("Select a box.");
        else if (targetCellItem != null && targetCellItem.IsOpen)
            Toast.Popup("Already open.");
    }



    // for layout size
    float tempSpacing, tempPadding, tempRound;
    void Update()
    {
        setResize();
        setKeyBoard();
        updateTime();
    }

    void updateTime()
    {
        if (isPlay)
        {
            playTime += Time.deltaTime;
            Txt_PlayTime.text = GetTimeStr(Mathf.RoundToInt(playTime));
        }
    }

    void setKeyBoard()
    {
        // 각 숫자패드가 눌릴 경우 처리. 나중에 소프트키도 만들어 동일하게 처리해야 함.
        if (Input.GetKeyDown(KeyCode.Alpha1))
        {
            checkNumber(1);
        }
        else if (Input.GetKeyDown(KeyCode.Alpha2))
        {
            checkNumber(2);
        }
        else if (Input.GetKeyDown(KeyCode.Alpha3))
        {
            checkNumber(3);
        }
        else if (Input.GetKeyDown(KeyCode.Alpha4))
        {
            checkNumber(4);
        }
        else if (Input.GetKeyDown(KeyCode.Alpha5))
        {
            checkNumber(5);
        }
        else if (Input.GetKeyDown(KeyCode.Alpha6))
        {
            checkNumber(6);
        }
        else if (Input.GetKeyDown(KeyCode.Alpha7))
        {
            checkNumber(7);
        }
        else if (Input.GetKeyDown(KeyCode.Alpha8))
        {
            checkNumber(8);
        }
        else if (Input.GetKeyDown(KeyCode.Alpha9))
        {
            checkNumber(9);
        }
        else if (Input.GetKeyDown(KeyCode.Escape) || Input.GetKeyDown(KeyCode.Backspace))
        {
            resetCell();
        }
    }

    string GetTimeStr(int totalTime)
    {
        int min = (int)totalTime / 60;
        int sec = totalTime % 60;
        string str = min.ToString("00") + ":" + sec.ToString("00");
        return str;
    }
}

 

BoardHandler.Initialize.cs 작성

게임에 가장 핵심적인 부분이다. 9x9의 블럭에 들어가는 숫자를 랜덤으로 생성하고 섞어주는 역할을 하고 게임의 난이도 등도 관리한다.

알고리즘을 참고한 사이트 링크 : https://citylock77.tistory.com/86

using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;
using Random = UnityEngine.Random;

[Serializable]
public class CellItem
{
    public RectTransform RT;
    public int MyGroup;
    public FreeModifier FM;
    public Button Btn;
    public Text Txt;
    public Image Img;
    public int MyNum;
    public bool IsOpen;
    public Vector2 MyPos;
    public List<GameObject> List_MemoNums;
    public GameObject GO_Memo;
    public bool IsOrigin;
}

public enum Dificulty
{
    Easy = 0,
    Normal = 1,
    Medium = 2,
    Hard = 3,
    Expert = 4
}

public partial class BoardHandler : MonoBehaviour
{
    void selectDificult(int idx)
    {
        switch (idx)
        {
            case 0:
                dificulty = Dificulty.Easy;
                break;
            case 1:
                dificulty = Dificulty.Normal;
                break;
            case 2:
                dificulty = Dificulty.Medium;
                break;
            case 3:
                dificulty = Dificulty.Hard;
                break;
            case 4:
                dificulty = Dificulty.Expert;
                break;
        }
        resetAll();
        init();
    }

    void init()
    {
        CG_SelectDificult.gameObject.SetActive(false);
        // 9x9 그리드 데이터를 생성.
        initGrid(solvedGrid);

        // 생성한 그리드 데이터 숫자를 섞어줌.
        shuffleGrid(solvedGrid, 25);
        debugGrid(solvedGrid);

        // 생성한 그리드 데이터를 기반으로 View 생성.
        initView(solvedGrid);
        reSizeView();

        // AdsManager ad = GameObject.FindWithTag("AdsManager").gameObject.GetComponent<AdsManager>();
        // ad.AdsInit();
        setTheme();
    }

    // 처음 화면이 만들어지는 곳.
    void initView(int[,] grid)
    {
        CG_Board.alpha = 0;
        PrefabItem.SetActive(false);
        List_CellItem = new List<CellItem>();

        PrefabItem.GetComponent<Image>().color = ListColor[ThemeNum].Clr_Cell;
        PrefabItem.transform.GetChild(0).GetComponent<Text>().color = ListColor[ThemeNum].Clr_CellText;

        for (int i = 0; i < 9; i++)
        {
            for (int j = 0; j < 9; j++)
            {
                GameObject go = Instantiate(PrefabItem);
                go.transform.SetParent(PrefabItem.transform.parent);
                go.transform.localScale = Vector3.one;
                go.transform.localPosition = Vector3.zero;
                go.SetActive(true);
                Transform t_Memo = go.transform.GetChild(1);
                List<GameObject> list_MemoNums = new List<GameObject>();
                for (int k = 0; k < t_Memo.childCount; k++)
                {
                    t_Memo.GetChild(k).gameObject.SetActive(false);
                    list_MemoNums.Add(t_Memo.GetChild(k).gameObject);
                }
                CellItem item = new CellItem
                {
                    RT = go.GetComponent<RectTransform>(),
                    FM = go.GetComponent<FreeModifier>(),
                    Btn = go.GetComponent<Button>(),
                    Txt = go.transform.GetChild(0).GetComponent<Text>(),
                    Img = go.GetComponent<Image>(),
                    MyNum = grid[i, j],
                    IsOpen = true,
                    GO_Memo = t_Memo.gameObject,
                    List_MemoNums = list_MemoNums
                };

                item.Txt.text = grid[i, j].ToString();
                item.MyPos = new Vector2(i, j);
                item.Btn.onClick.AddListener(() => { clickedItem(item); });

                // 9개 영역으로 구문하기 위한 넘버링 : 숫자가 열렸을 경우 메모해 두었던 숫자도 리셋해주기 위해 구분 함.
                if (i > 2 && i < 6 && j < 3)                // 1번 그룹 9개
                    item.MyGroup = 1;
                else if (i > 2 && i < 6 && j < 3)           // 2번 그룹 9개
                    item.MyGroup = 2;
                else if (i > 5 && j < 3)                    // 3번 그룹 9개
                    item.MyGroup = 3;
                else if (i < 3 && j > 2 && j < 6)           // 4번 그룹 9개
                    item.MyGroup = 4;
                else if (i > 2 && i < 6 && j > 2 && j < 6)  // 5번 그룹 9개
                    item.MyGroup = 5;
                else if (i > 5 && j > 2 && j < 6)           // 6번 그룹 9개
                    item.MyGroup = 6;
                else if (i < 3 && j > 5)                    // 7번 그룹 9개
                    item.MyGroup = 7;
                else if (i > 2 && i < 6 && j > 5)           // 8번 그룹 9개
                    item.MyGroup = 8;
                else if (i > 5 && j > 5)                    // 9번 그룹 9개
                    item.MyGroup = 9;

                List_CellItem.Add(item);
            }
        }

        //! Hide Random Cell from Dificulty
        if (dificulty == Dificulty.Easy)
        {
            Txt_Level.text = "Easy";
            hideCount = 10;
        }
        else if (dificulty == Dificulty.Normal)
        {
            Txt_Level.text = "Normal";
            hideCount = 27;//28
        }
        else if (dificulty == Dificulty.Medium)
        {
            Txt_Level.text = "Medium";
            hideCount = 37;//38;
        }
        else if (dificulty == Dificulty.Hard)
        {
            Txt_Level.text = "Hard";
            hideCount = 45;//46;
        }
        else if (dificulty == Dificulty.Expert)
        {
            Txt_Level.text = "Expert";
            hideCount = 55;//56;
        }
        setHint();

        // 난이도에 따라 숨겨질 셀을 램덤으로 처리
        List<int> listHideNum = new List<int>();
        for (int i = 0; i < hideCount; i++)
        {
            int ran = getRandomNumber(listHideNum, List_CellItem.Count);
            listHideNum.Add(ran);
        }

        for (int i = 0; i < listHideNum.Count; i++)
        {
            for (int j = 0; j < List_CellItem.Count; j++)
            {
                if (listHideNum[i] == j)
                {
                    List_CellItem[j].IsOpen = false;
                    List_CellItem[j].Txt.gameObject.SetActive(false);
                }
            }
        }
        for (int i = 0; i < List_CellItem.Count; i++)
        {
            if (List_CellItem[i].IsOpen)
            {
                List_CellItem[i].IsOrigin = true;
                // List_CellItem[i].Txt.fontStyle = FontStyle.Bold;
                List_CellItem[i].Txt.color = ListColor[ThemeNum].Clr_CellTextOrigin;
            }
        }
        CG_Board.DOFade(1, 0.5f).SetEase(SineInOut90);
        isPlay = true;

        setNumberCount();
    }

    // 하단 숫자버튼에 남은 수 표기 및 해당 버튼의 숫자가 0일 경우 비활성화
    void setNumberCount()
    {
        List<int> counts = new List<int>() { 0, 0, 0, 0, 0, 0, 0, 0, 0 };

        for (int i = 0; i < List_CellItem.Count; i++)
        {
            if (!List_CellItem[i].IsOpen)
            {
                if (List_CellItem[i].MyNum == 1)
                    counts[0]++;
                else if (List_CellItem[i].MyNum == 2)
                    counts[1]++;
                else if (List_CellItem[i].MyNum == 3)
                    counts[2]++;
                else if (List_CellItem[i].MyNum == 4)
                    counts[3]++;
                else if (List_CellItem[i].MyNum == 5)
                    counts[4]++;
                else if (List_CellItem[i].MyNum == 6)
                    counts[5]++;
                else if (List_CellItem[i].MyNum == 7)
                    counts[6]++;
                else if (List_CellItem[i].MyNum == 8)
                    counts[7]++;
                else if (List_CellItem[i].MyNum == 9)
                    counts[8]++;
            }
        }

        for (int i = 0; i < ListNumCountTxt.Count; i++)
        {
            ListNumCountTxt[i].color = ListColor[ThemeNum].Clr_CellText;
            if (counts[i] != 0)
            {
                ListNumCountTxt[i].gameObject.transform.parent.transform.GetChild(0).gameObject.GetComponent<Text>().color = ListColor[ThemeNum].Clr_CellText;
                ListNumCountTxt[i].gameObject.transform.parent.GetComponent<Button>().interactable = true;
                ListNumCountTxt[i].text = counts[i].ToString();
            }
            else
            {
                Color _cor = ListColor[ThemeNum].Clr_CellText;
                ListNumCountTxt[i].gameObject.transform.parent.transform.GetChild(0).gameObject.GetComponent<Text>().color = new Vector4(_cor.r, _cor.g, _cor.b, 0.2f);
                ListNumCountTxt[i].gameObject.transform.parent.GetComponent<Button>().interactable = false;
                ListNumCountTxt[i].text = "";
            }
        }
    }

    // 그리드 배열이 처음 생성되는 곳. 9x9의 갯수로 숫자가 섞이지 않고 일단 생성만 된다.
    void initGrid(int[,] grid)
    {
        for (int i = 0; i < 9; i++)
        {
            for (int j = 0; j < 9; j++)
            {
                grid[i, j] = (i * 3 + i / 3 + j) % 9 + 1;
            }
        }
    }

    // 디버깅용.
    void debugGrid(int[,] grid)
    {
        s = "";
        int sep = 0;

        for (int i = 0; i < 9; i++)
        {
            s += "|";
            for (int j = 0; j < 9; j++)
            {
                s += grid[i, j].ToString();

                sep = j % 3;
                if (sep == 2)
                    s += "|";
            }
            s += "\n";
        }
        Debug.Log("debugGrid : " + s);
    }

    // 전체 셀의 숫자들을 섞어준다.
    void shuffleGrid(int[,] grid, int shuffleAmount)
    {
        for (int i = 0; i < shuffleAmount; i++)
        {
            int value1 = Random.Range(1, 10);
            int value2 = Random.Range(1, 10);

            mixTwoGridCells(grid, value1, value2);
        }
        for (int i = 0; i < shuffleAmount; i++)
            shuffleGridHorizontal();
    }

    void shuffleGridHorizontal()
    {
        int ran = Random.Range(0, 8);
        int target = ran + 3;
        if (target > 8)
            target = target - 9;

        int small = 0, big = 0;
        if (ran > target)
        {
            small = target;
            big = ran;
        }
        else
        {
            small = ran;
            big = target;
        }
        Debug.Log(small + " change " + big);
        int changeNum = 0;
        for (int x = 0; x < 9; x++)
        {
            for (int y = 0; y < 9; y++)
            {
                if (y == small)
                {
                    changeNum = solvedGrid[x, y];
                }
                if (y == big)
                {
                    solvedGrid[x, small] = solvedGrid[x, y];
                    solvedGrid[x, y] = changeNum;
                }
            }
        }
    }

    void mixTwoGridCells(int[,] grid, int value1, int value2)
    {
        int x1 = 0, x2 = 0, y1 = 0, y2 = 0;

        for (int i = 0; i < 9; i += 3)
        {
            for (int j = 0; j < 9; j += 3)
            {
                for (int k = 0; k < 3; k++)
                {
                    for (int l = 0; l < 3; l++)
                    {
                        if (grid[i + k, j + l] == value1)
                        {
                            x1 = i + k;
                            y1 = j + l;
                        }

                        if (grid[i + k, j + l] == value2)
                        {
                            x2 = i + k;
                            y2 = j + l;
                        }
                    }
                }
                grid[x1, y1] = value2;
                grid[x2, y2] = value1;
            }
        }
    }

    // 겹치지 않는 랜덤 숫자를 가져온다.
    private int getRandomNumber(List<int> seleced, int max)
    {
        var range = Enumerable.Range(0, max).Where(i => !seleced.Contains(i));
        int index = Random.Range(0, max - seleced.Count);
        return range.ElementAt(index);
    }
}

 

BoardHandler.LayoutColor.cs 작성

게임의 컬러테마를 관리하는 파일.

using System;
using UnityEngine;
using UnityEngine.UI;

[Serializable]
public class ColorSet
{
    public Color Clr_BG;
    public Color Clr_Grid;
    public Color Clr_Cell, Clr_CellIsNotOpen;
    public Color Clr_CellText;
    public Color Clr_CellMemoText;
    public Color Clr_CellRed;
    public Color Clr_CellTextOrigin;
    public Color Clr_ButtonBG;
    public Color Clr_ButtonText;
    //======
    public Color Clr_Focused, Clr_UnFocused, Clr_FocusedSameNum, Clr_FocusLine, Clr_MemoMode, Clr_PlayMode;
    //======
    public Color Clr_ToastBg, Clr_ToastText;
}

public partial class BoardHandler : MonoBehaviour
{
    void changeTheme()
    {
        ThemeNum++;
        if (ThemeNum > ListColor.Count - 1)
            ThemeNum = 0;
        setTheme();
        PlayerPrefs.SetInt("ThemeNum", ThemeNum);
    }
    void setTheme()
    {
        for (int i = 0; i < Img_BGs.Count; i++)
            Img_BGs[i].color = ListColor[ThemeNum].Clr_BG;

        for (int i = 0; i < List_CellItem.Count; i++)
        {
            if (List_CellItem[i].IsOpen)
                List_CellItem[i].Img.color = ListColor[ThemeNum].Clr_Cell;
            else
                List_CellItem[i].Img.color = ListColor[ThemeNum].Clr_CellIsNotOpen;
            if (List_CellItem[i].Txt.gameObject.activeInHierarchy)
            {
                if (List_CellItem[i].IsOpen)
                {
                    if (!List_CellItem[i].IsOrigin)
                        List_CellItem[i].Txt.color = ListColor[ThemeNum].Clr_CellText;
                    else
                        List_CellItem[i].Txt.color = ListColor[ThemeNum].Clr_CellTextOrigin;
                }
                else
                    List_CellItem[i].Txt.color = ListColor[ThemeNum].Clr_CellRed;
            }

            for (int j = 0; j < List_CellItem[i].List_MemoNums.Count; j++)
                List_CellItem[i].List_MemoNums[j].GetComponent<Text>().color = ListColor[ThemeNum].Clr_CellMemoText;
        }

        for (int i = 0; i < Img_Grids.Count; i++)
            Img_Grids[i].color = ListColor[ThemeNum].Clr_Grid;

        if (MyStatus == Status.MemoMode)
            toMemoMode();
        else
            toPlayMode();

        for (int i = 0; i < ListButtons.Count; i++)
            ListButtons[i].color = ListColor[ThemeNum].Clr_ButtonBG;

        for (int i = 0; i < ListButtonIcons.Count; i++)
            ListButtonIcons[i].color = ListColor[ThemeNum].Clr_ButtonText;

        for (int i = 0; i < ListButtonsTexts.Count; i++)
            ListButtonsTexts[i].color = ListColor[ThemeNum].Clr_ButtonText;

        for (int i = 0; i < ListToastBGs.Count; i++)
            ListToastBGs[i].color = ListColor[ThemeNum].Clr_ToastBg;

        for (int i = 0; i < ListToastTexts.Count; i++)
            ListToastTexts[i].color = ListColor[ThemeNum].Clr_ToastText;

        for (int i = 0; i < PrefabCellItem.List_MemoNums.Count; i++)
            PrefabCellItem.List_MemoNums[i].GetComponent<Text>().color = ListColor[ThemeNum].Clr_CellMemoText;

        setNumberCount();
    }

    // 레이아웃의 사이즈가 달라질 경우 레이아웃을 다시 잡아줌.
    void reSizeView()
    {
        boardW = RT_Borad.rect.width;
        float width = (boardW - spacing * 8 - padding * 2) / 9;
        GLG_Holder.cellSize = new Vector2(width, width);
        GLG_Holder.spacing = new Vector2(spacing, spacing);
        GLG_Holder.padding.left = (int)padding;
        GLG_Holder.padding.right = (int)padding;

        VLG.spacing = width * 3 + spacing * 3 - 10;
        HLG.spacing = width * 3 + spacing * 3 - 10;

        screenW = GetComponent<RectTransform>().rect.width;
        screenH = GetComponent<RectTransform>().rect.height;
        float topHeight = (screenH - screenW) / 2 - 200;
        float botHeight = (screenH - screenW) / 2 + 200;
        float topPosY = screenW / 2 + RT_Top.rect.height / 2 + 200;
        float botPosY = -(screenW / 2 + RT_Bot.rect.height / 2) + 200;
        float gap = 0;
        if (topHeight < 160)
        {
            gap = topHeight - 160;
            Debug.Log(gap);
            RT_Borad.sizeDelta = new Vector2(1080 + gap, 1080 + gap);
            topHeight = 160;
            RT_BotUIHolder.localScale = new Vector3(RT_Borad.rect.width / 1080, RT_Borad.rect.width / 1080, RT_Borad.rect.width / 1080);
            RT_TopUIHolder.localScale = new Vector3(RT_Borad.rect.width / 1080, RT_Borad.rect.width / 1080, RT_Borad.rect.width / 1080);
        }
        else
        {
            RT_Borad.sizeDelta = new Vector2(1080, 1080);
            RT_BotUIHolder.localScale = Vector3.one;
        }
        RT_Top.sizeDelta = new Vector2(screenW, topHeight);
        // RT_Bot.sizeDelta = new Vector2(screenW, botHeight);
        // RT_Top.anchoredPosition = new Vector2(0, screenW / 2 + RT_Top.rect.height / 2 + 200);
        RT_Bot.anchoredPosition = new Vector2(0, -(screenW / 2 + RT_Bot.rect.height / 2) + 200);
    }

    // 레이아웃 사이즈를 자동 조절
    void setResize()
    {
        if (tempPadding != padding || tempSpacing != spacing || screenSize.x != Screen.width || screenSize.y != Screen.height)                                           // 패딩값이나 간격값이 바뀌게 되면 자동으로 레이아웃을 적용하도록 처리
        {
            tempPadding = padding;
            tempSpacing = spacing;
            reSizeView();
        }
        if (tempRound != round)
        {
            tempRound = round;
            for (int i = 0; i < List_CellItem.Count; i++)
                List_CellItem[i].FM.Radius = new Vector4(round, round, round, round);
        }
    }
}

 

HistoryManger.cs 작성

게임을 플레이하고 클리어 했던 기록을 볼 수 있도록하는 스크립트.

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;

[Serializable]
public class HistoryData
{
    public string date;
    public string dificult;
    public string time;
    public string mistake;
    public string hint;
}
public class HistoryItem
{
    public GameObject Go_Me;
    public Text Txt_Date, Txt_Level, Txt_Time, Txt_Mis, Txt_Hint;
}

public class HistoryManger : MonoBehaviour
{
    [SerializeField] string myHistoryTxt;
    [SerializeField] List<HistoryData> listHistory;
    [SerializeField] Button btn_History, btn_Reset;
    [SerializeField] ToastPopupHandler toastPopup;
    [SerializeField] List<HistoryItem> List_HistoryItem;
    [SerializeField] GameObject go_Prefab;
    [SerializeField] Transform t_Content;
    [SerializeField] CanvasGroup cg_View;
    [SerializeField] RectTransform rt_View;
    [SerializeField] Button btn_Close, btn_OpenRecords;
    [SerializeField] GameObject go_NoData;

    void Start()
    {
        rt_View.localScale = new Vector3(0.9f, 0.9f, 0.9f);
        cg_View.alpha = 0;
        cg_View.blocksRaycasts = false;

        List_HistoryItem = new List<HistoryItem>();
        // PlayerPrefs.SetString(BoardHandler.HISTORY, "");
        if (PlayerPrefs.GetString(BoardHandler.HISTORY).Length > 5)
            myHistoryTxt = PlayerPrefs.GetString(BoardHandler.HISTORY);
        else
            myHistoryTxt = "";
        btn_History.onClick.AddListener(openHistory);
        btn_OpenRecords.onClick.AddListener(openHistory);
        btn_Reset.onClick.AddListener(resetHistory);


        // Debug.Log(getDateStr());
        btn_Close.onClick.AddListener(closeHistory);
    }

    void openHistory()
    {
        LoadHistory();
        viewHistory();
    }

    void resetHistory()
    {
        PlayerPrefs.SetString(BoardHandler.HISTORY, "");
        toastPopup.Popup("Deleted all history");
        if (List_HistoryItem != null)
        {
            for (int i = 0; i < List_HistoryItem.Count; i++)
            {
                Destroy(List_HistoryItem[i].Go_Me);
            }
        }
        myHistoryTxt = "";
        listHistory.Clear();
        List_HistoryItem.Clear();
    }


    public void SaveHistory(string _dificult, string _time, string _mistake, string _hint)
    {
        string _date = getDateStr();
        string newHistory = _date + ";" + _dificult + ";" + _time + ";" + _mistake + ";" + _hint;
        if (myHistoryTxt.Length > 5)
            myHistoryTxt = myHistoryTxt + "," + newHistory;
        else
            myHistoryTxt = newHistory;
        PlayerPrefs.SetString(BoardHandler.HISTORY, myHistoryTxt);
    }

    public void LoadHistory()
    {
        listHistory = new List<HistoryData>();
        string[] words = myHistoryTxt.Split(',');
        foreach (var word in words)
        {
            HistoryData item = new HistoryData();
            string[] datas = word.Split(';');
            for (int i = 0; i < datas.Length; i++)
            {
                if (i == 0)
                    item.date = datas[i];
                else if (i == 1)
                    item.dificult = datas[i];
                else if (i == 2)
                    item.time = datas[i];
                else if (i == 3)
                    item.mistake = datas[i];
                else if (i == 4)
                    item.hint = datas[i];
            }
            listHistory.Add(item);
        }
    }

    void viewHistory()
    {
        if (List_HistoryItem != null)
        {
            for (int i = 0; i < List_HistoryItem.Count; i++)
            {
                Destroy(List_HistoryItem[i].Go_Me);
            }
        }
        List_HistoryItem.Clear();

        for (int i = 0; i < listHistory.Count; i++)
        {
            GameObject go = Instantiate(go_Prefab);
            go.SetActive(true);
            go.transform.SetParent(t_Content);
            go.transform.localScale = Vector3.one;
            go.transform.localPosition = Vector3.zero;
            HistoryItem item = new HistoryItem
            {
                Txt_Date = go.transform.GetChild(0).GetComponent<Text>(),
                Txt_Level = go.transform.GetChild(1).GetComponent<Text>(),
                Txt_Time = go.transform.GetChild(2).GetComponent<Text>(),
                Txt_Mis = go.transform.GetChild(3).GetComponent<Text>(),
                Txt_Hint = go.transform.GetChild(4).GetComponent<Text>(),
                Go_Me = go
            };
            item.Txt_Date.text = listHistory[i].date;
            item.Txt_Level.text = listHistory[i].dificult;
            item.Txt_Time.text = listHistory[i].time;
            item.Txt_Mis.text = listHistory[i].mistake;
            item.Txt_Hint.text = listHistory[i].hint;
            List_HistoryItem.Add(item);
        }
        if (myHistoryTxt.Length > 0)
        {
            go_NoData.SetActive(false);
        }
        else
        {
            go_NoData.SetActive(true);
        }
        cg_View.blocksRaycasts = true;
        cg_View.DOFade(1, 0.35f).SetEase(BoardHandler.SineInOut90);
        rt_View.DOScale(1, 0.35f).SetEase(BoardHandler.SineInOut90);
    }

    void closeHistory()
    {
        cg_View.blocksRaycasts = false;
        cg_View.DOFade(0, 0.35f).SetEase(BoardHandler.SineInOut90);
        rt_View.DOScale(0.9f, 0.35f).SetEase(BoardHandler.SineInOut90);
    }

    string getDateStr()
    {
        return DateTime.Now.ToString("yyyy-MM-dd\\ HH:mm");
    }
}

 

MenuHandler.cs 작성

게임화면에서 메뉴화면을 호출하기 위한 파일.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;

public class MenuHandler : MonoBehaviour
{
    [SerializeField] RectTransform RT_Menu;
    RectTransform rt_me;
    [SerializeField] Button Btn_Open, Btn_Close, Btn_CloseX;
    [SerializeField] CanvasGroup CG_Me;
    bool isOpen;
    float height;

    void Start()
    {
        Btn_Open.onClick.AddListener(openMenu);
        Btn_Close.onClick.AddListener(closeMenu);
        Btn_CloseX.onClick.AddListener(closeMenu);
        rt_me = GetComponent<RectTransform>();
        height = RT_Menu.rect.height;
        // Debug.Log(height);
        isOpen = false;
        CG_Me.blocksRaycasts = false;
        CG_Me.alpha = 0;
        RT_Menu.anchoredPosition = new Vector2(-1080, 0);
    }

    void openMenu()
    {
        BoardHandler.isPlay = false;
        isOpen = true;
        CG_Me.blocksRaycasts = true;
        CG_Me.alpha = 0;
        CG_Me.DOFade(1, 0.2f);
        RT_Menu.DOAnchorPosX(0, 0.35f).SetEase(BoardHandler.SineInOut90);
    }
    void closeMenu()
    {
        BoardHandler.isPlay = true;
        isOpen = false;
        CG_Me.blocksRaycasts = false;
        RT_Menu.DOAnchorPosX(-1080, 0.35f).SetEase(BoardHandler.SineInOut90);
        CG_Me.DOFade(0, 0.35f);
    }
}

 

NewGamePopupHandler.cs 작성

새로운 게임을 하기위해 버튼을 누를 경우 새로운 게임을 할 수 있게 하는 팝업을 호출 하기 위한 파일.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;

public class NewGamePopupHandler : MonoBehaviour
{
    [SerializeField] CanvasGroup CG;
    public Button Btn_Cancel, Btn_RePlay, Btn_NewGame;
    void Start()
    {
        Btn_Cancel.onClick.AddListener(Close);
        Btn_NewGame.onClick.AddListener(Close);
        Btn_RePlay.onClick.AddListener(Close);
        gameObject.SetActive(false);
    }

    void Close()
    {

        CG.blocksRaycasts = false;
        CG.DOFade(0, 0.3f).SetEase(BoardHandler.SineInOut90).OnComplete(() =>
        {
            gameObject.SetActive(false);
        });
    }

    public void Open()
    {
        gameObject.SetActive(true);
        CG.blocksRaycasts = true;
        CG.DOFade(1, 0.3f).SetEase(BoardHandler.SineInOut90);
    }
}

 

ToastPopupHandler.cs 작성

게임 중에 간단한 팝업 문구를 띄우기 위한 스크립트.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;

public class ToastPopupHandler : MonoBehaviour
{
    [SerializeField] Text Txt_Msg;
    [SerializeField] CanvasGroup CG;
    [SerializeField] Button Btn_Dim;
    public void Popup(string msg)
    {
        CG.DOKill();
        CG.alpha = 0;
        CG.DOFade(1, 0.3f).SetEase(Ease.OutQuart);
        CG.blocksRaycasts = true;
        Txt_Msg.text = msg;
        CancelInvoke("Hide");
        Invoke("Hide", 2f);
    }

    void Start()
    {
        Hide();
        Btn_Dim.onClick.AddListener(() =>
        {
            CancelInvoke("Hide");
            Hide();
        });
    }

    void Hide()
    {
        CG.blocksRaycasts = false;
        CG.DOFade(0, 0.3f).SetEase(Ease.OutQuart);
    }
}

 

UnityAdsManager.cs 작성

유니티에서 제공하고 있는 광고를 띄우기 위한 스크립트.

광고에 대한 부분은 추가로 포스팅 예정.

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.Advertisements;

public class UnityAdsManager : MonoBehaviour
{
    public BoardHandler Board;
    public ToastPopupHandler Toast;
    public string bannerId = "banner";
    public string rewardedId = "rewardedVideo";
    public string videoId = "video";
    public bool testMode = true;

#if UNITY_IOS 
    public const string gameID = "IOS용 광고아이디";
#elif UNITY_ANDROID
    public const string gameID = "Android용 광고아이디"; 
#elif UNITY_EDITOR
    public const string gameID = "";
#endif

    void Start()
    {
        Advertisement.Initialize(gameID, testMode);
        ShowBanner();
    }

    public void ShowBanner()
    {

        StartCoroutine(ShowBannerWhenReady());
    }

    IEnumerator ShowBannerWhenReady()
    {
        while (!Advertisement.isInitialized)
        {
            yield return new WaitForSeconds(0.5f);
        }
        Advertisement.Banner.Show(bannerId);
    }

    static string myTarget;
    public void AdsShow(string target = "hint")
    {
        myTarget = target;
        ShowRewardedAd();
    }
    public void AdsShowNewGame()
    {

    }

    /// === New Game Ads ==========

    public void ShowNewGameAd()
    {
        if (Advertisement.IsReady(videoId))
        {
            var options = new ShowOptions { resultCallback = HandleNewGameAdShowResult };
            Advertisement.Show(videoId, options);
        }
    }

    private void HandleNewGameAdShowResult(ShowResult result)
    {
        switch (result)
        {
            case ShowResult.Finished:
                Board.resetAll();
                break;
            case ShowResult.Skipped:
                Board.resetAll();
                break;
            case ShowResult.Failed:
                Toast.Popup("Ads Load failed.");
                break;
        }
    }


    /// === Reward Ads ===========

    public void ShowRewardedAd()
    {
        if (Advertisement.IsReady(rewardedId))
        {
            // 광고가 끝난 뒤 콜백함수 "HandleShowResult" 호출 
            var options = new ShowOptions { resultCallback = HandleShowResult };
            Advertisement.Show(rewardedId, options);
        }
    }

    // 광고가 종료된 후 자동으로 호출되는 콜백 함수 
    private void HandleShowResult(ShowResult result)
    {
        switch (result)
        {
            case ShowResult.Finished:
                // 광고를 성공적으로 시청한 경우 보상 지급 
                if (myTarget == "hint")
                {
                    Board.SetHint = 1;
                    Board.Invoke("HintOpen", 0.5f);
                }
                else if (myTarget == "rePlay")
                {
                    Board.RePlayGame();
                }
                break;
            case ShowResult.Skipped:
                // 스킵 되었다면 뭔가 그런짓을 하면 보상을 줄 수 없잖아! 같은 창을 띄워야곘죠?
                Toast.Popup("Skiped Ads...");
                break;
            case ShowResult.Failed:
                Toast.Popup("Skiped Ads or Load failed");
                break;
        }
    }
}

 

신을 만들고 세팅하는 부분은 따로 시간 나면 정리 예정...

반응형

'unity C#' 카테고리의 다른 글

[Unity] MQTT 통신 구현  (0) 2021.10.19
[Unity] Tetris 게임 만들기  (1) 2021.06.25
[Unity] UDP 통신  (0) 2021.05.04
[Unity] Partial class  (0) 2021.05.04
[Unity] Sprite Atlas  (0) 2021.04.13

+ Recent posts