프로그래밍 이야기

[유니티 / C#] 간단한 연습 1 : 큐브 가로줄 맞추기

mizq4482 2021. 7. 5. 19:38

 

목적

오브젝트 대량 생성 시스템에 대해서 간단하게 연습.

오브젝트 위치 바꾸기 시스템에 대해서 간단하게 연습.

 

설정

5개의 색의 큐브가 9개씩 생성됨. (45개)

같은 색의 큐브 9개를 같은 가로줄에 놓을 경우 큐브가 전부 파괴됨

큐브를 전부 파괴하면 끝

 

클릭 후 WASD로 이동

오브젝트 클릭, 이동 시 UI(보라색 외곽선)이 갱신됨.

 

기본 점수 300점

이동할 때마다 점수가 -1됨.

단, 이동 방향에 다른 큐브가 없다면 점수가 -2됨.

 

 

자체 피드백

최적화 등을 고려하지를 않았음.

쓸데없이 코드가 길어진 느낌이 있음. 해당 부분에 대한 개선이 필요할거 같음.

특히 오브젝트의 이름에 번호를 추가해주는 (CubeNum) 쪽이 개선이 가능할 것 같음.

 

 

큐브 생성이 완전 랜덤이라서 문제점이 있음.

만약 낮은 확률로 한 줄에 같은 색의 큐브 9개가 생성된다면 그대로 해당 큐브들이 삭제됨.

이런 알고리즘에 대해서 공부해봐야할 듯.

 

큐브 이동시 Vector3 UP / DOWN / LEFT / RIGHT 라는 변수를 만들어 각각 값을 할당해줬는데...

이게 맞는지는 모르겠음. 나중에 코드 추가하거나 보수할 땐 이게 편하려나?

 

 

큐브 파괴의 경우, R/B/G/Y/W 큐브 파괴 스크립트를 각각 만들어줬는데...

함수는 하나의 기능만을 하는게 적합하니까 일부러 나눴는데, 굳이 나눠야했나 싶긴 함.

어차피 기능 자체는 동일하게 큐브를 파괴하는건데...

만약 이 부분을 통합했더라면 코드 길이가 꽤 줄어들었을 것 같다.

 

가능하면 객체지향으로 하긴 했는데, 뭔가 잘못되진 않았나? 이건 잘 모르겠다.

 

 

대충 600줄 / 18,000자 정도 나왔는데 더 줄일 수 있지 않았을까?

그리고 디버그 로그가 좀 더럽다.

 

 

다음엔 이걸 좀 개량해서, 애니팡처럼 가로 3줄 / 세로 3줄 이런걸로 제거하는 걸 연습해봐야겠다.

그겸에 생성 스크립트도 좀 개선해서.

그거 만들 땐 아에 기능 하나 만들때마다 글을 써놔서 내가 보기 쉽게 정리해두는 편이 낫겠다.

 

 

 

 

 

 

 

코드

 

플레이어 컨트롤 스크립트

더보기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class PlayerAction : MonoBehaviour
{
    private bool _mouseState; // 마우스 상태
    [SerializeField] private GameObject target; // 클릭된 타겟
    private Vector3 MousePos; // 마우스 좌표

    public GameObject Effect;
    GameObject UI;

    private static int inputUP = 0;
    private static int inputDOWN = 1;
    private static int inputLEFT = 2;
    private static int inputRIGHT = 3;

    private RaycastHit hit;

    private int movescore = 300; // 이동 횟수 감지

    public Text countText; // 점수 텍스트

    // Start is called before the first frame update
    void Start()
    {
        countText.text = "" + movescore;
         UI = (GameObject)Instantiate(Effect);
        Instantiate(UI, transform.position, UI.transform.rotation);
    }

    // Update is called once per frame
    void Update()
    {
        if (true == Input.GetMouseButtonDown(0)) {
            target = GetClickedObject();
            if (target != null) Effectupdate(target.transform.position);
        }

        if (true ==Input.GetKeyDown(KeyCode.W)) {
            if (target != null) cubeMoving(target, inputUP);
        }
        else if (true == Input.GetKeyDown(KeyCode.A))  {
            if (target != null) cubeMoving(target, inputLEFT);
        }
        else if (true == Input.GetKeyDown(KeyCode.S))
        {
            if (target != null) cubeMoving(target, inputDOWN);
        }
        else if (true == Input.GetKeyDown(KeyCode.D))
        {
            if (target != null) cubeMoving(target, inputRIGHT);
        }

        if (target == null) Effectupdate(this.transform.position);
    }


   private GameObject GetClickedObject() {
      RaycastHit hit;

      GameObject target = null;


      Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); //마우스 포인트 근처 좌표를 만든다. 

        // 마우스 근처에 있나 확인
            if (true == (Physics.Raycast(ray.origin, ray.direction * 10, out hit)))   { 
                target = hit.collider.gameObject;
            }
        
            return target;
        }


    private void cubeMoving(GameObject cube, int dic)
    {
        Vector3 MoveTargetpos = cube.transform.position;
        bool ismove = true;

        Vector3 UP = new Vector3(0, 1.25f, 0);
        Vector3 DOWN = new Vector3(0, -1.25f, 0);
        Vector3 LEFT = new Vector3(-1.25f, 0, 0);
        Vector3 RIGHT = new Vector3(1.25f, 0, 0);


        // 이동 처리
        switch (dic)
        {
            case 0: // UP
                if (MoveTargetpos.y == 5f)
                { // 맨 윗줄일경우 작동하지 않습니다.
                    Debug.Log("move fail: 큐브가 맨 위에 있습니다."); ismove = false;
                }
                else cube.transform.position += UP;
                break;
            case 1: // DOWN
                if (MoveTargetpos.y == 0)
                { // 맨 아랫줄일경우 작동하지 않습니다.
                    Debug.Log("move fail: 큐브가 맨 아래에 있습니다."); ismove = false;
                }
                else cube.transform.position += DOWN;
                break;
            case 2: // LEFT
                if (MoveTargetpos.x == -1.25f)
                { // 맨 윗줄일경우 작동하지 않습니다.
                    Debug.Log("move fail: 큐브가 맨 왼쪽에 있습니다."); ismove = false;
                }
                else cube.transform.position += LEFT;
                break;
            case 3: // RIGHT
                if (MoveTargetpos.x == 8.75f)
                { // 맨 윗줄일경우 작동하지 않습니다.
                    Debug.Log("move fail: 큐브가 맨 오른쪽에 있습니다."); ismove = false; }
                else cube.transform.position += RIGHT;
                break;
            default: break;
        }

        if (ismove == true)
        {

            // 해당 방향키 방향에 다른 큐브가 있을 경우
            switch (dic)
            {
                case 0: //UP
                        // 오브젝트 검사
                    Vector3 rayup = new Vector3(0, 0.5f, 0);
                    if (true == Physics.Raycast(MoveTargetpos, rayup, out hit))
                    {
                        // 만약 히트 대상이 내가 사용하는 큐브와 인접하지 않앗다면 실패 판정
                        if (hit.transform.position == MoveTargetpos + UP) hit.transform.position = MoveTargetpos;
                        else movescore--;
                    }
                    else movescore--;
                    break;
                case 1: //DOWN
                        // 오브젝트 검사
                    Vector3 raydown = new Vector3(0, -0.1f, 0);
                    if (true == Physics.Raycast(MoveTargetpos, raydown, out hit))
                    {
                        // 만약 히트 대상이 내가 사용하는 큐브와 인접하지 않앗다면 실패 판정
                        if (hit.transform.position == MoveTargetpos + DOWN) hit.transform.position = MoveTargetpos;
                        else movescore--;
                    }
                    else movescore--;
                    break;
                case 2: //LEFT
                        // 오브젝트 검사
                    Vector3 rayleft = new Vector3(-0.5f, 0, 0);
                    if (true == Physics.Raycast(MoveTargetpos, rayleft, out hit))
                    {
                        // 만약 히트 대상이 내가 사용하는 큐브와 인접하지 않앗다면 실패 판정
                        if (hit.transform.position == MoveTargetpos + LEFT) hit.transform.position = MoveTargetpos;
                        else movescore--;
                    }
                    else movescore--;
                    break;
                case 3: //RIGHT
                        // 오브젝트 검사
                    Vector3 rayright = new Vector3(0.5f, 0, 0);
                    if (true == Physics.Raycast(MoveTargetpos, rayright, out hit))
                    {
                        // 만약 히트 대상이 내가 사용하는 큐브와 인접하지 않앗다면 실패 판정
                        if (hit.transform.position == MoveTargetpos +RIGHT) hit.transform.position = MoveTargetpos;
                        else movescore--;
                    }
                    else movescore--;
                    break;

                default: break;
            }

            // 셀렉트 UI 위치 변경
            Effectupdate(cube.transform.position);

            movescore--;
            Debug.Log("점수  : " + movescore);

            GameObject obj = GameObject.Find("CubeDestroy");
            cubeDestroyer destoryer = obj.GetComponent<cubeDestroyer>();
            destoryer.Destroyer();

            countText.text = ""+movescore;
        }
    }



    private void Effectupdate(Vector3 pos)
    {
        UI.transform.position = pos;
    }
}

 

