워리어 콤보 모작 개발일지

워리어콤보 개발일지 - Stack, LineRenderer

다모아 2023. 9. 18. 18:25

사용한 함수 : Stack, LineRenderer

 

https://learn.microsoft.com/ko-kr/dotnet/api/system.collections.stack?view=net-7.0 

 

Stack 클래스 (System.Collections)

제네릭이 아닌 개체의 간단한 LIFO(Last In First Out: 마지막에 들어간 것부터 사용) 컬렉션을 나타냅니다.

learn.microsoft.com

https://docs.unity3d.com/ScriptReference/LineRenderer.html

 

Unity - Scripting API: LineRenderer

Success! Thank you for helping us improve the quality of Unity Documentation. Although we cannot accept all submissions, we do read each suggested change from our users and will make updates where applicable. Close

docs.unity3d.com


목표 & 할일

목표.txt
0.00MB


알게된 점

LineRenderer라는 Component를 통해 

이 Line Effect 오브젝트에 

TestLine 스크립트를 넣어서 선을 그리는 Scripts 작동을 하게 한다.

TestLine은 Play, Stop, Init 메서드를 가지고있다.

Play = LineRenderer를 활성화하고 positionCount를 정해줘서 SetPosition으로 target을 생성해줬다.

Stop = LineRenderer를 비활성화해주고 Init메서드를 불러온다

Init = Stop 됐을 때 가지고있는 SetPosition을 초기화 시켜주는 메서드다.

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class TestLine : MonoBehaviour
{
    private LineRenderer lineRenderer;

    private int idx = 0;
    private void Awake()
    {
        this.lineRenderer = GetComponent<LineRenderer>();

        this.lineRenderer.enabled = false;
    }

    public void Play(TestSaveLocation target)
    {
        this.lineRenderer.enabled = true;

        this.lineRenderer.positionCount = idx + 1; // 1

        this.lineRenderer.SetPosition(idx, target.transform.position); // 0번 , target 생성
        idx++; // idx = 1; 
    }

    public void Stop()
    {
        this.lineRenderer.enabled = false;

        this.Init();
    }

    public void Init()
    {
        //Play의 target.position과 idx를 초기화해줘야할듯
        
        for(int i = 0; i < idx; i++)
        {
            this.lineRenderer.SetPosition(i, Vector3.zero);
        }
        idx = 0;
        //this.stackBlock.Clear();
    }
}

 


수정 전

아예 다른 블럭들을 이어도 삭제가 되게 일단 만들었다.

이 때는 Stack으로 마우스 드래그할 때 받지않았고, 그냥 GameObject를 인식해서 해주는 역할로 해주었다.

그래서 Stack으로 바꾸고자하고 코드를 완전 많이 수정하였다.


수정 후

Stack구조로 바꿔주었다.

Stack 구조로 바꾸고 나서 MouseButton이 클릭하고있는 상태일 때 좌표와 내가 무슨 색을 고르고있는지

Debug.Log로 찍게 만들었다.


어려웠고 알게된 점

 

stackBlock.Count != 0

이걸로 스택이 있는지 없는지 구별하게 만들었는데

처음에는 if(stackBlock == null) 로 해봤는데 그거는 에러가 나서 안되고

찾아보니까 Count라는 스택 속성이 있어서 사용하게 되었다.

 

 

if (stackBlock.Peek().type == this.location.type)

이 부분도 조금 애먹었던 곳이다. Push를 먼저 해줘서 그 후에 if문으로 검사하다보니까 음.. 계속 location.type과 Peek().type이 같은데 어떻게 구별을 해줘야할까.. 고민하다가 Push 위치를 바꿔 주어서 해결했다.

Push 부분을

이렇게 만들어줘서 Peek().type 과 location.type이

즉, 마우스 선택한 gameObject의 type과 전의 type이 다르게 만들어줬다.

 


스크립트

 

TestMain - 일단 잡다하게 적었는데 마우스가 클릭하고있을 때 Stack 추가를 한다거나 선을 긋고, 블록 저장,

Count (gameObject가 하나 있으면 true로 되서 한개의 gameObject만 저장해놓는 bool)

