스와이프 벽돌깨기 원커맨드로 만들기!





OneCommand.Cs 소스입니다



using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;

public class OneCommand : MonoBehaviour
{
    #region 태그에 따른 함수호출
    void Awake() { if (CompareTag("GameManager")) Awake_GM(); }

    void Update() { if (CompareTag("GameManager")) Update_GM(); }

    void FixedUpdate() { if (CompareTag("GameManager")) FixedUpdate_GM(); }

    void Start() { if (CompareTag("Ball")) Start_BALL(); }

    void OnCollisionEnter2D(Collision2D col) { if (CompareTag("Ball")) StartCoroutine(OnCollisionEnter2D_BALL(col)); }

    void OnTriggerEnter2D(Collider2D col) { if (CompareTag("Ball")) StartCoroutine(OnTriggerEnter2D_BALL(col)); }
    #endregion



    #region GameManager.Cs
    [Header("GameManagerValue")]
    public float groundY = -55.489f;
    public GameObject P_Ball, P_GreenOrb, P_Block, P_ParticleBlue, P_ParticleGreen, P_ParticleRed;
    public GameObject BallPreview, Arrow, GameOverPanel, BallCountTextObj, BallPlusTextObj;
    public Transform GreenBallGroup, BlockGroup, BallGroup;
    public LineRenderer MouseLR, BallLR;
    public Text BestScoreText, ScoreText, BallCountText, BallPlusText, FinalScoreText, NewRecordText;
    public Color[] blockColor;
    public Color greenColor;
    public AudioSource S_GameOver, S_GreenOrb, S_Plus;
    public AudioSource[] S_Block;
    public Quaternion QI = Quaternion.identity;
    public bool shotTrigger, shotable;
    public Vector3 veryFirstPos;

    Vector3 firstPos, secondPos, gap;
    int score, timerCount, launchIndex;
    bool timerStart, isDie, isNewRecord, isBlockMoving;
    float timeDelay;


    #region 시작
    void Awake_GM()
    {
        // 9:16 고정해상도 카메라
        Camera camera = Camera.main;
        Rect rect = camera.rect;
        float scaleheight = ((float)Screen.width / Screen.height) / ((float)9 / 16); // (가로 / 세로)
        float scalewidth = 1f / scaleheight;
        if (scaleheight < 1)
        {
            rect.height = scaleheight;
            rect.y = (1f - scaleheight) / 2f;
        }
        else
        {
            rect.width = scalewidth;
            rect.x = (1f - scalewidth) / 2f;
        }
        camera.rect = rect;


        // 시작
        BlockGenerator();
        BestScoreText.text = "최고기록 : " + PlayerPrefs.GetInt("BestScore").ToString();
    }