큐브 생성 스크립트

더보기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class cubeSummon : MonoBehaviour
{
    [SerializeField] private GameObject rcube;
    [SerializeField] private GameObject bcube;
    [SerializeField] private GameObject ycube;
    [SerializeField] private GameObject gcube;
    [SerializeField] private GameObject wcube;

    private int rcnt = 1;
    private int bcnt = 1;
    private int ycnt = 1;
    private int gcnt = 1;
    private int wcnt = 1;


    List<GameObject> cube = new List<GameObject>();
    // Start is called before the first frame update
    void Start()
    {
        SummonStart();
    }

    // 큐브를 규칙에 따라 한줄당 9개씩 소환합니다. (가로 9개 전부 소환 후 색 변경)
    // 추가해야할 기능 : 색 랜덤 배정 알고리즘.
    public void SummonStart()
    {
        List<int> color = new List<int>();
        int randcnt = 45;

        // 리스트의 값을 추가합니다.
        for (int f = 1; f<6; f++)  {
            for (int b = 0; b < 9; b++) {
                color.Add(f);
                switch(f)
                {
                    case 1: cube.Add(Instantiate(rcube) as GameObject); break;
                    case 2: cube.Add(Instantiate(bcube) as GameObject); break;
                    case 3: cube.Add(Instantiate(ycube) as GameObject); break;
                    case 4: cube.Add(Instantiate(gcube) as GameObject); break;
                    case 5: cube.Add(Instantiate(wcube) as GameObject); break;
                    default: break;
                }
            }
        }

        // 큐브 생성 알고리즘. i를 9단위로 올리면 세로 1줄을 더 만들 수 있습니다.
        for (int i = 0; i < 45; i++)
        {
            int z;
            float yPos;
            int clr = Random.Range(0, randcnt);

            if (i < 9) {
                cube[clr].SetActive(true);
                yPos = 5f;
                z = 0;
            }
            else if (i < 18)  {
                cube[clr].SetActive(true);
                yPos = 3.75f;
                z = 1;
            }
            else if (i < 27)  {
                cube[clr].SetActive(true);
                yPos = 2.5f;
                z = 2;
            }
            else if (i < 36) {
                cube[clr].SetActive(true);
                yPos = 1.25f;
                z = 3;
            }
            else {
                cube[clr].SetActive(true);
                yPos = 0;
                z = 4;
            }


            // 큐브 이름 Red
            if (cube[clr].name == "Rcube(Clone)")
            {
                string cubename = cube[clr].name + Cubenum(rcnt);
                cube[clr].name = cubename;
                rcnt += 1;
            }

            // 큐브 이름 Blue
            if (cube[clr].name == "Bcube(Clone)")
            {
                string cubename = cube[clr].name + Cubenum(bcnt);
                cube[clr].name = cubename;
                bcnt += 1;
            }

            // 큐브 이름 Grean
            if (cube[clr].name == "Gcube(Clone)")
            {
                string cubename = cube[clr].name + Cubenum(gcnt);
                cube[clr].name = cubename;
                gcnt += 1;
            }

            // 큐브 이름 Yellow
            if (cube[clr].name == "Ycube(Clone)")
            {
                string cubename = cube[clr].name + Cubenum(ycnt);
                cube[clr].name = cubename;
                ycnt += 1;
            }

            // 큐브 이름 White
            if (cube[clr].name == "Wcube(Clone)")
            {
                string cubename = cube[clr].name + Cubenum(wcnt);
                cube[clr].name = cubename;
                wcnt += 1;
            }

            cube[clr].transform.position = new Vector3((i - (z * 9)) * 1.25f - 1.25f, yPos, 0);
            cube.RemoveAt(clr);
            randcnt--;


        }

        // 모든 큐브를 생성했다면 해당 스크립트를 가진 오브젝트를 파괴합니다.
        Destroy(gameObject);
        Debug.Log("[" + name + "]: Cube Summon complete");
    }


    private string Cubenum(int num)
    {
        string str;

        switch(num)
        {
            case 1: str = "1"; break;
            case 2: str = "2"; break;
            case 3: str = "3"; break;
            case 4: str = "4"; break;
            case 5: str = "5"; break;
            case 6: str = "6"; break;
            case 7: str = "7"; break;
            case 8: str = "8"; break;
            case 9: str = "9"; break;
            default: str = "fail"; break;
        }

        return str;
    }
}

 

 