이 정도 구성을 하고있다.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.UI;
using static UnityEngine.GraphicsBuffer;

public class TestMain : MonoBehaviour
{

    [SerializeField]
    private GameObject wallPrefab;
    [SerializeField]
    private GameObject blockPrefab;
    [SerializeField]
    private Transform boardTr;
    private TestBlock testBlock;
    private TestSaveLocation location;
    [SerializeField]
    private TestLine testLine;
    [SerializeField]
    private float raycastDistance = 1f;
    private int[,] str =
    {
        {0, 4, 4, 2, 4, 1, 0},
        {0, 4, 5, 1, 1, 2, 0},
        {0, 5, 5, 4, 3, 2, 0},
        {0, 1, 1, 2, 3, 2, 0},
        {0, 1, 3, 3, 5, 5, 0},
        {0, 0, 0, 0, 0, 0, 0},
        {0, 0, 0, 0, 0, 0, 0}
    };

    private List<GameObject> listBlock = new List<GameObject>();
    private Stack<TestSaveLocation> stackBlock = new Stack<TestSaveLocation>();
    private bool IsCount = false;
    private List<bool> listCount = new List<bool>();
    // Start is called before the first frame update
    void Start()
    {
        int maxRow = 7;
        int maxCol = 7;
        this.testBlock = new TestBlock(maxRow, maxCol);

        for (int row = 0; row < maxRow; row++)
        {
            for (int col = 0; col < maxCol; col++)
            {
                switch (str[row, col])
                {
                    case 0:
                        testBlock.Move(row, col);
                        testBlock.InstantiateObj(this.wallPrefab, this.boardTr, TestBlock.eBlockType.WALL);
                        break;
                    case 1:
                        testBlock.Move(row, col);
                        testBlock.InstantiateObj(this.blockPrefab, this.boardTr, TestBlock.eBlockType.RED);
                        break;
                    case 2:
                        testBlock.Move(row, col);
                        testBlock.InstantiateObj(this.blockPrefab, this.boardTr, TestBlock.eBlockType.BLUE);
                        break;
                    case 3:
                        testBlock.Move(row, col);
                        testBlock.InstantiateObj(this.blockPrefab, this.boardTr, TestBlock.eBlockType.GREEN);
                        break;
                    case 4:
                        testBlock.Move(row, col);
                        testBlock.InstantiateObj(this.blockPrefab, this.boardTr, TestBlock.eBlockType.YELLOW);
                        break;
                    case 5:
                        testBlock.Move(row, col);
                        testBlock.InstantiateObj(this.blockPrefab, this.boardTr, TestBlock.eBlockType.PURPLE);
                        break;
                }
            }
        }
    }

    private void Update()
    {
        if (Input.GetMouseButton(0))
        {
            Vector3 pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            RaycastHit2D hit = Physics2D.Raycast(pos, Vector2.zero, raycastDistance);
            //마우스 왼쪽 버튼을 누르고 있을 때
            //1. 인식 [좌표 출력]
            if (hit == false)
            {
                //gameObject bool로 Count하기
                if (IsCount == true)
                {
                    this.IsCount = false;
                }
                return;
            }
            else // hit == true
            {
                //블럭일 때
                if (hit.collider.CompareTag("Block"))
                {
                    //gameObject Count 세기
                    if (IsCount == false)
                    {
                        this.location = hit.collider.gameObject.GetComponent<TestSaveLocation>();
                        //좌표찍기
                        this.location.PutLocation();
                        //블럭 색 별로 인식하기
                        GameObject blockGo = hit.collider.gameObject;
                        //스텍이 0개인지 아닌지 [다른 블록 넘어가지 않기]
                        if (stackBlock.Count != 0)
                        {
                            //스택이 1개 이상일 때
                            if (stackBlock.Peek().type == this.location.type) // type이 같을 때
                            {
                                //블록 저장, 선긋기, 스택저장, Count 저장
                                this.SaveBlock(blockGo);
                                this.testLine.Play(this.location);
                                this.stackBlock.Push(this.location);
                                this.listCount.Add(this.IsCount);
                                Debug.LogFormat("{0} : Peek", this.stackBlock.Peek().type);
                            }
                        }
                        else
                        {
                            //0개라면, 블록 저장, 선긋기, 스택저장, Count 저장
                            Debug.Log("아직 스택이 없습니다.");
                            this.SaveBlock(blockGo);
                            this.testLine.Play(this.location);
                            this.stackBlock.Push(this.location);
                            this.listCount.Add(this.IsCount);
                        }
                        this.IsCount = true;
                    }
                }
            }
        }
        else if (Input.GetMouseButtonUp(0)) // 마우스버튼을 뗐을 때
        {
            Vector3 pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            RaycastHit2D hit = Physics2D.Raycast(pos, Vector2.zero);
            if (hit == false)
            {
                return;
            }
            else
            {
                //listCount가 2개라면 Destroy 안하고 다시 listCount 0으로 초기화시키기
                if (this.listCount.Count >= 3)
                {
                    //3개 이상이라면
                    this.DestroyBlock();
                    this.testLine.Stop();
                    this.listCount.Clear();
                    this.stackBlock.Clear();
                    IsCount = false;
                }
                else if (this.listCount.Count <= 2)
                {
                    //2개 이하라면
                    this.testLine.Stop();
                    this.listCount.Clear();
                    this.listBlock.Clear();
                    this.stackBlock.Clear();
                    Debug.Log(listCount.Count);
                    IsCount = false;
                }
            }
        }
    }