    public void Restart() => SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);



    public void VeryFirstPosSet(Vector3 pos) { if (veryFirstPos == Vector3.zero) veryFirstPos = pos; }
    #endregion



    #region 블럭
    void BlockGenerator()
    {
        // 점수 
        ScoreText.text = "현재점수 : " + (++score).ToString();
        if (PlayerPrefs.GetInt("BestScore", 0) < score)
        {
            PlayerPrefs.SetInt("BestScore", score);
            BestScoreText.text = "최고기록 : " + PlayerPrefs.GetInt("BestScore").ToString();
            BestScoreText.color = greenColor;
            isNewRecord = true;
        }


        // 점수에 따른 블럭복사개수 정하기
        int count;
        int randBlock = Random.Range(0, 24);
        if (score <= 10) count = randBlock < 16 ? 1 : 2;
        else if (score <= 20) count = randBlock < 8 ? 1 : (randBlock < 16 ? 2 : 3);
        else if (score <= 40) count = randBlock < 9 ? 2 : (randBlock < 18 ? 3 : 4);
        else count = randBlock < 8 ? 2 : (randBlock < 16 ? 3 : (randBlock < 20 ? 4 : 5));


        // 스폰좌표에 블럭, 초록구 생성
        List<Vector3> SpawnList = new List<Vector3>();
        for (int i = 0; i < 6; i++) SpawnList.Add(new Vector3(-46.7f + i * 18.68f, 51.2f, 0));

        for (int i = 0; i < count; i++)
        {
            int rand = Random.Range(0, SpawnList.Count);

            Transform TR = Instantiate(P_Block, SpawnList[rand], QI).transform;
            TR.SetParent(BlockGroup);
            TR.GetChild(0).GetComponentInChildren<Text>().text = score.ToString();

            SpawnList.RemoveAt(rand);
        }
        Instantiate(P_GreenOrb, SpawnList[Random.Range(0, SpawnList.Count)], QI).transform.SetParent(BlockGroup);


        // 블럭 내리기
        isBlockMoving = true;
        for (int i = 0; i < BlockGroup.childCount; i++) StartCoroutine(BlockMoveDown(BlockGroup.GetChild(i)));
    }



    IEnumerator BlockMoveDown(Transform TR)
    {
        yield return new WaitForSeconds(0.2f);
        Vector3 targetPos = TR.position + new Vector3(0, -12.8f, 0);
        BlockColorChange();


        // 막줄이면 게임오버 트리거, 콜라이더 비활성화
        if (targetPos.y < -50)
        {
            if (TR.CompareTag("Block")) isDie = true;
            for (int i = 0; i < BallGroup.childCount; i++)
                BallGroup.GetChild(i).GetComponent<CircleCollider2D>().enabled = false;
        }


        // 0.3초간 블럭 이동
        float TT = 1.5f;
        while (true)
        {
            yield return null; TT -= Time.deltaTime * 1.5f;
            TR.position = Vector3.MoveTowards(TR.position, targetPos + new Vector3(0, -6, 0), TT);
            if (TR.position == targetPos + new Vector3(0, -6, 0)) break;
        }
        TT = 0.9f;
        while (true)
        {
            yield return null; TT -= Time.deltaTime;
            TR.position = Vector3.MoveTowards(TR.position, targetPos, TT);
            if (TR.position == targetPos) break;
        }
        isBlockMoving = false;


        // 이동되고 난 후 막줄이면 블럭이면 게임오버, 초록구면 파괴
        if (targetPos.y < -50)
        {
            if (TR.CompareTag("Block"))
            {
                for (int i = 0; i < BallGroup.childCount; i++)
                    Destroy(BallGroup.GetChild(i).gameObject);
                Destroy(Instantiate(P_ParticleBlue, veryFirstPos, QI), 1);

                BallCountTextObj.SetActive(false);
                BallPlusTextObj.SetActive(false);
                BestScoreText.gameObject.SetActive(false);
                ScoreText.gameObject.SetActive(false);

                GameOverPanel.SetActive(true);
                FinalScoreText.text = "최종점수 : " + score.ToString();
                if (isNewRecord) NewRecordText.gameObject.SetActive(true);

                Camera.main.GetComponent<Animator>().SetTrigger("shake");
                S_GameOver.Play();
            }
            else
            {
                Destroy(TR.gameObject);
                Destroy(Instantiate(P_ParticleGreen, TR.position, QI), 1);

                for (int i = 0; i < BallGroup.childCount; i++)
                    BallGroup.GetChild(i).GetComponent<CircleCollider2D>().enabled = true;
            }
        }
    }



    public void BlockColorChange()
    {
        // 블럭텍스트 / 스코어를 7등분해서 색을 칠함
        for (int i = 0; i < BlockGroup.childCount; i++)
        {
            if (BlockGroup.GetChild(i).CompareTag("Block"))
            {
                float per = int.Parse(BlockGroup.GetChild(i).GetChild(0).GetComponentInChildren<Text>().text) / (float)score;
                Color curColor;
                if (per <= 0.1428f) curColor = blockColor[6];
                else if (per <= 0.2856f) curColor = blockColor[5];
                else if (per <= 0.4284f) curColor = blockColor[4];
                else if (per <= 0.5172f) curColor = blockColor[3];
                else if (per <= 0.714f) curColor = blockColor[2];
                else if (per <= 0.8568f) curColor = blockColor[1];
                else curColor = blockColor[0];
                BlockGroup.GetChild(i).GetComponent<SpriteRenderer>().color = curColor;
            }
        }
    }
    #endregion



    void Update_GM()
    {
        if (isDie) return;


        // 마우스 첫번째 좌표
        if (Input.GetMouseButtonDown(0))
            firstPos = Camera.main.ScreenToWorldPoint(Input.mousePosition) + new Vector3(0, 0, 10);


        // 모든 움직임이 끝나면 쏠 수 있음
        shotable = true;
        for (int i = 0; i < BallGroup.childCount; i++)
            if (BallGroup.GetChild(i).GetComponent<OneCommand>().isMoving) shotable = false;
        if (isBlockMoving) shotable = false;


        if (!shotable) return;


        // 모든 공이 바닥에 부딪히면 한 번 실행
        if (shotTrigger && shotable)
        {
            shotTrigger = false;
            BlockGenerator();
            timeDelay = 0;

            StartCoroutine(BallCountTextShow(GreenBallGroup.childCount));
            for (int i = 0; i < GreenBallGroup.childCount; i++) StartCoroutine(GreenBallMove(GreenBallGroup.GetChild(i)));
        }


        timeDelay += Time.deltaTime;
        if (timeDelay < 0.1f) return; // 0.1초 딜레이로 너무 빠르게 손 떼면 라인이 남는 버그 제거


        bool isMouse = Input.GetMouseButton(0);
        if (isMouse)
        {
            // 차이값
            secondPos = Camera.main.ScreenToWorldPoint(Input.mousePosition) + new Vector3(0, 0, 10);
            if ((secondPos - firstPos).magnitude < 1) return;
            gap = (secondPos - firstPos).normalized;
            gap = new Vector3(gap.y >= 0 ? gap.x : gap.x >= 0 ? 1 : -1, Mathf.Clamp(gap.y, 0.2f, 1), 0);


            // 화살표, 공 미리보기
            Arrow.transform.position = veryFirstPos;
            Arrow.transform.rotation = Quaternion.Euler(0, 0, Mathf.Atan2(gap.y, gap.x) * Mathf.Rad2Deg);
            BallPreview.transform.position =
                Physics2D.CircleCast(new Vector2(Mathf.Clamp(veryFirstPos.x, -54, 54), groundY), 1.7f, gap, 10000, 1 << LayerMask.NameToLayer("Wall") | 1 << LayerMask.NameToLayer("Block")).centroid;

            RaycastHit2D hit = Physics2D.Raycast(veryFirstPos, gap, 10000, 1 << LayerMask.NameToLayer("Wall"));


            // 라인
            MouseLR.SetPosition(0, firstPos);
            MouseLR.SetPosition(1, secondPos);
            BallLR.SetPosition(0, veryFirstPos);
            BallLR.SetPosition(1, (Vector3)hit.point - gap * 1.5f);
        }
        BallPreview.SetActive(isMouse);
        Arrow.SetActive(isMouse);


        if (Input.GetMouseButtonUp(0))
        {
            if ((secondPos - firstPos).magnitude < 1) return;

            // 라인 초기화
            MouseLR.SetPosition(0, Vector3.zero);
            MouseLR.SetPosition(1, Vector3.zero);
            BallLR.SetPosition(0, Vector3.zero);
            BallLR.SetPosition(1, Vector3.zero);

            timerStart = true;
            veryFirstPos = Vector3.zero;
            firstPos = Vector3.zero;
        }
    }



    IEnumerator BallCountTextShow(int greenBallCount)
    {
        // 초록공 합쳐지기 전후 공 개수 보여주기
        BallCountTextObj.transform.position = new Vector3(Mathf.Clamp(veryFirstPos.x, -49.9f, 49.9f), -65, 0);
        BallCountText.text = "x" + BallGroup.childCount.ToString();

        yield return new WaitForSeconds(0.17f);

        if (BallGroup.childCount > score) Destroy(BallGroup.GetChild(BallGroup.childCount - 1).gameObject);
        BallCountText.text = "x" + BallGroup.childCount.ToString();


        // 바닥에 떨어진 초록공 +로 표시하기
        if (greenBallCount != 0)
        {
            BallPlusTextObj.SetActive(true);
            BallPlusTextObj.transform.position = new Vector3(Mathf.Clamp(veryFirstPos.x, -49.9f, 49.9f), -47, 0);
            BallPlusText.text = "+" + greenBallCount.ToString();
            S_Plus.Play();

            yield return new WaitForSeconds(0.5f);

            BallPlusTextObj.SetActive(false);
        }
    }



    IEnumerator GreenBallMove(Transform TR)
    {
        // 바닥에 떨어진 초록공 최초좌표로 0.17초간 이동
        Instantiate(P_Ball, veryFirstPos, QI).transform.SetParent(BallGroup);
        float speed = (TR.position - veryFirstPos).magnitude / 12f;
        while (true)
        {
            yield return null;
            TR.position = Vector3.MoveTowards(TR.position, veryFirstPos, speed);
            if (TR.position == veryFirstPos) { Destroy(TR.gameObject); yield break; }
        }
    }



    void FixedUpdate_GM()
    {
        // 0.06초 간격으로 공 발사
        if (timerStart && ++timerCount == 3)
        {
            timerCount = 0;
            BallGroup.GetChild(launchIndex++).GetComponent<OneCommand>().Launch(gap);
            BallCountText.text = "x" + (BallGroup.childCount - launchIndex).ToString();
            if (launchIndex == BallGroup.childCount)
            {
                timerStart = false;
                launchIndex = 0;
                BallCountText.text = "";
            }
        }
    }
    #endregion



    #region BallScript.Cs
    [Header("BallScriptValue")]
    public GameObject P_GreenBall;
    public Rigidbody2D RB;
    public bool isMoving;

    OneCommand GM;



    void Start_BALL() => GM = GameObject.FindWithTag("GameManager").GetComponent<OneCommand>();



    public void Launch(Vector3 pos)
    {
        GM.shotTrigger = true;
        isMoving = true;
        RB.AddForce(pos * 7000);
    }



    IEnumerator OnCollisionEnter2D_BALL(Collision2D col)
    {
        GameObject Col = col.gameObject;
        Physics2D.IgnoreLayerCollision(2, 2);


        // 가로로 움직일경우 아래로 내림
        Vector2 pos = RB.velocity.normalized;
        if (pos.magnitude != 0 && pos.y < 0.15f && pos.y > -0.15f)
        {
            RB.velocity = Vector2.zero;
            RB.AddForce(new Vector2(pos.x > 0 ? 1 : -1, -0.2f).normalized * 7000);
        }


        // 바닥충돌시 최초좌표로 이동
        if (Col.CompareTag("Ground"))
        {
            RB.velocity = Vector2.zero;
            transform.position = new Vector2(col.contacts[0].point.x, GM.groundY);
            GM.VeryFirstPosSet(transform.position);

            while (true)
            {
                yield return null;
                transform.position = Vector3.MoveTowards(transform.position, GM.veryFirstPos, 4);
                if (transform.position == GM.veryFirstPos) { isMoving = false; yield break; }
            }
        }


        // 블럭충돌시 블럭숫자 1씩 줄이다 0이되면 부숨
        if (Col.CompareTag("Block"))
        {
            Text BlockText = col.transform.GetChild(0).GetComponentInChildren<Text>();
            int blockValue = int.Parse(BlockText.text) - 1;
            GM.BlockColorChange();


            for (int i = 0; i < GM.S_Block.Length; i++)
            {
                if (GM.S_Block[i].isPlaying) continue;
                else { GM.S_Block[i].Play(); break; }
            }


            if (blockValue > 0)
            {
                BlockText.text = blockValue.ToString();
                Col.GetComponent<Animator>().SetTrigger("shock");
            }
            else
            {
                Destroy(Col);
                Destroy(Instantiate(GM.P_ParticleRed, col.transform.position, GM.QI), 1);
            }
        }
    }



    IEnumerator OnTriggerEnter2D_BALL(Collider2D col)
    {
        // 초록구 충돌시 초록공 생성해서 아래로 떨어짐
        if (col.gameObject.CompareTag("GreenOrb"))
        {
            Destroy(col.gameObject);
            Destroy(Instantiate(GM.P_ParticleGreen, col.transform.position, GM.QI), 1);

            GM.S_GreenOrb.Play();
            Transform TR = Instantiate(P_GreenBall, col.transform.position, GM.QI).transform;
            TR.SetParent(GameObject.Find("GreenBallGroup").transform);
            Vector3 targetPos = new Vector3(TR.position.x, GM.groundY, 0);
            while (true)
            {
                yield return null;
                TR.position = Vector3.MoveTowards(TR.position, targetPos, 2.5f);
                if (TR.position == targetPos) yield break;
            }
        }
    }
    #endregion
}