큐브 파괴 스크립트

더보기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class cubeDestroyer : MonoBehaviour
{
    private bool RedDestory = false; // true라면 rcube는 전부 파괴되었습니다.
    private bool BlueDestory = false; // true라면 bcube는 전부 파괴되었습니다.
    private bool YellowDestory = false; // true라면 ycube는 전부 파괴되었습니다.
    private bool GreanDestory = false; // true라면 ycube는 전부 파괴되었습니다.
    private bool WhiteDestory = false; // true라면 ycube는 전부 파괴되었습니다.

    public void Destroyer()
    {

        if (RedDestory == false) RCubeDestroy();
        if (BlueDestory == false) BCubeDestroy();
        if (YellowDestory == false) YCubeDestroy();
        if (GreanDestory == false) GCubeDestroy();
        if (WhiteDestory == false) WCubeDestroy();
    }


    private void RCubeDestroy()
    {
        bool RedChack = false; // Rcube가 모두 같은 y축에 있는지 체크합니다.
        float oldCubepos = 0;

        for (int i = 1; i < 10; i++)
        {
            string cubename = "Rcube(Clone)" + Cubenum(i);
            GameObject obj = GameObject.Find(cubename);

            if (i == 1)
            {
                RedChack = true;
                oldCubepos = obj.transform.position.y;
                Debug.Log("번호 :" + i + "  성공 여부 : " + RedChack);
            }

            else if (RedChack == true)
            {
                if (oldCubepos == obj.transform.position.y)
                {
                    RedChack = true;
                    oldCubepos = obj.transform.position.y;
                    Debug.Log("번호 :" + i + "  성공 여부 : " + RedChack);
                }
                else { RedChack = false; Debug.Log("번호 :" + i + "  성공 여부 : " + RedChack); }
            }
            else Debug.Log("Red Cube DESTROY FAIL");

            if (i == 9 && RedChack == true)
            {
                Debug.Log("Red Cube DESTROYD!");
                for (int z = 1; z < 10; z++)
                {
                    RedDestory = true;
                    string cubename2 = "Rcube(Clone)" + Cubenum(z);
                    GameObject obj2 = GameObject.Find(cubename2);

                    Destroy(obj2);
                }
            }
        }
    }

    private void BCubeDestroy()
    {
        bool BlueChack = false; // Rcube가 모두 같은 y축에 있는지 체크합니다.
        float oldCubepos = 0;

        for (int i = 1; i < 10; i++)
        {
            string cubename = "Bcube(Clone)" + Cubenum(i);
            GameObject obj = GameObject.Find(cubename);

            if (i == 1)
            {
                BlueChack = true;
                oldCubepos = obj.transform.position.y;
                Debug.Log("번호 :" + i + "  성공 여부 : " + BlueChack);
            }

            else if (BlueChack == true)
            {
                if (oldCubepos == obj.transform.position.y)
                {
                    BlueChack = true;
                    oldCubepos = obj.transform.position.y;
                    Debug.Log("번호 :" + i + "  성공 여부 : " + BlueChack);
                }
                else { BlueChack = false; Debug.Log("번호 :" + i + "  성공 여부 : " + BlueChack); }
            }
            else Debug.Log("Blue Cube DESTROY FAIL");

            if (i == 9 && BlueChack == true)
            {
                Debug.Log("Blue Cube DESTROYD!");
                for (int z = 1; z < 10; z++)
                {
                    BlueDestory = true;
                    string cubename2 = "Bcube(Clone)" + Cubenum(z);
                    GameObject obj2 = GameObject.Find(cubename2);

                    Destroy(obj2);
                }
            }
        }
    }

    private void YCubeDestroy()
    {
        bool YellowChack = false; // Rcube가 모두 같은 y축에 있는지 체크합니다.
        float oldCubepos = 0;

        for (int i = 1; i < 10; i++)
        {
            string cubename = "Ycube(Clone)" + Cubenum(i);
            GameObject obj = GameObject.Find(cubename);

            if (i == 1)
            {
                YellowChack = true;
                oldCubepos = obj.transform.position.y;
                Debug.Log("번호 :" + i + "  성공 여부 : " + YellowChack);
            }

            else if (YellowChack == true)
            {
                if (oldCubepos == obj.transform.position.y)
                {
                    YellowChack = true;
                    oldCubepos = obj.transform.position.y;
                    Debug.Log("번호 :" + i + "  성공 여부 : " + YellowChack);
                }
                else { YellowChack = false; Debug.Log("번호 :" + i + "  성공 여부 : " + YellowChack); }
            }
            else Debug.Log("Yellow Cube DESTROY FAIL");

            if (i == 9 && YellowChack == true)
            {
                Debug.Log("Yellow Cube DESTROYD!");
                for (int z = 1; z < 10; z++)
                {
                    YellowDestory = true;
                    string cubename2 = "Ycube(Clone)" + Cubenum(z);
                    GameObject obj2 = GameObject.Find(cubename2);

                    Destroy(obj2);
                }
            }
        }
    }

    private void GCubeDestroy()
    {
        bool GreanChack = false; // Rcube가 모두 같은 y축에 있는지 체크합니다.
        float oldCubepos = 0;

        for (int i = 1; i < 10; i++)
        {
            string cubename = "Gcube(Clone)" + Cubenum(i);
            GameObject obj = GameObject.Find(cubename);

            if (i == 1)
            {
                GreanChack = true;
                oldCubepos = obj.transform.position.y;
                Debug.Log("번호 :" + i + "  성공 여부 : " + GreanChack);
            }

            else if (GreanChack == true)
            {
                if (oldCubepos == obj.transform.position.y)
                {
                    GreanChack = true;
                    oldCubepos = obj.transform.position.y;
                    Debug.Log("번호 :" + i + "  성공 여부 : " + GreanChack);
                }
                else { GreanChack = false; Debug.Log("번호 :" + i + "  성공 여부 : " + GreanChack); }
            }
            else Debug.Log("Grean Cube DESTROY FAIL");

            if (i == 9 && GreanChack == true)
            {
                Debug.Log("Grean Cube DESTROYD!");
                for (int z = 1; z < 10; z++)
                {
                    GreanDestory = true;
                    string cubename2 = "Gcube(Clone)" + Cubenum(z);
                    GameObject obj2 = GameObject.Find(cubename2);

                    Destroy(obj2);
                }
            }
        }
    }

    private void WCubeDestroy()
    {
        bool WhiteChack = false; // Rcube가 모두 같은 y축에 있는지 체크합니다.
        float oldCubepos = 0;

        for (int i = 1; i < 10; i++)
        {
            string cubename = "Wcube(Clone)" + Cubenum(i);
            GameObject obj = GameObject.Find(cubename);

            if (i == 1)
            {
                WhiteChack = true;
                oldCubepos = obj.transform.position.y;
                Debug.Log("번호 :" + i + "  성공 여부 : " + WhiteChack);
            }

            else if (WhiteChack == true)
            {
                if (oldCubepos == obj.transform.position.y)
                {
                    WhiteChack = true;
                    oldCubepos = obj.transform.position.y;
                    Debug.Log("번호 :" + i + "  성공 여부 : " + WhiteChack);
                }
                else { WhiteChack = false; Debug.Log("번호 :" + i + "  성공 여부 : " + WhiteChack); }
            }
            else Debug.Log("White Cube DESTROY FAIL");

            if (i == 9 && WhiteChack == true)
            {
                Debug.Log("White Cube DESTROYD!");
                for (int z = 1; z < 10; z++)
                {
                    WhiteDestory = true;
                    string cubename2 = "Wcube(Clone)" + Cubenum(z);
                    GameObject obj2 = GameObject.Find(cubename2);

                    Destroy(obj2);
                }
            }
        }
    }


    private string Cubenum(int num)
    {
        string str;

        switch (num)
        {
            case 1: str = "1"; break;
            case 2: str = "2"; break;
            case 3: str = "3"; break;
            case 4: str = "4"; break;
            case 5: str = "5"; break;
            case 6: str = "6"; break;
            case 7: str = "7"; break;
            case 8: str = "8"; break;
            case 9: str = "9"; break;
            default: str = "fail"; break;
        }

        return str;
    }
}
728x90