    //블럭 저장하는거
    public void SaveBlock(GameObject blockGo)
    {
        this.listBlock.Add(blockGo);
        Debug.Log(this.listBlock.Count);
    }

    public void DestroyBlock()
    {
        for (int i = 0; i < listBlock.Count; i++)
        {
            //만약 100개를 찍었다. Destroy를 했다 -> 0번 부터 100개까지 Destroy 시킨다.
            Destroy(this.listBlock[i]);
        }

        this.listBlock.Clear();
    }
}

 

TestSaveLocation - row, col, type 값을 저장해놓고 그 정보를 내보내거나 저장해놓는 스크립트

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TestSaveLocation : MonoBehaviour
{
    public int row;
    public int col;
    public TestBlock.eBlockType type;
    public void GetLocation(int row, int col, TestBlock.eBlockType type)
    {
        this.row = row;
        this.col = col;
        this.type = type;
        Debug.LogFormat("<color=yellow>({0},{1}) = {2}</color>", row, col, type); 
    }

    public void PutLocation()
    {
         Debug.LogFormat($"<color={type.ToString()}>({row},{col}) = {type}</color>");
    }
}

 

TestBlock

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TestBlock : MonoBehaviour
{
    private int nRow;
    private int nCol;

    private int m_nRow;
    private int m_nCol;

    private eBlockType[,] str;

    public eBlockType[,] Str
    {
        get { return this.str; }
    }

    public enum eBlockType
    {
        WALL = 0,
        RED = 1,
        BLUE = 2,
        GREEN = 3,
        YELLOW = 4,
        PURPLE = 5,
    }

    private eBlockType m_BlockType;

    public eBlockType blockType
    {
        get { return this.m_BlockType; }
    }

    public TestBlock(int maxRow, int maxCol)
    {
        this.m_nRow = maxRow;
        this.m_nCol = maxCol;

        //배열 방 크기 만들기
        str = new eBlockType[maxRow, maxCol];
    }
    public void InstantiateObj(GameObject objPrefab, Transform boardTr, eBlockType type)
    {
        GameObject obj = Instantiate(objPrefab, boardTr);

        obj.transform.position = boardTr.position + new Vector3(nCol, nRow);

        SpriteRenderer objSp = obj.GetComponent<SpriteRenderer>();

        objSp.sprite = Resources.Load<Sprite>($"Test/{type}");

        this.m_BlockType = type;

        Str[nRow, nCol] = this.m_BlockType;

        TestSaveLocation location = obj.GetComponent<TestSaveLocation>();
        location.GetLocation(nRow, nCol, Str[nRow, nCol]);

        Debug.LogFormat("({0},{1}) = {2}", nRow, nCol, Str[nRow, nCol]);
    }

    public void Move(int row, int col)
    {
        this.nRow = row;
        this.nCol = col;
        
    }
}